Projects
openEuler:Mainline
libgusb
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 10
View file
_service:tar_scm:libgusb.spec
Changed
@@ -1,12 +1,12 @@ Name: libgusb -Version: 0.3.10 +Version: 0.4.6 Release: 1 Summary: GObject-based library for libusb1 License: LGPLv2+ URL: https://github.com/hughsie/libgusb -Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz +Source0: https://github.com/hughsie/libgusb/releases/download/%{version}/%{name}-%{version}.tar.xz -BuildRequires: vala meson libusb1-devel gtk-doc gobject-introspection-devel glib2-devel +BuildRequires: vala meson libusb1-devel gtk-doc gobject-introspection-devel glib2-devel umockdev-devel gi-docgen %description GUsb is a GObject wrapper for libusb1 that makes it easy to do @@ -57,9 +57,12 @@ %files help %defattr(-,root,root) %doc NEWS README.md -%{_datadir}/gtk-doc/html/gusb/* +%{_datadir}/doc/libgusb/* %changelog +* Sat Jul 22 2023 zhouwenpei <zhouwenpei1@h-partners.com> - 0.4.6-1 +- update to 0.4.6 + * Fri Jul 01 2022 jiangxinyu <jiangxinyu@kylinos.cn> - 0.3.10-1 - Upgrade to 0.3.10
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/api
Deleted
-(directory)
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/api/gusb-docs.sgml
Deleted
@@ -1,78 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" - "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" -<!ENTITY version SYSTEM "version.xml"> -> -<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> - <bookinfo> - <title>GUsb Reference Manual</title> - <releaseinfo> - for GUsb &version; - </releaseinfo> - <authorgroup> - <author> - <firstname>Richard</firstname> - <surname>Hughes</surname> - <affiliation> - <address> - <email>richard@hughsie.com</email> - </address> - </affiliation> - </author> - </authorgroup> - <copyright> - <year>2011</year> - <holder>Richard Hughes</holder> - </copyright> - </bookinfo> - - <reference id="specification"> - <title>GUSB Specification</title> - <partintro> - <para> - GUsb is a GLib wrapper for libusb1. - </para> - <para> - This manual documents features of GUsb. - </para> - </partintro> - <xi:include href="gusb-introduction.xml"/> - </reference> - - <reference id="libgusb"> - <title>libgusb GObject library</title> - <partintro> - <para> - This part documents GObjects used in libgusb. - </para> - </partintro> - <xi:include href="xml/gusb-context.xml"/> - <xi:include href="xml/gusb-source.xml"/> - <xi:include href="xml/gusb-device.xml"/> - <xi:include href="xml/gusb-device-list.xml"/> - <xi:include href="xml/gusb-interface.xml"/> - <xi:include href="xml/gusb-endpoint.xml"/> - </reference> - - <reference id="libgusb-helpers"> - <title>libgusb glib helpers</title> - <partintro> - <para> - This part documents helper functions in libgusb. - </para> - </partintro> - <xi:include href="xml/gusb-version.xml"/> - </reference> - - <reference id="faq"> - <title>Frequently asked questions</title> - <partintro> - <para> - This part has answers to developer frequently asked questions. - </para> - </partintro> - <xi:include href="gusb-faq.xml"/> - </reference> - -</book> -
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/api/gusb-faq.xml
Deleted
@@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> -<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> - -<chapter id="faq"> - <title>FAQ</title> - <para> - The following sections explain frequently asked questions from people. - </para> - - <sect1 id="faq-why"> - <title>Why wrap libusb1?</title> - <para> - libusb1 is a pain in the arse to use in GLib. - </para> - - </sect1> - -</chapter> -
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/api/gusb-introduction.xml
Deleted
@@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> -<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> - -<chapter id="introduction"> - <title>GUSB Introduction</title> - - <sect1 id="introduction-description"> - <title>Overall Description</title> - <para> - GUsb is a GLib wrapper for libusb1. - </para> - </sect1> - -</chapter> -
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/api/meson.build
Deleted
@@ -1,15 +0,0 @@ -gusb_version_xml = configure_file( - input : 'version.xml.in', - output : 'version.xml', - configuration : conf, -) - -gnome.gtkdoc( - 'gusb', - src_dir : - gusb_source_dir, - gusb_build_dir, - , - main_sgml : 'gusb-docs.sgml', - install : true -)
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/api/version.xml.in
Deleted
@@ -1,1 +0,0 @@ -@VERSION@
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-autocleanups.h
Deleted
@@ -1,20 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2015 Kalev Lember <klember@redhat.com> - * - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#pragma once - -#include <gusb/gusb-context.h> -#include <gusb/gusb-device.h> -#include <gusb/gusb-device-list.h> - -#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUsbContext, g_object_unref) -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUsbDevice, g_object_unref) -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUsbDeviceList, g_object_unref) - -#endif
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/.clang-format
Added
@@ -0,0 +1,47 @@ +--- +AlignAfterOpenBracket: 'Align' +AlignConsecutiveAssignments: 'false' +AlignConsecutiveDeclarations: 'false' +AlignConsecutiveMacros: 'true' +AlignOperands: 'true' +AlignTrailingComments: 'true' +AllowAllArgumentsOnNextLine: 'false' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortFunctionsOnASingleLine: 'Inline' +AllowShortIfStatementsOnASingleLine: 'false' +AlwaysBreakAfterReturnType: 'All' +BinPackParameters: 'false' +BinPackArguments: 'false' +BreakBeforeBraces: 'Linux' +ColumnLimit: '100' +DerivePointerAlignment: 'false' +IndentCaseLabels: 'false' +IndentWidth: '8' +IncludeBlocks: 'Regroup' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +MaxEmptyLinesToKeep: '1' +PointerAlignment: 'Right' +SortIncludes: 'true' +SpaceAfterCStyleCast: 'false' +SpaceBeforeAssignmentOperators : 'true' +SpaceBeforeParens: 'ControlStatements' +SpaceInEmptyParentheses: 'false' +SpacesInSquareBrackets: 'false' +TabWidth: '8' +UseTab: 'Always' +PenaltyBreakAssignment: '3' +PenaltyBreakBeforeFirstCallParameter: '15' +--- +Language: 'Proto' +--- +Language: 'Cpp' +IncludeCategories: + - Regex: '^"config.h"$' + Priority: '0' + - Regex: '^<' + Priority: '2' + - Regex: '.*' + Priority: '4' +...
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/.github/workflows/main.yml -> _service:tar_scm:libgusb-0.4.6.tar.xz/.github/workflows/main.yml
Changed
@@ -23,18 +23,18 @@ - run: docker run -t -v `pwd`:/build libgusb-${{ matrix.distro }} ./contrib/ci/build_and_test.sh -Dtests=false build-freebsd: - runs-on: macos-10.15 + runs-on: macos-12 steps: - name: Checkout uses: actions/checkout@v2 - name: Build id: test - uses: vmactions/freebsd-vm@v0.1.5 + uses: vmactions/freebsd-vm@v0.2.6 with: usesh: true mem: 8192 prepare: | - pkg install -y git python3 glib meson pkgconf gobject-introspection usbids + pkg install -y git python3 glib json-glib meson pkgconf gobject-introspection usbids sync: rsync run: ./contrib/ci/build_and_test.sh -Dvapi=false -Ddocs=false -Dusb_ids=/usr/local/share/usbids/usb.ids
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/NEWS -> _service:tar_scm:libgusb-0.4.6.tar.xz/NEWS
Changed
@@ -1,385 +1,130 @@ -Version 0.3.10 -~~~~~~~~~~~~~~ -Released: 2021-01-10 - -New Features: - - Add API to change the hotplug poll interval (Richard Hughes) - -Version 0.3.9 -~~~~~~~~~~~~~ -Released: 2021-12-07 - -Bugfixes: - - Don't hard-code the list of OS supporting --version-script (Ting-Wei Lan) - - Fix hotplug after threaded device removal (Richard Hughes) - - Fix version script check for GNU BFD linker on FreeBSD (Ting-Wei Lan) - -Version 0.3.8 -~~~~~~~~~~~~~ -Released: 2021-10-06 - -New Features: - - Add g_usb_device_get_string_descriptor_bytes_full (Ricardo Cañuelo) - -Bugfixes: - - Add the GUsbEndpoint methods to the docs (Richard Hughes) - - Fix hotplug handling and signal emission during enumerate (Benjamin Berg) - -Version 0.3.7 -~~~~~~~~~~~~~ -Released: 2021-05-24 - -New Features: - - Add a FreeBSD CI target (Richard Hughes) - -Bugfixes: - - Do not depend on libusb_get_parent() to fix FreeBSD compile (Richard Hughes) - - Do not depend on libusb_get_port_number() to fix DragonFlyBSD compile (Richard Hughes) - - Do not double-reference USB devices (Marco Trevisan) - - Do not run the tests on FreeBSD (Richard Hughes) - - Require *any* python3 to fix FreeBSD build (Richard Hughes) - -Version 0.3.6 -~~~~~~~~~~~~~ -Released: 2021-03-12 - -New Features: - - Add g_usb_device_get_string_descriptor_bytes() (Richard Hughes) - -Bugfixes: - - Properly set dylib versions on darwin (Caleb Xu) - - Fix cancellation if cancellable is already cancelled (Benjamin Berg) - -Version 0.3.5 -~~~~~~~~~~~~~ -Released: 2020-07-30 - -Notes: - -New Features: - - Add a way to get iConfiguration (Benson Leung) - -Bugfixes: - - Allow building GtkDoc when building as a subproject (Richard Hughes) - - Fix version script to be more portable (Laurent Bigonville, Ting-Wei Lan) - - Include methods on plain structs in the version script (Simon McVittie) - -Version 0.3.4 -~~~~~~~~~~~~~ -Released: 2020-02-20 - -Notes: - - This fixes the symbol version for g_usb_version_string() to be in the right - place, so update this library alongside with external programs if you've - already started using this symbol for example in fwupd. We've put a mechanism - in place so this kind of thing can't happen again. Sorry! - -New Features: - - Validate the exported symbol list during check (Richard Hughes) - -Bugfixes: - - Include the USB bus in the generated platform_id (Richard Hughes) - -Version 0.3.3 -~~~~~~~~~~~~~ -Released: 2020-01-30 - -New Features: - - Add a thin glib wrapper around libusb_endpoint_descriptor (Emmanuel Pacaud) - -Bugfixes: - - Fix high number of wakeups when checking the GUsbContext (Richard Hughes) - - Use '#pragma once' to reduce boilerplate (Richard Hughes) - - Wrap the upstream libusb_strerror() (Richard Hughes) - -Version 0.3.2 -~~~~~~~~~~~~~ -Released: 2020-01-06 - -Bugfixes: - - Do not use deprecated libusb API (Richard Hughes) - - Fix compilation on macOS (Richard Hughes) - - Use a 1ms timeout in the Windows event thread (Richard Hughes) - - Use has_link_argument() to detect linker flags (Richard Hughes) - -Version 0.3.1 -~~~~~~~~~~~~~ -Released: 2019-11-16 +Version 0.4.6 +============= +Released: 2023-06-08 -New Features: - - Add g_usb_device_get_spec() (Richard Hughes) - - Add g_usb_version_string() for fwupd (Richard Hughes) +This release fixes the following bugs: + * Add JSON compatibility helpers for old json-glib versions + * Fix emulation of devices using out-of-order BulkTransfer replies + * Use project_source_root to fix building as a subproject -Bugfixes: - - Add -Wswitch-enum (Benjamin Berg) - - Fix GI length introspection annotations (grindhold) - - Make gir generation optional (maxice8) +Version 0.4.5 +============= +Released: 2023-02-08 -Version 0.3.0 -~~~~~~~~~~~~~ -Released: 2018-02-14 +This release adds the following features: + * Add new API to better detect emulated replug -New Features: - - Add Travis integration (Richard Hughes) - - Allow changing the path to usb.ids file (Ting-Wei Lan) - - Port to the Meson build system (Richard Hughes) +This release fixes the following bugs: + * Do not emit spurious ::device-removed events when emulating + * Record zero-sized device events + * Reset the in-order event index when clearing the event array + * Save the libusb error if libusb_submit_transfer() fails -Bugfixes: - - Replace libusb-1.0/libusb.h with libusb.h (Ting-Wei Lan) +Version 0.4.4 +============= +Released: 2023-01-30 -Version 0.2.11 -~~~~~~~~~~~~~~ -Released: 2017-07-24 +This release adds the following features: + * Add new API to make emulation easier to use -New Features: - - Add g_usb_context_set_flags() (Richard Hughes) +This release fixes the following bugs: + * Emit remove devices with matching tags when loading contexts + * Fix a critical warning when finalizing devices without endpoints + * Reduce the debugging level when emulating firmware -Bugfixes: - - Fix the actual required GLib version (Richard Hughes) +Version 0.4.3 +============= +Released: 2022-12-20 -Version 0.2.10 -~~~~~~~~~~~~~~ -Released: 2017-04-10 +This release fixes the following bugs: + * Export g_usb_device_has_tag() + * Work around a libusb issue which causes devices to appear twice -Bugfixes: - - Correctly detect removed devices when rescanning (Richard Hughes) - - Fix a memory leak when using control transfers (Richard Hughes) - - Fix gtk-doc build when builddir != srcdir (Ting-Wei Lan) - - Fix symbol version table up to version 0.2.9 (Dominique Leuenberger) +Version 0.4.2 +============= +Released: 2022-10-18 -Version 0.2.9 -~~~~~~~~~~~~~ -Released: 2016-03-21 +This release fixes the following bugs: + * Close the GUsbDevice objects in gusbcmd + * Do not call the hotplug callback with the mutex held -New Features: - - Add g_usb_context_wait_for_replug() (Richard Hughes) - - Install gusbcmd as a debugging aid (Richard Hughes) +Version 0.4.1 +============= +Released: 2022-10-01 -Version 0.2.8 -~~~~~~~~~~~~~ -Released: 2015-12-01 +This release adds the following features: + * Allow loading and saving only devices with specific tags + * Include removed devices in the JSON dump -New Features: - - Add a PERMISSION_DENIED error enum (Richard Hughes) - - Add a thin glib wrapper around a libusb_interface_descriptor (Richard Hughes) - - Add g_usb_device_get_interfaces() (Richard Hughes) - - Add g_usb_device_get_release() (Richard Hughes) - - Add g_usb_device_set_interface_alt() (Richard Hughes) +This release fixes the following bug: + * Port from gtkdoc to gi-docgen -Bugfixes: - - Ignore the not-found error when resetting a device (Richard Hughes) +Version 0.4.0 +============= +Released: 2022-09-12 -Version 0.2.7 -~~~~~~~~~~~~~ -Released: 2015-09-15 +The JSON format used to serialising devices is not yet stable, and might +change. -New Features: - - Support g_autoptr() for all gusb object types (Kalev Lember) +This release adds the following features: + * Add support for getting BOS descriptors + * Allow emulating devices by saving and replaying device events + * Cache the list of interfaces and descriptors + * Serialize the GUsbDevice to and from JSON format -Bugfixes: - - Add missing element-type annotations (Robert Ancell) +This release fixes the following bugs: + * Ignore usb.ids classes, subclasses and protocols + * Never dispatch idle events after the context has been destroyed + * Skip some functionality when emulating -Version 0.2.6 -~~~~~~~~~~~~~ -Released: 2015-07-06 - -Bugfixes: - - Do not unref the GMainContext after each request (Richard Hughes) - -Version 0.2.5 -~~~~~~~~~~~~~ -Released: 2015-05-28 - -New Features: - - Add g_usb_device_get_custom_index() (Richard Hughes) - - Allow setting the GMainContext when used for sync methods (Richard Hughes) - - Include all the USB device class codes (Richard Hughes) - - Use symbol versioning (Pass Automated Testing Suite) - -Version 0.2.4 -~~~~~~~~~~~~~ -Released: 2015-01-09 - -Notes: - - Bump glib build requirement to 2.38 (Ignacio Casal Quinteiro) - -New Features: - - Add g_usb_context_find_by_platform_id() (Richard Hughes) - - Add g_usb_device_get_children() (Richard Hughes) - - Add g_usb_device_get_device_subclass and get_device_protocol methods (Ignacio Casal Quinteiro) - - Add g_usb_device_get_parent() (Richard Hughes) - - Add g_usb_device_get_port_number() (Richard Hughes) - - Add g_usb_device_get_vid_as_str() (Richard Hughes) - - Show more helpful output for 'gusb show' (Richard Hughes) - -Bugfixes: - - Don't filter out hub devices when getting the device list (Richard Hughes) - - Make the platform ID persistent across re-plug (Richard Hughes) - - Port to GTask (Ignacio Casal Quinteiro) - - Use new Glib features for various code cleanups (Ignacio Casal Quinteiro) - -Version 0.2.3 -~~~~~~~~~~~~~ -Released: 2014-12-01 - -Bugfixes: - - Correctly terminate the libusb event thread (Richard Hughes) - -Version 0.2.2 -~~~~~~~~~~~~~ -Released: 2014-11-26 - -New Features: - - Official Windows support! - -Bugfixes: - - No longer require G_USB_API_IS_SUBJECT_TO_CHANGE (Richard Hughes) - - Use a thread to process libusb1 events (Richard Hughes) - -Version 0.2.1 -~~~~~~~~~~~~~ -Released: 2014-11-24 - -Bugfixes: - - Always set a device platform ID (Richard Hughes) - - Ignore 'unsupported' as a return value for kernel drivers (Richard Hughes) - -Version 0.2.0 -~~~~~~~~~~~~~ -Released: 2014-11-20 - -Notes: - - This release raises the GLib requirement to 2.32 and libusb to 1.0.19 - - No GUdev functionality is now required - -New Features: - - Add g_usb_device_get_device_class() (Richard Hughes) - - Use the native hotplug support in libusb 1.0.19 (Richard Hughes) - -Bugfixes: - - Fix a crash where libusb_get_pollfds() is unavailable (Richard Hughes) - - Manually coldplug devices and poll if hotplugging is not available (Richard Hughes) - -Version 0.1.6 -~~~~~~~~~~~~~ -Released: 2013-03-05 - -Bugfixes: - - Do not use deprecated GLib functionality (Richard Hughes) - - Remove duplicate gtk-doc check in configure (David King) - - Unref the GMainloop after it has been run, not when just quit (Richard Hughes) - -Version 0.1.5 -~~~~~~~~~~~~~ -Released: 2013-02-05 - -Bugfixes: - - Don't use the deprecated INCLUDES in Makefile.am (Richard Hughes) - - Fix documentation build (Christopher James Halse Rogers) - - Fix obvious typo in README (Hans Ulrich Niedermann) - -Version 0.1.4 -~~~~~~~~~~~~~ -Released: 2012-11-06 - -New Features: - - Add GObject Introspection support (Evan Nemerson) - - Add g_usb_device_reset() to reset a connected device (Richard Hughes) - - Add Vala bindings (Evan Nemerson) - -Bugfixes: - - Assorted introspection annotation fixes (Evan Nemerson) - - Rename inconsistently named gusb_* symbols to g_usb_* (Evan Nemerson) +Version 0.3.10 +============== +Released: 2021-01-10 -Version 0.1.3 -~~~~~~~~~~~~~ -Released: 2011-12-05 +This release adds the following feature: + * Add API to change the hotplug poll interval -Bugfixes: - - Do not build with -Werror by default (Richard Hughes) - - Add a missing error enum value (Richard Hughes) +Version 0.3.9 +============= +Released: 2021-12-07 -Version 0.1.2 -~~~~~~~~~~~~~ -Released: 2011-11-11 +This release fixes the following bugs: + * Don't hard-code the list of OS supporting --version-script + * Fix hotplug after threaded device removal + * Fix version script check for GNU BFD linker on FreeBSD -New Features: - - Call g_usb_device_list_coldplug() automatically (Richard Hughes) +Version 0.3.8 +============= +Released: 2021-10-06 -Bugfixes: - - Ignore EBUSY when trying to detach a kernel driver (Richard Hughes) - - Fix a build failure on Debian (Richard Hughes) +This release adds the following feature: + * Add g_usb_device_get_string_descriptor_bytes_full -Version 0.1.1 -~~~~~~~~~~~~~ -Released: 2011-11-01 +This release fixes the following bugs: + * Add the GUsbEndpoint methods to the docs + * Fix hotplug handling and signal emission during enumerate -Notes: - - This release bumps soname to remove GUdevDevice from the public API. +Version 0.3.7 +============= +Released: 2021-05-24 -New Features: - - Add g_usb_device_get_platform_id (Richard Hughes) +This release adds the following feature: + * Add a FreeBSD CI target -Bugfixes: - - Add usb-1.0 to the gusb.pc 'Requires' (Richard Hughes) - - Do not leak the GUdev API into the public API of GUsb (Richard Hughes) - - Do not try to set the currently running device configuration twice (Richard Hughes) - - Do not use g_simple_async_result_is_valid() as it fails for sync methods (Richard Hughes) +This release fixes the following bugs: + * Do not depend on libusb_get_parent() to fix FreeBSD compile + * Do not depend on libusb_get_port_number() to fix DragonFlyBSD compile + * Do not double-reference USB devices + * Do not run the tests on FreeBSD + * Require *any* python3 to fix FreeBSD build -Version 0.1.0 -~~~~~~~~~~~~~ -Released: 2011-09-15 +Version 0.3.6 +============= +Released: 2021-03-12 -Notes: - - This is the first public release of GUsb! - - The library is not API or ABI stable -- you also have to define - G_USB_API_IS_SUBJECT_TO_CHANGE before including the header to - acknowlegde this. - - Quite a lot of functionality has been added by Richard, Debarshi and - Hans for this release, and we're open to new API ideas, patches and - bugreports. +This release adds the following feature: + * Add g_usb_device_get_string_descriptor_bytes() -New Features: - - Add a debugging tool to exercise the API that is not installed (Richard Hughes) - - Add a simple self test framework (Richard Hughes) - - Build: AM_PROG_CC_C_O required (Javier Jardón) - - Build: Honor aclocal flags (Javier Jardón) - - Build: Use new libtool syntax only (Javier Jardón) - - Build: xz tarballs generation (Javier Jardón) - - Generate gtk-doc files and add some gtk-doc markup (Richard Hughes) - - GUsbContext: Ensure that there is only one GUsbSource for each GUsbContext (Debarshi Ray) - - GUsbContext: fix mapping of GLogLevelFlags to libusb debug level (Hans de Goede) - - GUsbContext: Turn into a proper gobject derived class (Hans de Goede) - - GUsbDevice: Add asynchronous bulk and control transfer (Debarshi Ray) - - GUsbDevice: Add functionality to do sync bulk, control and interrupt transfers (Richard Hughes) - - GUsbDevice: Add functions to get string descriptors (Hans de Goede) - - GUsbDevice: Add get bus / address methods (Hans de Goede) - - GUsbDevice: Add g_usb_device_interrupt_transfer_async() (Richard Hughes) - - GUsbDevice: Add GUsbDeviceList (Hans de Goede) - - GUsbDevice: Add g_usb_device_open() and g_usb_device_close() (Richard Hughes) - - GUsbDevice: Add some helpers for reporting not open functionality (Hans de Goede) - - GUsbDevice: Add some more detailed error codes (Richard Hughes) - - GUsbDevice: Add the ability to get elements of the device descriptor (Richard Hughes) - - GUsbDevice: Call g_usb_device_req_free only after we are done with the instance (Debarshi Ray) - - GUsbDevice: Check several methods for unopened device (Debarshi Ray) - - GUsbDevice: Ensure the new async methods return the correct exit codes on failure (Richard Hughes) - - GUsbDevice: Ensure we have the device descriptor before getting the vendor and product ID's (Richard Hughes) - - GUsbDevice: g_usb_device_bulk_transfer_finish: Use g_simple_async_result_is_valid (Debarshi Ray) - - GUsbDevice: g_usb_device_*_transfer_async: Report if the submission failed (Debarshi Ray) - - GUsbDeviceList: Add g_usb_device_list_find_by_vid_pid() as it's required in colord (Richard Hughes) - - GUsbDeviceList: Add g_usb_device_list_get_devices() to get the complete device list (Richard Hughes) - - GUsbDeviceList: Do not duplicate all devices if the user calls coldplug() twice (Richard Hughes) - - GUsbDeviceList: Make g_usb_device_list_add_dev() return TRUE if the device was added (Richard Hughes) - - GUsbDeviceList: Ref the device returned by g_usb_device_list_get_dev_by_bus_n_address() (Richard Hughes) - - GUsbDevice: Make several methods cancellable (Debarshi Ray) - - GUsbDevice: Move setting config / claiming of interface to their own methods (Hans de Goede) - - GUsbDevice: Set the GUsbContext for install use in GUsbDevice (Richard Hughes) - - GUsbDevice: Turn into a wrapper around libusb_device (Hans de Goede) - - GUsbSource: Add a GError parameter to g_usb_source_new() (Richard Hughes) - - GUsbSource: g_usb_source_new won't return NULL (Debarshi Ray) - - GUsbSource: Make ref / unref the context it uses (Hans de Goede) - - Provide our own gusb_strerror function (Hans de Goede) - - Require users specify G_USB_API_IS_SUBJECT_TO_CHANGE when using libusb (Richard Hughes) - - Simplify the reference counting of the GSimpleAsyncResult instances (Debarshi Ray) - - Use standard GLogLevelFlags when setting the debug flags (Richard Hughes) - - Use the slice allocator for fixed size structs (Debarshi Ray) +This release fixes the following bugs: + * Properly set dylib versions on darwin + * Fix cancellation if cancellable is already cancelled
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/RELEASE.md -> _service:tar_scm:libgusb-0.4.6.tar.xz/RELEASE.md
Changed
@@ -1,37 +1,23 @@ GUsb Release Notes ================== -Write `NEWS` entries for GUsb in the same format as usual. - - git shortlog 0.3.9.. | grep -i -v trivial | grep -v Merge > NEWS.new - ================================================= - Version 0.3.10 - ~~~~~~~~~~~~~~ - Released: 2021-xx-xx - - Notes: - - New Features: - - Bugfixes: - ================================================= +git log --format="%s" --cherry-pick --right-only 0.4.5... | grep -i -v trivial | grep -v Merge | sort | uniq +Add any user visible changes into ../contrib/org.freedesktop.GUsb.metainfo.xml +appstream-util appdata-to-news ../contrib/org.freedesktop.GUsb.metainfo.xml > ../NEWS Update library version if new ABI or API in `meson.build`, commit, and build tarball: # MAKE SURE THIS IS CORRECT - export release_ver="0.3.10" + export release_ver="0.4.6" git commit -a -m "Release version ${release_ver}" git tag -s -f -m "Release ${release_ver}" "${release_ver}" - <gpg password> ninja dist git push --tags git push gpg -b -a meson-dist/libgusb-${release_ver}.tar.xz -Upload tarball: - - scp meson-dist/libgusb-${release_ver}.tar.* hughsient@people.freedesktop.org:public_html/releases/ +Upload tarball and GPG signatures to https://github.com/hughsie/libgusb Do post release version bump in `meson.build` and commit changes: @@ -41,11 +27,11 @@ Send an email to devkit-devel@lists.freedesktop.org ================================================= - GUsb 0.3.10 released! + GUsb 0.4.6 released GUsb is a GObject wrapper for libusb1 that makes it easy to do asynchronous control, bulk and interrupt transfers with proper cancellation and integration into a mainloop. - Tarballs available here: http://people.freedesktop.org/~hughsient/releases/ + Tarballs available here: https://github.com/hughsie/libgusb/releases =================================================
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/contrib/ci/Dockerfile-debian -> _service:tar_scm:libgusb-0.4.6.tar.xz/contrib/ci/Dockerfile-debian
Changed
@@ -1,8 +1,8 @@ -FROM debian:buster +FROM debian:testing -RUN echo "deb-src http://deb.debian.org/debian/ buster main" >> /etc/apt/sources.list +RUN echo "deb-src http://deb.debian.org/debian/ testing main" >> /etc/apt/sources.list RUN apt-get update -qq -RUN apt-get install -yq --no-install-recommends meson +RUN apt-get install -yq --no-install-recommends meson libjson-glib-dev gi-docgen RUN apt-get build-dep --allow-unauthenticated -yq libgusb RUN mkdir /build
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/contrib/ci/Dockerfile-fedora -> _service:tar_scm:libgusb-0.4.6.tar.xz/contrib/ci/Dockerfile-fedora
Changed
@@ -1,16 +1,17 @@ -FROM fedora:34 +FROM fedora:37 RUN dnf -y update RUN dnf -y install \ diffutils \ glib2-devel \ + json-glib-devel \ gobject-introspection-devel \ - gtk-doc \ + gi-docgen \ libusb1-devel \ meson \ redhat-rpm-config \ rpm-devel \ vala-devel \ - vala-tools + vala RUN mkdir /build WORKDIR /build
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/contrib/libgusb.spec.in -> _service:tar_scm:libgusb-0.4.6.tar.xz/contrib/libgusb.spec.in
Changed
@@ -6,12 +6,14 @@ Release: 0.#BUILD#%{?alphatag}%{?dist} License: LGPLv2+ URL: https://github.com/hughsie/libgusb -Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.tar.xz +Source0: https://github.com/hughsie/libgusb/releases/download/%{version}/%{name}-%{version}.tar.xz BuildRequires: glib2-devel >= 2.38.0 +BuildRequires: json-glib-devel BuildRequires: gobject-introspection-devel -BuildRequires: gtk-doc +BuildRequires: gi-docgen BuildRequires: libusb1-devel >= 1.0.19 +BuildRequires: umockdev-devel BuildRequires: meson BuildRequires: vala @@ -51,11 +53,10 @@ %{_bindir}/gusbcmd %{_libdir}/libgusb.so %{_libdir}/pkgconfig/gusb.pc -%{_datadir}/gtk-doc/html/gusb +%{_datadir}/doc/libgusb %{_datadir}/gir-1.0/GUsb-1.0.gir %{_datadir}/vala/vapi/gusb.deps %{_datadir}/vala/vapi/gusb.vapi %changelog -* #LONGDATE# Richard Hughes <richard@hughsie.com> #VERSION#-0.#BUILD##ALPHATAG# -- Update from git +%autochangelog
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/contrib/org.freedesktop.GUsb.metainfo.xml
Added
@@ -0,0 +1,176 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2022 Richard Hughes <richard@hughsie.com> --> +<component type="console-application"> + <id>org.freedesktop.GUsb</id> + <metadata_license>CC0-1.0</metadata_license> + <project_license>LGPL-2.0+</project_license> + <name>GUsb</name> + <summary>A GObject wrapper for libusb1</summary> + <description> + <p> + GUsb is a GObject wrapper for libusb1 that makes it easy to do asynchronous control, + bulk and interrupt transfers with proper cancellation and integration into a mainloop. + This makes it easy to integrate low level USB transfers with your high-level application or + system daemon. + </p> + </description> + <url type="bugtracker">https://github.com/hughsie/libgusb/issues</url> + <url type="homepage">https://github.com/hughsie/libgusb</url> + <content_rating type="oars-1.0"/> + <provides> + <binary>gusbcmd</binary> + </provides> + <releases> + <release version="0.4.6" date="2023-06-08"> + <description> + <p>This release fixes the following bugs:</p> + <ul> + <li>Add JSON compatibility helpers for old json-glib versions</li> + <li>Fix emulation of devices using out-of-order BulkTransfer replies</li> + <li>Use project_source_root to fix building as a subproject</li> + </ul> + </description> + </release> + <release version="0.4.5" date="2023-02-08"> + <description> + <p>This release adds the following features:</p> + <ul> + <li>Add new API to better detect emulated replug</li> + </ul> + <p>This release fixes the following bugs:</p> + <ul> + <li>Do not emit spurious ::device-removed events when emulating</li> + <li>Record zero-sized device events</li> + <li>Reset the in-order event index when clearing the event array</li> + <li>Save the libusb error if libusb_submit_transfer() fails</li> + </ul> + </description> + </release> + <release version="0.4.4" date="2023-01-30"> + <description> + <p>This release adds the following features:</p> + <ul> + <li>Add new API to make emulation easier to use</li> + </ul> + <p>This release fixes the following bugs:</p> + <ul> + <li>Emit remove devices with matching tags when loading contexts</li> + <li>Fix a critical warning when finalizing devices without endpoints</li> + <li>Reduce the debugging level when emulating firmware</li> + </ul> + </description> + </release> + <release version="0.4.3" date="2022-12-20"> + <description> + <p>This release fixes the following bugs:</p> + <ul> + <li>Export g_usb_device_has_tag()</li> + <li>Work around a libusb issue which causes devices to appear twice</li> + </ul> + </description> + </release> + <release version="0.4.2" date="2022-10-18"> + <description> + <p>This release fixes the following bugs:</p> + <ul> + <li>Close the GUsbDevice objects in gusbcmd</li> + <li>Do not call the hotplug callback with the mutex held</li> + </ul> + </description> + </release> + <release version="0.4.1" date="2022-10-01"> + <description> + <p>This release adds the following features:</p> + <ul> + <li>Allow loading and saving only devices with specific tags</li> + <li>Include removed devices in the JSON dump</li> + </ul> + <p>This release fixes the following bug:</p> + <ul> + <li>Port from gtkdoc to gi-docgen</li> + </ul> + </description> + </release> + <release version="0.4.0" date="2022-09-12"> + <description> + <p> + The JSON format used to serialising devices is not yet stable, and + might change. + </p> + <p>This release adds the following features:</p> + <ul> + <li>Add support for getting BOS descriptors</li> + <li>Allow emulating devices by saving and replaying device events</li> + <li>Cache the list of interfaces and descriptors</li> + <li>Serialize the GUsbDevice to and from JSON format</li> + </ul> + <p>This release fixes the following bugs:</p> + <ul> + <li>Ignore usb.ids classes, subclasses and protocols</li> + <li>Never dispatch idle events after the context has been destroyed</li> + <li>Skip some functionality when emulating</li> + </ul> + </description> + </release> + <release version="0.3.10" date="2021-01-10"> + <description> + <p>This release adds the following feature:</p> + <ul> + <li>Add API to change the hotplug poll interval</li> + </ul> + </description> + </release> + <release version="0.3.9" date="2021-12-07"> + <description> + <p>This release fixes the following bugs:</p> + <ul> + <li>Don't hard-code the list of OS supporting --version-script</li> + <li>Fix hotplug after threaded device removal</li> + <li>Fix version script check for GNU BFD linker on FreeBSD</li> + </ul> + </description> + </release> + <release version="0.3.8" date="2021-10-06"> + <description> + <p>This release adds the following feature:</p> + <ul> + <li>Add g_usb_device_get_string_descriptor_bytes_full</li> + </ul> + <p>This release fixes the following bugs:</p> + <ul> + <li>Add the GUsbEndpoint methods to the docs</li> + <li>Fix hotplug handling and signal emission during enumerate</li> + </ul> + </description> + </release> + <release version="0.3.7" date="2021-05-24"> + <description> + <p>This release adds the following feature:</p> + <ul> + <li>Add a FreeBSD CI target</li> + </ul> + <p>This release fixes the following bugs:</p> + <ul> + <li>Do not depend on libusb_get_parent() to fix FreeBSD compile</li> + <li>Do not depend on libusb_get_port_number() to fix DragonFlyBSD compile</li> + <li>Do not double-reference USB devices</li> + <li>Do not run the tests on FreeBSD</li> + <li>Require *any* python3 to fix FreeBSD build</li> + </ul> + </description> + </release> + <release version="0.3.6" date="2021-03-12"> + <description> + <p>This release adds the following feature:</p> + <ul> + <li>Add g_usb_device_get_string_descriptor_bytes()</li> + </ul> + <p>This release fixes the following bugs:</p> + <ul> + <li>Properly set dylib versions on darwin</li> + <li>Fix cancellation if cancellable is already cancelled</li> + </ul> + </description> + </release> + </releases> +</component>
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/docs/libgusb.toml.in
Added
@@ -0,0 +1,38 @@ +library +version = "@version@" +browse_url = "https://github.com/hughsie/libgusb" +repository_url = "https://github.com/hughsie/libgusb.git" +website_url = "https://github.com/hughsie/libgusb" +authors = "GUsb Development Team" +license = "LGPL-2.1-or-later" +description = "GUsb is a GLib wrapper for libusb1" +dependencies = + "GObject-2.0", + "Gio-2.0", + "Json-1.0" + +devhelp = true +search_index = true + + dependencies."GObject-2.0" + name = "GObject" + description = "The base type system library" + docs_url = "https://docs.gtk.org/gobject/" + + dependencies."Gio-2.0" + name = "Gio" + description = "A modern, easy-to-use VFS API" + docs_url = "https://docs.gtk.org/gio/" + + dependencies."Json-1.0" + name = "Json" + description = "API for efficient parsing and writing of JSON (JavaScript Object Notation) streams" + docs_url = "https://gnome.pages.gitlab.gnome.org/json-glib/" + +theme +name = "basic" +show_index_summary = true +show_class_hierarchy = true + +extra +urlmap_file = "urlmap_libgusb.js"
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/docs/meson.build -> _service:tar_scm:libgusb-0.4.6.tar.xz/docs/meson.build
Changed
@@ -1,3 +1,45 @@ -if get_option('docs') -subdir('api') +gidocgen_dep = dependency('gi-docgen', + version: '>= 2021.1', + native: true, + required: false, +) +gidocgen_app = find_program('gi-docgen') + +if gidocgen_dep.found() and gidocgen_app.found() and get_option('introspection') + toml_conf = configuration_data() + toml_conf.set('version', meson.project_version()) + + libgusb_toml = configure_file( + input: 'libgusb.toml.in', + output: 'libgusb.toml', + configuration: toml_conf + ) + + custom_target('doc-libgusb', + input: + libgusb_toml, + libgusb_girtarget0, + , + output: 'libgusb', + command: + gidocgen_app, + 'generate', + '--quiet', + '--add-include-path=@0@'.format(meson.current_build_dir() / '../libgusb'), + '--config=@INPUT0@', + '--output-dir=@OUTPUT@', + '--no-namespace-dir', + '--content-dir=@0@'.format(meson.current_source_dir()), + '@INPUT1@', + , + depends: + libgusb_girtarget0, + , + build_by_default: true, + install: true, + install_dir: join_paths(datadir, 'doc'), + ) + install_data('urlmap_libgusb.js', + install_dir: join_paths(datadir, 'doc', 'libgusb') + ) endif
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/docs/urlmap_libgusb.js
Added
@@ -0,0 +1,4 @@ +baseURLs = + 'Gio', 'https://people.gnome.org/~ebassi/docs/_build/Gio/' , + 'GObject', 'https://people.gnome.org/~ebassi/docs/_build/GObject/' , +
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-bos-descriptor-private.h
Added
@@ -0,0 +1,24 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include <gusb/gusb-bos-descriptor.h> +#include <json-glib/json-glib.h> +#include <libusb.h> + +G_BEGIN_DECLS + +GUsbBosDescriptor * +_g_usb_bos_descriptor_new(const struct libusb_bos_dev_capability_descriptor *bos_cap); + +gboolean +_g_usb_bos_descriptor_load(GUsbBosDescriptor *self, JsonObject *json_object, GError **error); +gboolean +_g_usb_bos_descriptor_save(GUsbBosDescriptor *self, JsonBuilder *json_builder, GError **error); + +G_END_DECLS
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-bos-descriptor.c
Added
@@ -0,0 +1,165 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:gusb-bos-descriptor + * @short_description: GLib wrapper around a USB BOS descriptor. + * + * This object is a thin glib wrapper around a `libusb_bos_dev_capability_descriptor`. + * + * All the data is copied when the object is created and the original descriptor can be destroyed + * at any point. + */ + +#include "config.h" + +#include <string.h> + +#include "gusb-bos-descriptor-private.h" +#include "gusb-json-common.h" + +struct _GUsbBosDescriptor { + GObject parent_instance; + + struct libusb_bos_dev_capability_descriptor bos_cap; + GBytes *extra; +}; + +G_DEFINE_TYPE(GUsbBosDescriptor, g_usb_bos_descriptor, G_TYPE_OBJECT) + +static void +g_usb_bos_descriptor_finalize(GObject *object) +{ + GUsbBosDescriptor *self = G_USB_BOS_DESCRIPTOR(object); + + g_bytes_unref(self->extra); + + G_OBJECT_CLASS(g_usb_bos_descriptor_parent_class)->finalize(object); +} + +static void +g_usb_bos_descriptor_class_init(GUsbBosDescriptorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->finalize = g_usb_bos_descriptor_finalize; +} + +static void +g_usb_bos_descriptor_init(GUsbBosDescriptor *self) +{ +} + +gboolean +_g_usb_bos_descriptor_load(GUsbBosDescriptor *self, JsonObject *json_object, GError **error) +{ + const gchar *str; + + g_return_val_if_fail(G_USB_IS_BOS_DESCRIPTOR(self), FALSE); + g_return_val_if_fail(json_object != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, -1); + + /* optional properties */ + self->bos_cap.bDevCapabilityType = + json_object_get_int_member_with_default(json_object, "DevCapabilityType", 0x0); + + /* extra data */ + str = json_object_get_string_member_with_default(json_object, "ExtraData", NULL); + if (str != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = g_base64_decode(str, &bufsz); + if (self->extra != NULL) + g_bytes_unref(self->extra); + self->extra = g_bytes_new_take(g_steal_pointer(&buf), bufsz); + } + + /* success */ + return TRUE; +} + +gboolean +_g_usb_bos_descriptor_save(GUsbBosDescriptor *self, JsonBuilder *json_builder, GError **error) +{ + g_return_val_if_fail(G_USB_IS_BOS_DESCRIPTOR(self), FALSE); + g_return_val_if_fail(json_builder != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* start */ + json_builder_begin_object(json_builder); + + /* optional properties */ + if (self->bos_cap.bDevCapabilityType != 0) { + json_builder_set_member_name(json_builder, "DevCapabilityType"); + json_builder_add_int_value(json_builder, self->bos_cap.bDevCapabilityType); + } + + /* extra data */ + if (self->extra != NULL && g_bytes_get_size(self->extra) > 0) { + g_autofree gchar *str = g_base64_encode(g_bytes_get_data(self->extra, NULL), + g_bytes_get_size(self->extra)); + json_builder_set_member_name(json_builder, "ExtraData"); + json_builder_add_string_value(json_builder, str); + } + + /* success */ + json_builder_end_object(json_builder); + return TRUE; +} + +/** + * _g_usb_bos_descriptor_new: + * + * Return value: a new #GUsbBosDescriptor object. + * + * Since: 0.4.0 + **/ +GUsbBosDescriptor * +_g_usb_bos_descriptor_new(const struct libusb_bos_dev_capability_descriptor *bos_cap) +{ + GUsbBosDescriptor *self; + self = g_object_new(G_USB_TYPE_BOS_DESCRIPTOR, NULL); + + /* copy the data */ + memcpy(&self->bos_cap, bos_cap, sizeof(*bos_cap)); + self->extra = g_bytes_new(bos_cap->dev_capability_data, bos_cap->bLength - 0x03); + + return G_USB_BOS_DESCRIPTOR(self); +} + +/** + * g_usb_bos_descriptor_get_capability: + * @self: a #GUsbBosDescriptor + * + * Gets the BOS descriptor capability. + * + * Return value: capability + * + * Since: 0.4.0 + **/ +guint8 +g_usb_bos_descriptor_get_capability(GUsbBosDescriptor *self) +{ + g_return_val_if_fail(G_USB_IS_BOS_DESCRIPTOR(self), 0); + return self->bos_cap.bDevCapabilityType; +} + +/** + * g_usb_bos_descriptor_get_extra: + * @self: a #GUsbBosDescriptor + * + * Gets any extra data from the BOS descriptor. + * + * Return value: (transfer none): a #GBytes, or %NULL for failure + * + * Since: 0.4.0 + **/ +GBytes * +g_usb_bos_descriptor_get_extra(GUsbBosDescriptor *self) +{ + g_return_val_if_fail(G_USB_IS_BOS_DESCRIPTOR(self), NULL); + return self->extra; +}
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-bos-descriptor.h
Added
@@ -0,0 +1,22 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define G_USB_TYPE_BOS_DESCRIPTOR (g_usb_bos_descriptor_get_type()) +G_DECLARE_FINAL_TYPE(GUsbBosDescriptor, g_usb_bos_descriptor, G_USB, BOS_DESCRIPTOR, GObject) + +guint8 +g_usb_bos_descriptor_get_capability(GUsbBosDescriptor *self); +GBytes * +g_usb_bos_descriptor_get_extra(GUsbBosDescriptor *self); + +G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-context-private.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-context-private.h
Changed
@@ -7,20 +7,19 @@ #pragma once -#include <libusb.h> - #include <gusb/gusb-context.h> +#include <libusb.h> G_BEGIN_DECLS -libusb_context *_g_usb_context_get_context (GUsbContext *context); +libusb_context * +_g_usb_context_get_context(GUsbContext *self); -const gchar *_g_usb_context_lookup_vendor (GUsbContext *context, - guint16 vid, - GError **error); -const gchar *_g_usb_context_lookup_product (GUsbContext *context, - guint16 vid, - guint16 pid, - GError **error); +const gchar * +_g_usb_context_lookup_vendor(GUsbContext *self, guint16 vid, GError **error); +const gchar * +_g_usb_context_lookup_product(GUsbContext *self, guint16 vid, guint16 pid, GError **error); +gboolean +_g_usb_context_has_flag(GUsbContext *self, GUsbContextFlags flags); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-context.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-context.c
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2011-2016 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * * SPDX-License-Identifier: LGPL-2.1+ @@ -17,47 +17,42 @@ #include <libusb.h> -#include "gusb-context.h" #include "gusb-context-private.h" #include "gusb-device-private.h" #include "gusb-util.h" -enum { - PROP_0, - PROP_LIBUSB_CONTEXT, - PROP_DEBUG_LEVEL, - N_PROPERTIES -}; +enum { PROP_0, PROP_LIBUSB_CONTEXT, PROP_DEBUG_LEVEL, N_PROPERTIES }; -enum { - DEVICE_ADDED_SIGNAL, - DEVICE_REMOVED_SIGNAL, - LAST_SIGNAL -}; +enum { DEVICE_ADDED_SIGNAL, DEVICE_REMOVED_SIGNAL, DEVICE_CHANGED_SIGNAL, LAST_SIGNAL }; #define G_USB_CONTEXT_HOTPLUG_POLL_INTERVAL_DEFAULT 1000 /* ms */ +#define GET_PRIVATE(o) (g_usb_context_get_instance_private(o)) + /** * GUsbContextPrivate: * * Private #GUsbContext data **/ -struct _GUsbContextPrivate -{ - GMainContext *main_ctx; - GPtrArray *devices; - GHashTable *dict_usb_ids; - GHashTable *dict_replug; - GThread *thread_event; - gboolean done_enumerate; - volatile gint thread_event_run; - guint hotplug_poll_id; - guint hotplug_poll_interval; - int debug_level; - GUsbContextFlags flags; - libusb_context *ctx; - libusb_hotplug_callback_handle hotplug_id; -}; +typedef struct { + GMainContext *main_ctx; + GPtrArray *devices; + GPtrArray *devices_removed; + GHashTable *dict_usb_ids; + GHashTable *dict_replug; + GThread *thread_event; + gboolean done_enumerate; + volatile gint thread_event_run; + guint hotplug_poll_id; + guint hotplug_poll_interval; + int debug_level; + GUsbContextFlags flags; + libusb_context *ctx; + libusb_hotplug_callback_handle hotplug_id; + GPtrArray *idle_events; + GMutex idle_events_mutex; + guint idle_events_id; +} GUsbContextPrivate; /* not defined in FreeBSD */ #ifndef HAVE_LIBUSB_CAP_HAS_HOTPLUG @@ -65,25 +60,30 @@ #endif typedef struct { - GMainLoop *loop; - GUsbDevice *device; - guint timeout_id; + GMainLoop *loop; + GUsbDevice *device; + guint timeout_id; } GUsbContextReplugHelper; -static guint signalsLAST_SIGNAL = { 0 }; -static GParamSpec *pspecsN_PROPERTIES = { NULL, }; +static guint signalsLAST_SIGNAL = {0}; +static GParamSpec *pspecsN_PROPERTIES = { + NULL, +}; -static void g_usb_context_initable_iface_init (GInitableIface *iface); +static void +g_usb_context_initable_iface_init(GInitableIface *iface); -G_DEFINE_TYPE_WITH_CODE (GUsbContext, g_usb_context, G_TYPE_OBJECT, - G_ADD_PRIVATE (GUsbContext) - G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, - g_usb_context_initable_iface_init)) +G_DEFINE_TYPE_WITH_CODE(GUsbContext, + g_usb_context, + G_TYPE_OBJECT, + G_ADD_PRIVATE(GUsbContext) + G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, + g_usb_context_initable_iface_init)) /* not defined in FreeBSD */ #ifndef HAVE_LIBUSB_HAS_CAPABILITY static gboolean -libusb_has_capability (int cap) +libusb_has_capability(int cap) { if (cap == LIBUSB_CAP_HAS_HOTPLUG) return TRUE; @@ -92,15 +92,16 @@ #endif static void -g_usb_context_replug_helper_free (GUsbContextReplugHelper *replug_helper) +g_usb_context_replug_helper_free(GUsbContextReplugHelper *replug_helper) { if (replug_helper->timeout_id != 0) - g_source_remove (replug_helper->timeout_id); - g_main_loop_unref (replug_helper->loop); - g_object_unref (replug_helper->device); - g_free (replug_helper); + g_source_remove(replug_helper->timeout_id); + g_main_loop_unref(replug_helper->loop); + g_object_unref(replug_helper->device); + g_free(replug_helper); } +/* clang-format off */ /** * g_usb_context_error_quark: * @@ -109,83 +110,85 @@ * Since: 0.1.0 **/ G_DEFINE_QUARK (g-usb-context-error-quark, g_usb_context_error) +/* clang-format on */ static void -g_usb_context_dispose (GObject *object) +g_usb_context_dispose(GObject *object) { - GUsbContext *context = G_USB_CONTEXT (object); - GUsbContextPrivate *priv = context->priv; + GUsbContext *self = G_USB_CONTEXT(object); + GUsbContextPrivate *priv = GET_PRIVATE(self); /* this is safe to call even when priv->hotplug_id is unset */ - if (g_atomic_int_dec_and_test (&priv->thread_event_run)) { - libusb_hotplug_deregister_callback (priv->ctx, priv->hotplug_id); - g_thread_join (priv->thread_event); + if (g_atomic_int_dec_and_test(&priv->thread_event_run)) { + libusb_hotplug_deregister_callback(priv->ctx, priv->hotplug_id); + g_thread_join(priv->thread_event); } if (priv->hotplug_poll_id > 0) { - g_source_remove (priv->hotplug_poll_id); + g_source_remove(priv->hotplug_poll_id); priv->hotplug_poll_id = 0; } + if (priv->idle_events_id > 0) { + g_source_remove(priv->idle_events_id); + priv->idle_events_id = 0; + } - g_clear_pointer (&priv->main_ctx, g_main_context_unref); - g_clear_pointer (&priv->devices, g_ptr_array_unref); - g_clear_pointer (&priv->dict_usb_ids, g_hash_table_unref); - g_clear_pointer (&priv->dict_replug, g_hash_table_unref); - g_clear_pointer (&priv->ctx, libusb_exit); + g_clear_pointer(&priv->main_ctx, g_main_context_unref); + g_clear_pointer(&priv->devices, g_ptr_array_unref); + g_clear_pointer(&priv->devices_removed, g_ptr_array_unref); + g_clear_pointer(&priv->dict_usb_ids, g_hash_table_unref); + g_clear_pointer(&priv->dict_replug, g_hash_table_unref); + g_clear_pointer(&priv->ctx, libusb_exit); + g_clear_pointer(&priv->idle_events, g_ptr_array_unref); + g_mutex_clear(&priv->idle_events_mutex); - G_OBJECT_CLASS (g_usb_context_parent_class)->dispose (object); + G_OBJECT_CLASS(g_usb_context_parent_class)->dispose(object); } static void -g_usb_context_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +g_usb_context_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - GUsbContext *context = G_USB_CONTEXT (object); - GUsbContextPrivate *priv = context->priv; + GUsbContext *self = G_USB_CONTEXT(object); + GUsbContextPrivate *priv = GET_PRIVATE(self); switch (prop_id) { case PROP_LIBUSB_CONTEXT: - g_value_set_pointer (value, priv->ctx); + g_value_set_pointer(value, priv->ctx); break; case PROP_DEBUG_LEVEL: - g_value_set_int (value, priv->debug_level); + g_value_set_int(value, priv->debug_level); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void -g_usb_context_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +g_usb_context_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GUsbContext *context = G_USB_CONTEXT (object); - GUsbContextPrivate *priv = context->priv; + GUsbContext *self = G_USB_CONTEXT(object); + GUsbContextPrivate *priv = GET_PRIVATE(self); switch (prop_id) { case PROP_DEBUG_LEVEL: - priv->debug_level = g_value_get_int (value); + priv->debug_level = g_value_get_int(value); #ifdef HAVE_LIBUSB_SET_OPTION - libusb_set_option (priv->ctx, LIBUSB_OPTION_LOG_LEVEL, priv->debug_level); + libusb_set_option(priv->ctx, LIBUSB_OPTION_LOG_LEVEL, priv->debug_level); #else - libusb_set_debug (priv->ctx, priv->debug_level); + libusb_set_debug(priv->ctx, priv->debug_level); #endif break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void -g_usb_context_class_init (GUsbContextClass *klass) +g_usb_context_class_init(GUsbContextClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->dispose = g_usb_context_dispose; object_class->get_property = g_usb_context_get_property; @@ -195,282 +198,541 @@ * GUsbContext:libusb_context: */ pspecsPROP_LIBUSB_CONTEXT = - g_param_spec_pointer ("libusb_context", NULL, NULL, - G_PARAM_READABLE); + g_param_spec_pointer("libusb_context", NULL, NULL, G_PARAM_READABLE); /** * GUsbContext:debug_level: */ pspecsPROP_DEBUG_LEVEL = - g_param_spec_int ("debug_level", NULL, NULL, - 0, 3, 0, - G_PARAM_READWRITE); + g_param_spec_int("debug_level", NULL, NULL, 0, 3, 0, G_PARAM_READWRITE); - g_object_class_install_properties (object_class, N_PROPERTIES, pspecs); + g_object_class_install_properties(object_class, N_PROPERTIES, pspecs); /** * GUsbContext::device-added: - * @context: the #GUsbContext instance that emitted the signal + * @self: the #GUsbContext instance that emitted the signal * @device: A #GUsbDevice * * This signal is emitted when a USB device is added. **/ - signalsDEVICE_ADDED_SIGNAL = g_signal_new ("device-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GUsbContextClass, device_added), - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - G_USB_TYPE_DEVICE); + signalsDEVICE_ADDED_SIGNAL = g_signal_new("device-added", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GUsbContextClass, device_added), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_USB_TYPE_DEVICE); /** * GUsbContext::device-removed: - * @context: the #GUsbContext instance that emitted the signal + * @self: the #GUsbContext instance that emitted the signal * @device: A #GUsbDevice * * This signal is emitted when a USB device is removed. **/ - signalsDEVICE_REMOVED_SIGNAL = g_signal_new ("device-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GUsbContextClass, device_removed), - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - G_USB_TYPE_DEVICE); + signalsDEVICE_REMOVED_SIGNAL = + g_signal_new("device-removed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GUsbContextClass, device_removed), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_USB_TYPE_DEVICE); + + /** + * GUsbContext::device-changed: + * @self: the #GUsbContext instance that emitted the signal + * @device: A #GUsbDevice + * + * This signal is emitted when a USB device is changed. + **/ + signalsDEVICE_CHANGED_SIGNAL = + g_signal_new("device-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GUsbContextClass, device_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_USB_TYPE_DEVICE); } static void -g_usb_context_emit_device_add (GUsbContext *context, - GUsbDevice *device) +g_usb_context_emit_device_add(GUsbContext *self, GUsbDevice *device) { + GUsbContextPrivate *priv = GET_PRIVATE(self); + /* emitted directly by g_usb_context_enumerate */ - if (!context->priv->done_enumerate) + if (!priv->done_enumerate) return; - g_signal_emit (context, signalsDEVICE_ADDED_SIGNAL, 0, device); + if (_g_usb_context_has_flag(self, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("emitting ::device-added(%s)", g_usb_device_get_platform_id(device)); + g_signal_emit(self, signalsDEVICE_ADDED_SIGNAL, 0, device); } static void -g_usb_context_emit_device_remove (GUsbContext *context, - GUsbDevice *device) +g_usb_context_emit_device_remove(GUsbContext *self, GUsbDevice *device) { + GUsbContextPrivate *priv = GET_PRIVATE(self); + /* should not happen, if it does we would not fire any signal */ - if (!context->priv->done_enumerate) + if (!priv->done_enumerate) return; - g_signal_emit (context, signalsDEVICE_REMOVED_SIGNAL, 0, device); + if (_g_usb_context_has_flag(self, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("emitting ::device-removed(%s)", g_usb_device_get_platform_id(device)); + g_signal_emit(self, signalsDEVICE_REMOVED_SIGNAL, 0, device); } static void -g_usb_context_add_device (GUsbContext *context, - struct libusb_device *dev) +g_usb_context_emit_device_changed(GUsbContext *self, GUsbDevice *device) { - GUsbDevice *device = NULL; - GUsbContextPrivate *priv = context->priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); + + /* should not happen, if it does we would not fire any signal */ + if (!priv->done_enumerate) + return; + + if (_g_usb_context_has_flag(self, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("emitting ::device-changed(%s)", g_usb_device_get_platform_id(device)); + g_signal_emit(self, signalsDEVICE_CHANGED_SIGNAL, 0, device); +} + +static void +g_usb_context_add_device(GUsbContext *self, struct libusb_device *dev) +{ + GUsbContextPrivate *priv = GET_PRIVATE(self); GUsbContextReplugHelper *replug_helper; const gchar *platform_id; guint8 bus; guint8 address; - GError *error = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GUsbDevice) device = NULL; /* does any existing device exist */ - bus = libusb_get_bus_number (dev); - address = libusb_get_device_address (dev); + bus = libusb_get_bus_number(dev); + address = libusb_get_device_address(dev); if (priv->done_enumerate) - device = g_usb_context_find_by_bus_address (context, bus, address, NULL); + device = g_usb_context_find_by_bus_address(self, bus, address, NULL); if (device != NULL) - goto out; + return; /* add the device */ - device = _g_usb_device_new (context, dev, &error); + device = _g_usb_device_new(self, dev, &error); if (device == NULL) { - g_debug ("There was a problem creating the device: %s", - error->message); - g_error_free (error); - goto out; + g_debug("There was a problem creating the device: %s", error->message); + return; } /* auto-open */ if (priv->flags & G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES) { - if (!_g_usb_device_open_internal (device, &error)) { - g_warning ("cannot open the device: %s", error->message); - g_error_free (error); - goto out; + if (!_g_usb_device_open_internal(device, &error)) { + g_warning("cannot open the device: %s", error->message); + return; } } /* add to enumerated list */ - g_ptr_array_add (priv->devices, g_object_ref (device)); + g_ptr_array_add(priv->devices, g_object_ref(device)); /* if we're waiting for replug, suppress the signal */ - platform_id = g_usb_device_get_platform_id (device); - replug_helper = g_hash_table_lookup (priv->dict_replug, platform_id); + platform_id = g_usb_device_get_platform_id(device); + replug_helper = g_hash_table_lookup(priv->dict_replug, platform_id); if (replug_helper != NULL) { - g_debug ("%s is in replug, ignoring add", platform_id); - g_object_unref (replug_helper->device); - replug_helper->device = g_object_ref (device); - g_main_loop_quit (replug_helper->loop); - goto out; + g_debug("%s is in replug, ignoring add", platform_id); + g_object_unref(replug_helper->device); + replug_helper->device = g_object_ref(device); + g_main_loop_quit(replug_helper->loop); + return; } /* emit signal */ - g_usb_context_emit_device_add (context, device); -out: - if (device != NULL) - g_object_unref (device); + g_usb_context_emit_device_add(self, device); } static void -g_usb_context_remove_device (GUsbContext *context, - struct libusb_device *dev) +g_usb_context_remove_device(GUsbContext *self, struct libusb_device *dev) { - GUsbDevice *device = NULL; - GUsbContextPrivate *priv = context->priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); GUsbContextReplugHelper *replug_helper; const gchar *platform_id; guint8 bus; guint8 address; + g_autoptr(GUsbDevice) device = NULL; /* does any existing device exist */ - bus = libusb_get_bus_number (dev); - address = libusb_get_device_address (dev); - device = g_usb_context_find_by_bus_address (context, bus, address, NULL); + bus = libusb_get_bus_number(dev); + address = libusb_get_device_address(dev); + device = g_usb_context_find_by_bus_address(self, bus, address, NULL); if (device == NULL) { - g_debug ("%i:%i does not exist", bus, address); + g_debug("%i:%i does not exist", bus, address); return; } + /* save this to a lookaside */ + if (priv->flags & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + g_ptr_array_add(priv->devices_removed, g_object_ref(device)); + } + /* remove from enumerated list */ - g_ptr_array_remove (priv->devices, device); + g_ptr_array_remove(priv->devices, device); /* if we're waiting for replug, suppress the signal */ - platform_id = g_usb_device_get_platform_id (device); - replug_helper = g_hash_table_lookup (priv->dict_replug, platform_id); + platform_id = g_usb_device_get_platform_id(device); + replug_helper = g_hash_table_lookup(priv->dict_replug, platform_id); if (replug_helper != NULL) { - g_debug ("%s is in replug, ignoring remove", platform_id); - goto out; + g_debug("%s is in replug, ignoring remove", platform_id); + return; } /* emit signal */ - g_usb_context_emit_device_remove (context, device); -out: - g_object_unref (device); + g_usb_context_emit_device_remove(self, device); +} + +/** + * g_usb_context_load: + * @self: a #GUsbContext + * @json_object: a #JsonObject + * @error: a #GError, or %NULL + * + * Loads the context from a JSON object. + * + * Return value: %TRUE on success + * + * Since: 0.4.0 + **/ +gboolean +g_usb_context_load(GUsbContext *self, JsonObject *json_object, GError **error) +{ + return g_usb_context_load_with_tag(self, json_object, NULL, error); +} + +/** + * g_usb_context_load_with_tag: + * @self: a #GUsbContext + * @json_object: a #JsonObject + * @tag: a string tag, e.g. `runtime-reload`, or %NULL + * @error: a #GError, or %NULL + * + * Loads any devices with a specified tag into the context from a JSON object. + * + * Return value: %TRUE on success + * + * Since: 0.4.1 + **/ +gboolean +g_usb_context_load_with_tag(GUsbContext *self, + JsonObject *json_object, + const gchar *tag, + GError **error) +{ + GUsbContextPrivate *priv = GET_PRIVATE(self); + JsonArray *json_array; + g_autoptr(GPtrArray) devices_added = + g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + g_autoptr(GPtrArray) devices_remove = + g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + + g_return_val_if_fail(G_USB_IS_CONTEXT(self), FALSE); + g_return_val_if_fail(json_object != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* if not already set */ + priv->done_enumerate = TRUE; + + /* sanity check */ + if (!json_object_has_member(json_object, "UsbDevices")) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no UsbDevices array"); + return FALSE; + } + + /* four steps: + * + * 1. store all the existing devices matching the tag in devices_remove + * 2. read the devices in the array: + * - if the platform-id exists: replace the event data & remove from devices_remove + * - otherwise add to devices_added + * 3. emit devices in devices_remove + * 4. emit devices in devices_added + */ + for (guint i = 0; i < priv->devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices, i); + if (tag == NULL || g_usb_device_has_tag(device, tag)) + g_ptr_array_add(devices_remove, g_object_ref(device)); + } + json_array = json_object_get_array_member(json_object, "UsbDevices"); + for (guint i = 0; i < json_array_get_length(json_array); i++) { + JsonNode *node_tmp = json_array_get_element(json_array, i); + JsonObject *obj_tmp = json_node_get_object(node_tmp); + g_autoptr(GUsbDevice) device_old = NULL; + g_autoptr(GUsbDevice) device_tmp = + g_object_new(G_USB_TYPE_DEVICE, "context", self, NULL); + if (!_g_usb_device_load(device_tmp, obj_tmp, error)) + return FALSE; + if (tag != NULL && !g_usb_device_has_tag(device_tmp, tag)) + continue; + + /* does a device with this platform ID and the same created date already exist */ + device_old = + g_usb_context_find_by_platform_id(self, + g_usb_device_get_platform_id(device_tmp), + NULL); + if (device_old != NULL && g_date_time_equal(g_usb_device_get_created(device_old), + g_usb_device_get_created(device_tmp))) { + g_autoptr(GPtrArray) events = g_usb_device_get_events(device_tmp); + g_usb_device_clear_events(device_old); + for (guint j = 0; j < events->len; j++) { + GUsbDeviceEvent *event = g_ptr_array_index(events, j); + _g_usb_device_add_event(device_old, event); + } + g_usb_context_emit_device_changed(self, device_old); + g_ptr_array_remove(devices_remove, device_old); + continue; + } + + /* new to us! */ + g_ptr_array_add(devices_added, g_object_ref(device_tmp)); + } + + /* emit removes then adds */ + for (guint i = 0; i < devices_remove->len; i++) { + GUsbDevice *device = g_ptr_array_index(devices_remove, i); + g_usb_context_emit_device_remove(self, device); + g_ptr_array_remove(priv->devices, device); + } + for (guint i = 0; i < devices_added->len; i++) { + GUsbDevice *device = g_ptr_array_index(devices_added, i); + g_ptr_array_add(priv->devices, g_object_ref(device)); + g_usb_context_emit_device_add(self, device); + } + + /* success */ + return TRUE; +} + +/** + * g_usb_context_save: + * @self: a #GUsbContext + * @json_builder: a #JsonBuilder + * @error: a #GError, or %NULL + * + * Saves the context to an existing JSON builder. + * + * Return value: %TRUE on success + * + * Since: 0.4.0 + **/ +gboolean +g_usb_context_save(GUsbContext *self, JsonBuilder *json_builder, GError **error) +{ + return g_usb_context_save_with_tag(self, json_builder, NULL, error); +} + +/** + * g_usb_context_save_with_tag: + * @self: a #GUsbContext + * @json_builder: a #JsonBuilder + * @tag: a string tag, e.g. `runtime-reload`, or %NULL + * @error: a #GError, or %NULL + * + * Saves any devices with a specified tag into an existing JSON builder. + * + * Return value: %TRUE on success + * + * Since: 0.4.1 + **/ +gboolean +g_usb_context_save_with_tag(GUsbContext *self, + JsonBuilder *json_builder, + const gchar *tag, + GError **error) +{ + GUsbContextPrivate *priv = GET_PRIVATE(self); + + g_return_val_if_fail(G_USB_IS_CONTEXT(self), FALSE); + g_return_val_if_fail(json_builder != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* start */ + g_usb_context_enumerate(self); + json_builder_begin_object(json_builder); + + /* array of devices */ + json_builder_set_member_name(json_builder, "UsbDevices"); + json_builder_begin_array(json_builder); + if (priv->flags & G_USB_CONTEXT_FLAGS_SAVE_REMOVED_DEVICES) { + for (guint i = 0; i < priv->devices_removed->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices_removed, i); + if (!_g_usb_device_save(device, json_builder, error)) + return FALSE; + } + } + for (guint i = 0; i < priv->devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices, i); + if (tag != NULL && !g_usb_device_has_tag(device, tag)) + continue; + if (!_g_usb_device_save(device, json_builder, error)) + return FALSE; + } + json_builder_end_array(json_builder); + + /* success */ + json_builder_end_object(json_builder); + return TRUE; } typedef struct { - GUsbContext *context; - libusb_device *dev; - libusb_hotplug_event event; + GUsbContext *self; + libusb_device *dev; + libusb_hotplug_event event; } GUsbContextIdleHelper; static void -g_usb_context_idle_helper_free (GUsbContextIdleHelper *helper) +g_usb_context_idle_helper_free(GUsbContextIdleHelper *helper) { - g_object_unref (helper->context); - libusb_unref_device (helper->dev); - g_free (helper); + g_object_unref(helper->self); + libusb_unref_device(helper->dev); + g_free(helper); } -static gboolean -g_usb_context_idle_hotplug_cb (gpointer user_data) +static gpointer +g_usb_context_idle_helper_copy(gconstpointer src, gpointer user_data) { - GUsbContextIdleHelper *helper = (GUsbContextIdleHelper *) user_data; + GUsbContextIdleHelper *helper_src = (GUsbContextIdleHelper *)src; + GUsbContextIdleHelper *helper_dst = g_new0(GUsbContextIdleHelper, 1); + helper_dst->self = g_object_ref(helper_src->self); + helper_dst->dev = libusb_ref_device(helper_src->dev); + helper_dst->event = helper_src->event; + return helper_dst; +} - switch (helper->event) { - case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: - g_usb_context_add_device (helper->context, helper->dev); - break; - case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: - g_usb_context_remove_device (helper->context, helper->dev); - break; - default: - break; +/* always in the main thread */ +static gboolean +g_usb_context_idle_hotplug_cb(gpointer user_data) +{ + GUsbContext *self = G_USB_CONTEXT(user_data); + GUsbContextPrivate *priv = GET_PRIVATE(self); + g_autoptr(GPtrArray) idle_events = NULL; + + /* drain the idle events with the lock held */ + g_mutex_lock(&priv->idle_events_mutex); + idle_events = g_ptr_array_copy(priv->idle_events, g_usb_context_idle_helper_copy, NULL); + g_ptr_array_set_size(priv->idle_events, 0); + priv->idle_events_id = 0; + g_mutex_unlock(&priv->idle_events_mutex); + + /* run the callbacks when not locked */ + for (guint i = 0; i < idle_events->len; i++) { + GUsbContextIdleHelper *helper = g_ptr_array_index(idle_events, i); + switch (helper->event) { + case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: + g_usb_context_add_device(helper->self, helper->dev); + break; + case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: + g_usb_context_remove_device(helper->self, helper->dev); + break; + default: + break; + } } - g_usb_context_idle_helper_free (helper); + /* all done */ return FALSE; } +/* this is run in the libusb thread */ static int -g_usb_context_hotplug_cb (struct libusb_context *ctx, - struct libusb_device *dev, - libusb_hotplug_event event, - void *user_data) +g_usb_context_hotplug_cb(struct libusb_context *ctx, + struct libusb_device *dev, + libusb_hotplug_event event, + void *user_data) { - GUsbContext *context = G_USB_CONTEXT (user_data); + GUsbContext *self = G_USB_CONTEXT(user_data); GUsbContextIdleHelper *helper; + GUsbContextPrivate *priv = GET_PRIVATE(self); + g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&priv->idle_events_mutex); + + g_assert(locker != NULL); + + /* libusb is returning devices but LIBUSB_HOTPLUG_ENUMERATE is not set! */ + if (!priv->done_enumerate) + return 0; - helper = g_new0 (GUsbContextIdleHelper, 1); - helper->context = g_object_ref (context); - helper->dev = libusb_ref_device (dev); + helper = g_new0(GUsbContextIdleHelper, 1); + helper->self = g_object_ref(self); + helper->dev = libusb_ref_device(dev); helper->event = event; - g_idle_add (g_usb_context_idle_hotplug_cb, helper); + g_ptr_array_add(priv->idle_events, helper); + if (priv->idle_events_id == 0) + priv->idle_events_id = g_idle_add(g_usb_context_idle_hotplug_cb, self); return 0; } static void -g_usb_context_rescan (GUsbContext *context) +g_usb_context_rescan(GUsbContext *self) { - GList *existing_devices = NULL; - GList *l; - GUsbDevice *device; - GUsbContextPrivate *priv = context->priv; - gboolean found; - guint i; + GUsbContextPrivate *priv = GET_PRIVATE(self); libusb_device **dev_list = NULL; + g_autoptr(GList) existing_devices = NULL; /* copy to a context so we can remove from the array */ - for (i = 0; i < priv->devices->len; i++) { - device = g_ptr_array_index (priv->devices, i); - existing_devices = g_list_prepend (existing_devices, device); + for (guint i = 0; i < priv->devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices, i); + existing_devices = g_list_prepend(existing_devices, device); } /* look for any removed devices */ - libusb_get_device_list (priv->ctx, &dev_list); - for (l = existing_devices; l != NULL; l = l->next) { - device = G_USB_DEVICE (l->data); - found = FALSE; - for (i = 0; dev_list != NULL && dev_listi != NULL; i++) { - if (libusb_get_bus_number (dev_listi) == g_usb_device_get_bus (device) && - libusb_get_device_address (dev_listi) == g_usb_device_get_address (device)) { + libusb_get_device_list(priv->ctx, &dev_list); + for (GList *l = existing_devices; l != NULL; l = l->next) { + GUsbDevice *device = G_USB_DEVICE(l->data); + gboolean found = FALSE; + for (guint i = 0; dev_list != NULL && dev_listi != NULL; i++) { + if (libusb_get_bus_number(dev_listi) == g_usb_device_get_bus(device) && + libusb_get_device_address(dev_listi) == + g_usb_device_get_address(device)) { found = TRUE; break; } } if (!found) { - g_usb_context_emit_device_remove (context, device); - g_ptr_array_remove (priv->devices, device); + g_usb_context_emit_device_remove(self, device); + g_ptr_array_remove(priv->devices, device); } } /* add any devices not yet added (duplicates will be filtered */ - for (i = 0; dev_list != NULL && dev_listi != NULL; i++) - g_usb_context_add_device (context, dev_listi); + for (guint i = 0; dev_list != NULL && dev_listi != NULL; i++) + g_usb_context_add_device(self, dev_listi); - g_list_free (existing_devices); - libusb_free_device_list (dev_list, 1); + libusb_free_device_list(dev_list, 1); } static gboolean -g_usb_context_rescan_cb (gpointer user_data) +g_usb_context_rescan_cb(gpointer user_data) { - GUsbContext *context = G_USB_CONTEXT (user_data); - g_usb_context_rescan (context); + GUsbContext *self = G_USB_CONTEXT(user_data); + g_usb_context_rescan(self); return TRUE; } /** * g_usb_context_get_main_context: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Gets the internal GMainContext to use for synchronous methods. * By default the value is set to the value of g_main_context_default() @@ -480,73 +742,70 @@ * Since: 0.2.5 **/ GMainContext * -g_usb_context_get_main_context (GUsbContext *context) +g_usb_context_get_main_context(GUsbContext *self) { - GUsbContextPrivate *priv = context->priv; - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); + GUsbContextPrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); return priv->main_ctx; } - /** * g_usb_context_set_main_context: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Sets the internal GMainContext to use for synchronous methods. * * Since: 0.2.5 **/ void -g_usb_context_set_main_context (GUsbContext *context, - GMainContext *main_ctx) +g_usb_context_set_main_context(GUsbContext *self, GMainContext *main_ctx) { - GUsbContextPrivate *priv = context->priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); - g_return_if_fail (G_USB_IS_CONTEXT (context)); + g_return_if_fail(G_USB_IS_CONTEXT(self)); - if (main_ctx != priv->main_ctx){ - g_main_context_unref (priv->main_ctx); - priv->main_ctx = g_main_context_ref (main_ctx); + if (main_ctx != priv->main_ctx) { + g_main_context_unref(priv->main_ctx); + priv->main_ctx = g_main_context_ref(main_ctx); } } static void -g_usb_context_ensure_rescan_timeout (GUsbContext *context) +g_usb_context_ensure_rescan_timeout(GUsbContext *self) { - GUsbContextPrivate *priv = context->priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); if (priv->hotplug_poll_id > 0) { - g_source_remove (priv->hotplug_poll_id); + g_source_remove(priv->hotplug_poll_id); priv->hotplug_poll_id = 0; } if (priv->hotplug_poll_interval > 0) { - priv->hotplug_poll_id = g_timeout_add (priv->hotplug_poll_interval, - g_usb_context_rescan_cb, - context); + priv->hotplug_poll_id = + g_timeout_add(priv->hotplug_poll_interval, g_usb_context_rescan_cb, self); } } /** * g_usb_context_get_hotplug_poll_interval: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Gets the poll interval for platforms like Windows that do not support `LIBUSB_CAP_HAS_HOTPLUG`. * - * Return value: (transfer none): the interval in ms + * Return value: interval in ms * * Since: 0.3.10 **/ guint -g_usb_context_get_hotplug_poll_interval (GUsbContext *context) +g_usb_context_get_hotplug_poll_interval(GUsbContext *self) { - GUsbContextPrivate *priv = context->priv; - g_return_val_if_fail (G_USB_IS_CONTEXT (context), G_MAXUINT); + GUsbContextPrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), G_MAXUINT); return priv->hotplug_poll_id; } /** * g_usb_context_set_hotplug_poll_interval: - * @context: a #GUsbContext + * @self: a #GUsbContext * @hotplug_poll_interval: the interval in ms * * Sets the poll interval for platforms like Windows that do not support `LIBUSB_CAP_HAS_HOTPLUG`. @@ -556,12 +815,11 @@ * Since: 0.3.10 **/ void -g_usb_context_set_hotplug_poll_interval (GUsbContext *context, - guint hotplug_poll_interval) +g_usb_context_set_hotplug_poll_interval(GUsbContext *self, guint hotplug_poll_interval) { - GUsbContextPrivate *priv = context->priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); - g_return_if_fail (G_USB_IS_CONTEXT (context)); + g_return_if_fail(G_USB_IS_CONTEXT(self)); /* same */ if (priv->hotplug_poll_interval == hotplug_poll_interval) @@ -571,12 +829,12 @@ /* if already running then change the existing timeout */ if (priv->hotplug_poll_id > 0) - g_usb_context_ensure_rescan_timeout (context); + g_usb_context_ensure_rescan_timeout(self); } /** * g_usb_context_enumerate: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Enumerates all the USB devices and adds them to the context. * @@ -586,32 +844,35 @@ * Since: 0.2.2 **/ void -g_usb_context_enumerate (GUsbContext *context) +g_usb_context_enumerate(GUsbContext *self) { - GUsbContextPrivate *priv = context->priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); /* only ever initially scan once, then rely on hotplug / poll */ if (priv->done_enumerate) return; - g_usb_context_rescan (context); - if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { - g_debug ("platform does not do hotplug, using polling"); - g_usb_context_ensure_rescan_timeout (context); + g_usb_context_rescan(self); + if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { + g_debug("platform does not do hotplug, using polling"); + g_usb_context_ensure_rescan_timeout(self); } priv->done_enumerate = TRUE; /* emit device-added signals before returning */ - for (guint i = 0; i < priv->devices->len; i++) - g_signal_emit (context, signalsDEVICE_ADDED_SIGNAL, 0, - g_ptr_array_index (priv->devices, i)); + for (guint i = 0; i < priv->devices->len; i++) { + g_signal_emit(self, + signalsDEVICE_ADDED_SIGNAL, + 0, + g_ptr_array_index(priv->devices, i)); + } /* any queued up hotplug events are queued as idle handlers */ } /** * g_usb_context_set_flags: - * @context: a #GUsbContext + * @self: a #GUsbContext * @flags: some #GUsbContextFlags, e.g. %G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES * * Sets the flags to use for the context. These should be set before @@ -620,14 +881,15 @@ * Since: 0.2.11 **/ void -g_usb_context_set_flags (GUsbContext *context, GUsbContextFlags flags) +g_usb_context_set_flags(GUsbContext *self, GUsbContextFlags flags) { - context->priv->flags = flags; + GUsbContextPrivate *priv = GET_PRIVATE(self); + priv->flags = flags; } /** * g_usb_context_get_flags: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Sets the flags to use for the context. * @@ -636,85 +898,91 @@ * Since: 0.2.11 **/ GUsbContextFlags -g_usb_context_get_flags (GUsbContext *context) +g_usb_context_get_flags(GUsbContext *self) +{ + GUsbContextPrivate *priv = GET_PRIVATE(self); + return priv->flags; +} + +gboolean +_g_usb_context_has_flag(GUsbContext *self, GUsbContextFlags flag) { - return context->priv->flags; + GUsbContextPrivate *priv = GET_PRIVATE(self); + return (priv->flags & flag) > 0; } static gpointer -g_usb_context_event_thread_cb (gpointer data) +g_usb_context_event_thread_cb(gpointer data) { - GUsbContext *context = G_USB_CONTEXT (data); - GUsbContextPrivate *priv = context->priv; + GUsbContext *self = G_USB_CONTEXT(data); + GUsbContextPrivate *priv = GET_PRIVATE(self); struct timeval tv = { - .tv_usec = 0, - .tv_sec = 2, + .tv_usec = 0, + .tv_sec = 2, }; - while (g_atomic_int_get (&priv->thread_event_run) > 0) - libusb_handle_events_timeout_completed (priv->ctx, &tv, NULL); + while (g_atomic_int_get(&priv->thread_event_run) > 0) + libusb_handle_events_timeout_completed(priv->ctx, &tv, NULL); return NULL; } static void -g_usb_context_init (GUsbContext *context) +g_usb_context_init(GUsbContext *self) { - GUsbContextPrivate *priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); - priv = context->priv = g_usb_context_get_instance_private (context); priv->flags = G_USB_CONTEXT_FLAGS_NONE; priv->hotplug_poll_interval = G_USB_CONTEXT_HOTPLUG_POLL_INTERVAL_DEFAULT; - priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - priv->dict_usb_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - priv->dict_replug = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); + priv->devices = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + priv->devices_removed = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + priv->dict_usb_ids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + priv->dict_replug = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + /* to escape the thread into the mainloop */ + g_mutex_init(&priv->idle_events_mutex); + priv->idle_events = + g_ptr_array_new_with_free_func((GDestroyNotify)g_usb_context_idle_helper_free); } static gboolean -g_usb_context_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) +g_usb_context_initable_init(GInitable *initable, GCancellable *cancellable, GError **error) { - GUsbContext *context = G_USB_CONTEXT (initable); - GUsbContextPrivate *priv; + GUsbContext *self = G_USB_CONTEXT(initable); + GUsbContextPrivate *priv = GET_PRIVATE(self); gint rc; libusb_context *ctx; - priv = context->priv; - - rc = libusb_init (&ctx); + rc = libusb_init(&ctx); if (rc < 0) { - g_set_error (error, - G_USB_CONTEXT_ERROR, - G_USB_CONTEXT_ERROR_INTERNAL, - "failed to init libusb: %s %i", - g_usb_strerror (rc), rc); + g_set_error(error, + G_USB_CONTEXT_ERROR, + G_USB_CONTEXT_ERROR_INTERNAL, + "failed to init libusb: %s %i", + g_usb_strerror(rc), + rc); return FALSE; } - priv->main_ctx = g_main_context_ref (g_main_context_default ()); + priv->main_ctx = g_main_context_ref(g_main_context_default()); priv->ctx = ctx; priv->thread_event_run = 1; - priv->thread_event = g_thread_new ("GUsbEventThread", - g_usb_context_event_thread_cb, - context); + priv->thread_event = g_thread_new("GUsbEventThread", g_usb_context_event_thread_cb, self); /* watch for add/remove */ - if (libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { - rc = libusb_hotplug_register_callback (priv->ctx, - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, - 0, - LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - g_usb_context_hotplug_cb, - context, - &context->priv->hotplug_id); + if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { + rc = libusb_hotplug_register_callback(priv->ctx, + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + 0, + LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, + g_usb_context_hotplug_cb, + self, + &priv->hotplug_id); if (rc != LIBUSB_SUCCESS) { - g_warning ("Error creating a hotplug callback: %s", - g_usb_strerror (rc)); + g_warning("Error creating a hotplug callback: %s", g_usb_strerror(rc)); } } @@ -722,14 +990,14 @@ } static void -g_usb_context_initable_iface_init (GInitableIface *iface) +g_usb_context_initable_iface_init(GInitableIface *iface) { iface->init = g_usb_context_initable_init; } /** * _g_usb_context_get_context: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Gets the internal libusb_context. * @@ -738,14 +1006,15 @@ * Since: 0.1.0 **/ libusb_context * -_g_usb_context_get_context (GUsbContext *context) +_g_usb_context_get_context(GUsbContext *self) { - return context->priv->ctx; + GUsbContextPrivate *priv = GET_PRIVATE(self); + return priv->ctx; } /** * g_usb_context_get_source: - * @context: a #GUsbContext + * @self: a #GUsbContext * @main_ctx: a #GMainContext, or %NULL * * This function does nothing. @@ -755,15 +1024,14 @@ * Since: 0.1.0 **/ GUsbSource * -g_usb_context_get_source (GUsbContext *context, - GMainContext *main_ctx) +g_usb_context_get_source(GUsbContext *self, GMainContext *main_ctx) { return NULL; } /** * g_usb_context_set_debug: - * @context: a #GUsbContext + * @self: a #GUsbContext * @flags: a GLogLevelFlags such as %G_LOG_LEVEL_ERROR | %G_LOG_LEVEL_INFO, or 0 * * Sets the debug flags which control what is logged to the console. @@ -774,15 +1042,12 @@ * Since: 0.1.0 **/ void -g_usb_context_set_debug (GUsbContext *context, - GLogLevelFlags flags) +g_usb_context_set_debug(GUsbContext *self, GLogLevelFlags flags) { - GUsbContextPrivate *priv; + GUsbContextPrivate *priv = GET_PRIVATE(self); int debug_level; - g_return_if_fail (G_USB_IS_CONTEXT (context)); - - priv = context->priv; + g_return_if_fail(G_USB_IS_CONTEXT(self)); if (flags & (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO)) debug_level = 3; @@ -796,18 +1061,18 @@ if (debug_level != priv->debug_level) { priv->debug_level = debug_level; #ifdef HAVE_LIBUSB_SET_OPTION - libusb_set_option (priv->ctx, LIBUSB_OPTION_LOG_LEVEL, debug_level); + libusb_set_option(priv->ctx, LIBUSB_OPTION_LOG_LEVEL, debug_level); #else - libusb_set_debug (priv->ctx, debug_level); + libusb_set_debug(priv->ctx, debug_level); #endif - g_object_notify_by_pspec (G_OBJECT (context), pspecsPROP_DEBUG_LEVEL); + g_object_notify_by_pspec(G_OBJECT(self), pspecsPROP_DEBUG_LEVEL); } } /** * g_usb_context_find_by_bus_address: - * @context: a #GUsbContext + * @self: a #GUsbContext * @bus: a bus number * @address: a bus address * @error: A #GError or %NULL @@ -819,44 +1084,33 @@ * Since: 0.2.2 **/ GUsbDevice * -g_usb_context_find_by_bus_address (GUsbContext *context, - guint8 bus, - guint8 address, - GError **error) +g_usb_context_find_by_bus_address(GUsbContext *self, guint8 bus, guint8 address, GError **error) { - GUsbContextPrivate *priv; - GUsbDevice *device = NULL; - guint i; - - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + GUsbContextPrivate *priv = GET_PRIVATE(self); - priv = context->priv; + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); - g_usb_context_enumerate (context); - for (i = 0; i < priv->devices->len; i++) { - GUsbDevice *curr = g_ptr_array_index (priv->devices, i); - if (g_usb_device_get_bus (curr) == bus && - g_usb_device_get_address (curr) == address) { - device = g_object_ref (curr); - break; + g_usb_context_enumerate(self); + for (guint i = 0; i < priv->devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices, i); + if (g_usb_device_get_bus(device) == bus && + g_usb_device_get_address(device) == address) { + return g_object_ref(device); } } - - if (device == NULL) { - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NO_DEVICE, - "Failed to find device %04x:%04x", - bus, address); - } - - return device; + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE, + "Failed to find device %04x:%04x", + bus, + address); + return NULL; } /** * g_usb_context_find_by_platform_id: - * @context: a #GUsbContext + * @self: a #GUsbContext * @platform_id: a platform id, e.g. "usb:00:03:03:02" * @error: A #GError or %NULL * @@ -867,42 +1121,30 @@ * Since: 0.2.4 **/ GUsbDevice * -g_usb_context_find_by_platform_id (GUsbContext *context, - const gchar *platform_id, - GError **error) +g_usb_context_find_by_platform_id(GUsbContext *self, const gchar *platform_id, GError **error) { - GUsbContextPrivate *priv; - GUsbDevice *device = NULL; - guint i; - - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + GUsbContextPrivate *priv = GET_PRIVATE(self); - priv = context->priv; + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); - g_usb_context_enumerate (context); - for (i = 0; i < priv->devices->len; i++) { - GUsbDevice *curr = g_ptr_array_index (priv->devices, i); - if (g_strcmp0 (g_usb_device_get_platform_id (curr), platform_id) == 0) { - device = g_object_ref (curr); - break; - } + g_usb_context_enumerate(self); + for (guint i = 0; i < priv->devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices, i); + if (g_strcmp0(g_usb_device_get_platform_id(device), platform_id) == 0) + return g_object_ref(device); } - - if (device == NULL) { - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NO_DEVICE, - "Failed to find device %s", - platform_id); - } - - return device; + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE, + "Failed to find device %s", + platform_id); + return NULL; } /** * g_usb_context_find_by_vid_pid: - * @context: a #GUsbContext + * @self: a #GUsbContext * @vid: a vendor ID * @pid: a product ID * @error: A #GError or %NULL @@ -914,98 +1156,89 @@ * Since: 0.2.2 **/ GUsbDevice * -g_usb_context_find_by_vid_pid (GUsbContext *context, - guint16 vid, - guint16 pid, - GError **error) +g_usb_context_find_by_vid_pid(GUsbContext *self, guint16 vid, guint16 pid, GError **error) { - GUsbContextPrivate *priv; - GUsbDevice *device = NULL; - guint i; + GUsbContextPrivate *priv = GET_PRIVATE(self); - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); - priv = context->priv; - - g_usb_context_enumerate (context); - for (i = 0; i < priv->devices->len; i++) { - GUsbDevice *curr = g_ptr_array_index (priv->devices, i); - if (g_usb_device_get_vid (curr) == vid && - g_usb_device_get_pid (curr) == pid) { - device = g_object_ref (curr); - break; + g_usb_context_enumerate(self); + for (guint i = 0; i < priv->devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(priv->devices, i); + if (g_usb_device_get_vid(device) == vid && g_usb_device_get_pid(device) == pid) { + return g_object_ref(device); } } - - if (device == NULL) { - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NO_DEVICE, - "Failed to find device %04x:%04x", - vid, pid); - } - - return device; + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE, + "Failed to find device %04x:%04x", + vid, + pid); + return NULL; } + static gboolean -g_usb_context_load_usb_ids (GUsbContext *context, - GError **error) +g_usb_context_load_usb_ids(GUsbContext *self, GError **error) { + GUsbContextPrivate *priv = GET_PRIVATE(self); guint16 pid; guint16 vid = 0x0000; - guint i; - gchar *data = NULL; - gchar **lines = NULL; + g_autofree gchar *data = NULL; + g_auto(GStrv) lines = NULL; /* already loaded */ - if (g_hash_table_size (context->priv->dict_usb_ids) > 0) + if (g_hash_table_size(priv->dict_usb_ids) > 0) return TRUE; /* parse */ - if (!g_file_get_contents (USB_IDS, &data, NULL, error)) + if (!g_file_get_contents(USB_IDS, &data, NULL, error)) return FALSE; - lines = g_strsplit (data, "\n", -1); - g_free (data); - - for (i = 0; linesi != NULL; i++) { + lines = g_strsplit(data, "\n", -1); + for (guint i = 0; linesi != NULL; i++) { if (linesi0 == '#') continue; if (linesi0 == '\0') continue; + /* the list of known device classes, subclasses and protocols appeared */ + if (g_str_has_prefix(linesi, "C 00")) + break; + if (linesi0 != '\t') { + if (strlen(linesi) < 7) + continue; linesi4 = '\0'; - - vid = g_ascii_strtoull (linesi, NULL, 16); + vid = g_ascii_strtoull(linesi, NULL, 16); if (vid == 0) break; - g_hash_table_insert (context->priv->dict_usb_ids, - g_strdup (linesi), - g_strdup (linesi + 6)); + g_hash_table_insert(priv->dict_usb_ids, + g_strdup(linesi), + g_strdup(linesi + 6)); } else { if (vid == 0x0000) break; + if (strlen(linesi) < 8) + continue; linesi5 = '\0'; - pid = g_ascii_strtoull (linesi + 1, NULL, 16); - g_hash_table_insert (context->priv->dict_usb_ids, - g_strdup_printf ("%04x:%04x", vid, pid), - g_strdup (linesi + 7)); + pid = g_ascii_strtoull(linesi + 1, NULL, 16); + g_hash_table_insert(priv->dict_usb_ids, + g_strdup_printf("%04x:%04x", vid, pid), + g_strdup(linesi + 7)); } } - g_strfreev (lines); - return TRUE; } /** * _g_usb_context_lookup_vendor: - * @context: a #GUsbContext + * @self: a #GUsbContext * @vid: a USB vendor ID * @error: a #GError, or %NULL * @@ -1016,40 +1249,37 @@ * Since: 0.1.5 **/ const gchar * -_g_usb_context_lookup_vendor (GUsbContext *context, - guint16 vid, - GError **error) +_g_usb_context_lookup_vendor(GUsbContext *self, guint16 vid, GError **error) { + GUsbContextPrivate *priv = GET_PRIVATE(self); const gchar *tmp; - gchar *key = NULL; + g_autofree gchar *key = NULL; - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* load */ - if (!g_usb_context_load_usb_ids (context, error)) + if (!g_usb_context_load_usb_ids(self, error)) return NULL; /* find */ - key = g_strdup_printf ("%04x", vid); - tmp = g_hash_table_lookup (context->priv->dict_usb_ids, key); + key = g_strdup_printf("%04x", vid); + tmp = g_hash_table_lookup(priv->dict_usb_ids, key); if (tmp == NULL) { - g_set_error (error, - G_USB_CONTEXT_ERROR, - G_USB_CONTEXT_ERROR_INTERNAL, - "failed to find vid %s", key); - g_free (key); + g_set_error(error, + G_USB_CONTEXT_ERROR, + G_USB_CONTEXT_ERROR_INTERNAL, + "failed to find vid %s", + key); return NULL; } - g_free (key); - return tmp; } /** * _g_usb_context_lookup_product: - * @context: a #GUsbContext + * @self: a #GUsbContext * @vid: a USB vendor ID * @pid: a USB product ID * @error: a #GError, or %NULL @@ -1061,68 +1291,68 @@ * Since: 0.1.5 **/ const gchar * -_g_usb_context_lookup_product (GUsbContext *context, - guint16 vid, - guint16 pid, - GError **error) +_g_usb_context_lookup_product(GUsbContext *self, guint16 vid, guint16 pid, GError **error) { + GUsbContextPrivate *priv = GET_PRIVATE(self); const gchar *tmp; - gchar *key = NULL; + g_autofree gchar *key = NULL; - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* load */ - if (!g_usb_context_load_usb_ids (context, error)) + if (!g_usb_context_load_usb_ids(self, error)) return NULL; /* find */ - key = g_strdup_printf ("%04x:%04x", vid, pid); - tmp = g_hash_table_lookup (context->priv->dict_usb_ids, key); + key = g_strdup_printf("%04x:%04x", vid, pid); + tmp = g_hash_table_lookup(priv->dict_usb_ids, key); if (tmp == NULL) { - g_set_error (error, - G_USB_CONTEXT_ERROR, - G_USB_CONTEXT_ERROR_INTERNAL, - "failed to find vid %s", key); - g_free (key); + g_set_error(error, + G_USB_CONTEXT_ERROR, + G_USB_CONTEXT_ERROR_INTERNAL, + "failed to find vid %s", + key); return NULL; } - g_free (key); - return tmp; } /** * g_usb_context_get_devices: - * @context: a #GUsbContext + * @self: a #GUsbContext * * Return value: (transfer full) (element-type GUsbDevice): a new #GPtrArray of #GUsbDevice's. * * Since: 0.2.2 **/ GPtrArray * -g_usb_context_get_devices (GUsbContext *context) +g_usb_context_get_devices(GUsbContext *self) { - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); + GUsbContextPrivate *priv = GET_PRIVATE(self); - g_usb_context_enumerate (context); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); - return g_ptr_array_ref (context->priv->devices); + g_usb_context_enumerate(self); + + return g_ptr_array_ref(priv->devices); } static gboolean -g_usb_context_replug_timeout_cb (gpointer user_data) +g_usb_context_replug_timeout_cb(gpointer user_data) { - GUsbContextReplugHelper *replug_helper = (GUsbContextReplugHelper *) user_data; + GUsbContextReplugHelper *replug_helper = (GUsbContextReplugHelper *)user_data; replug_helper->timeout_id = 0; - g_main_loop_quit (replug_helper->loop); + g_main_loop_quit(replug_helper->loop); return FALSE; } +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUsbContextReplugHelper, g_usb_context_replug_helper_free) + /** * g_usb_context_wait_for_replug: - * @context: a #GUsbContext + * @self: a #GUsbContext * @device: a #GUsbDevice * @timeout_ms: timeout to wait * @error: A #GError or %NULL @@ -1138,50 +1368,44 @@ * Since: 0.2.9 **/ GUsbDevice * -g_usb_context_wait_for_replug (GUsbContext *context, - GUsbDevice *device, - guint timeout_ms, - GError **error) +g_usb_context_wait_for_replug(GUsbContext *self, + GUsbDevice *device, + guint timeout_ms, + GError **error) { - GUsbDevice *device_new = NULL; - GUsbContextPrivate *priv = context->priv; - GUsbContextReplugHelper *replug_helper; + GUsbContextPrivate *priv = GET_PRIVATE(self); const gchar *platform_id; + g_autoptr(GUsbContextReplugHelper) replug_helper = NULL; - g_return_val_if_fail (G_USB_IS_CONTEXT (context), NULL); + g_return_val_if_fail(G_USB_IS_CONTEXT(self), NULL); /* create a helper */ - replug_helper = g_new0 (GUsbContextReplugHelper, 1); - replug_helper->device = g_object_ref (device); - replug_helper->loop = g_main_loop_new (priv->main_ctx, FALSE); - replug_helper->timeout_id = g_timeout_add (timeout_ms, - g_usb_context_replug_timeout_cb, - replug_helper); + replug_helper = g_new0(GUsbContextReplugHelper, 1); + replug_helper->device = g_object_ref(device); + replug_helper->loop = g_main_loop_new(priv->main_ctx, FALSE); + replug_helper->timeout_id = + g_timeout_add(timeout_ms, g_usb_context_replug_timeout_cb, replug_helper); /* register */ - platform_id = g_usb_device_get_platform_id (device); - g_hash_table_insert (priv->dict_replug, - g_strdup (platform_id), replug_helper); + platform_id = g_usb_device_get_platform_id(device); + g_hash_table_insert(priv->dict_replug, g_strdup(platform_id), replug_helper); /* wait for timeout, or replug */ - g_main_loop_run (replug_helper->loop); + g_main_loop_run(replug_helper->loop); /* unregister */ - g_hash_table_remove (priv->dict_replug, platform_id); + g_hash_table_remove(priv->dict_replug, platform_id); /* so we timed out; emit the removal now */ if (replug_helper->timeout_id == 0) { - g_usb_context_emit_device_remove (context, replug_helper->device); - g_set_error_literal (error, - G_USB_CONTEXT_ERROR, - G_USB_CONTEXT_ERROR_INTERNAL, - "request timed out"); - goto out; + g_usb_context_emit_device_remove(self, replug_helper->device); + g_set_error_literal(error, + G_USB_CONTEXT_ERROR, + G_USB_CONTEXT_ERROR_INTERNAL, + "request timed out"); + return NULL; } - device_new = g_object_ref (replug_helper->device); -out: - g_usb_context_replug_helper_free (replug_helper); - return device_new; + return g_object_ref(replug_helper->device); } /** @@ -1195,7 +1419,7 @@ * Since: 0.1.0 **/ GUsbContext * -g_usb_context_new (GError **error) +g_usb_context_new(GError **error) { - return g_initable_new (G_USB_TYPE_CONTEXT, NULL, error, NULL); + return g_initable_new(G_USB_TYPE_CONTEXT, NULL, error, NULL); }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-context.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-context.h
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2011-2016 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * * SPDX-License-Identifier: LGPL-2.1+ @@ -8,46 +8,30 @@ #pragma once -#include <glib-object.h> - #include <gusb/gusb-device.h> #include <gusb/gusb-source.h> G_BEGIN_DECLS -#define G_USB_TYPE_CONTEXT (g_usb_context_get_type ()) -#define G_USB_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_USB_TYPE_CONTEXT, GUsbContext)) -#define G_USB_IS_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_USB_TYPE_CONTEXT)) -#define G_USB_CONTEXT_ERROR (g_usb_context_error_quark ()) - -typedef struct _GUsbContextPrivate GUsbContextPrivate; -typedef struct _GUsbContext GUsbContext; -typedef struct _GUsbContextClass GUsbContextClass; +#define G_USB_TYPE_CONTEXT (g_usb_context_get_type()) +#define G_USB_CONTEXT_ERROR (g_usb_context_error_quark()) -struct _GUsbContext -{ - GObject parent; - GUsbContextPrivate *priv; -}; +G_DECLARE_DERIVABLE_TYPE(GUsbContext, g_usb_context, G_USB, CONTEXT, GObject) -struct _GUsbContextClass -{ - GObjectClass parent_class; - void (*device_added) (GUsbContext *context, - GUsbDevice *device); - void (*device_removed) (GUsbContext *context, - GUsbDevice *device); +struct _GUsbContextClass { + GObjectClass parent_class; + void (*device_added)(GUsbContext *self, GUsbDevice *device); + void (*device_removed)(GUsbContext *self, GUsbDevice *device); + void (*device_changed)(GUsbContext *self, GUsbDevice *device); /*< private >*/ /* * If adding fields to this struct, remove corresponding * amount of padding to avoid changing overall struct size */ - gchar _gusb_reserved62; + gchar _gusb_reserved61; }; -typedef enum { - G_USB_CONTEXT_ERROR_INTERNAL -} GUsbContextError; +typedef enum { G_USB_CONTEXT_ERROR_INTERNAL } GUsbContextError; /** * GUsbContextFlags: @@ -55,53 +39,73 @@ * The flags to use for the context. **/ typedef enum { - G_USB_CONTEXT_FLAGS_NONE = 0, - G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES = 1 << 0, + G_USB_CONTEXT_FLAGS_NONE = 0, + G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES = 1 << 0, + G_USB_CONTEXT_FLAGS_SAVE_EVENTS = 1 << 1, + G_USB_CONTEXT_FLAGS_SAVE_REMOVED_DEVICES = 1 << 2, + G_USB_CONTEXT_FLAGS_DEBUG = 1 << 3, /*< private >*/ G_USB_CONTEXT_FLAGS_LAST } GUsbContextFlags; -GType g_usb_context_get_type (void); -GQuark g_usb_context_error_quark (void); +GQuark +g_usb_context_error_quark(void); -GUsbContext *g_usb_context_new (GError **error); +GUsbContext * +g_usb_context_new(GError **error); -void g_usb_context_set_flags (GUsbContext *context, - GUsbContextFlags flags); -GUsbContextFlags g_usb_context_get_flags (GUsbContext *context); +void +g_usb_context_set_flags(GUsbContext *self, GUsbContextFlags flags); +GUsbContextFlags +g_usb_context_get_flags(GUsbContext *self); G_DEPRECATED -GUsbSource *g_usb_context_get_source (GUsbContext *context, - GMainContext *main_ctx); -GMainContext *g_usb_context_get_main_context (GUsbContext *context); -void g_usb_context_set_main_context (GUsbContext *context, - GMainContext *main_ctx); -guint g_usb_context_get_hotplug_poll_interval(GUsbContext *context); -void g_usb_context_set_hotplug_poll_interval(GUsbContext *context, - guint hotplug_poll_interval); - -void g_usb_context_enumerate (GUsbContext *context); - -void g_usb_context_set_debug (GUsbContext *context, - GLogLevelFlags flags); -GPtrArray *g_usb_context_get_devices (GUsbContext *context); - -GUsbDevice *g_usb_context_find_by_bus_address (GUsbContext *context, - guint8 bus, - guint8 address, - GError **error); - -GUsbDevice *g_usb_context_find_by_vid_pid (GUsbContext *context, - guint16 vid, - guint16 pid, - GError **error); -GUsbDevice *g_usb_context_find_by_platform_id (GUsbContext *context, - const gchar *platform_id, - GError **error); - -GUsbDevice *g_usb_context_wait_for_replug (GUsbContext *context, - GUsbDevice *device, - guint timeout_ms, - GError **error); +GUsbSource * +g_usb_context_get_source(GUsbContext *self, GMainContext *main_ctx); +GMainContext * +g_usb_context_get_main_context(GUsbContext *self); +void +g_usb_context_set_main_context(GUsbContext *self, GMainContext *main_ctx); +guint +g_usb_context_get_hotplug_poll_interval(GUsbContext *self); +void +g_usb_context_set_hotplug_poll_interval(GUsbContext *self, guint hotplug_poll_interval); + +void +g_usb_context_enumerate(GUsbContext *self); + +gboolean +g_usb_context_load(GUsbContext *self, JsonObject *json_object, GError **error); +gboolean +g_usb_context_load_with_tag(GUsbContext *self, + JsonObject *json_object, + const gchar *tag, + GError **error); +gboolean +g_usb_context_save(GUsbContext *self, JsonBuilder *json_builder, GError **error); +gboolean +g_usb_context_save_with_tag(GUsbContext *self, + JsonBuilder *json_builder, + const gchar *tag, + GError **error); + +void +g_usb_context_set_debug(GUsbContext *self, GLogLevelFlags flags); +GPtrArray * +g_usb_context_get_devices(GUsbContext *self); + +GUsbDevice * +g_usb_context_find_by_bus_address(GUsbContext *self, guint8 bus, guint8 address, GError **error); + +GUsbDevice * +g_usb_context_find_by_vid_pid(GUsbContext *self, guint16 vid, guint16 pid, GError **error); +GUsbDevice * +g_usb_context_find_by_platform_id(GUsbContext *self, const gchar *platform_id, GError **error); + +GUsbDevice * +g_usb_context_wait_for_replug(GUsbContext *self, + GUsbDevice *device, + guint timeout_ms, + GError **error); G_END_DECLS
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device-event-private.h
Added
@@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include <gusb/gusb-device-event.h> +#include <json-glib/json-glib.h> +#include <libusb.h> + +G_BEGIN_DECLS + +GUsbDeviceEvent * +_g_usb_device_event_new(const gchar *id); +void +_g_usb_device_event_set_bytes_raw(GUsbDeviceEvent *self, gconstpointer buf, gsize bufsz); +void +_g_usb_device_event_set_status(GUsbDeviceEvent *self, gint status); +void +_g_usb_device_event_set_rc(GUsbDeviceEvent *self, gint rc); + +gboolean +_g_usb_device_event_load(GUsbDeviceEvent *self, JsonObject *json_object, GError **error); +gboolean +_g_usb_device_event_save(GUsbDeviceEvent *self, JsonBuilder *json_builder, GError **error); + +G_END_DECLS
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device-event.c
Added
@@ -0,0 +1,259 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/** + * SECTION:gusb-device-event + * @short_description: An event that happened to a GUsbDevice. + */ + +#include "config.h" + +#include "gusb-device-event-private.h" +#include "gusb-json-common.h" + +struct _GUsbDeviceEvent { + GObject parent_instance; + gchar *id; + gint status; + gint rc; + GBytes *bytes; +}; + +G_DEFINE_TYPE(GUsbDeviceEvent, g_usb_device_event, G_TYPE_OBJECT) + +static void +g_usb_device_event_finalize(GObject *object) +{ + GUsbDeviceEvent *self = G_USB_DEVICE_EVENT(object); + + g_free(self->id); + if (self->bytes != NULL) + g_bytes_unref(self->bytes); + + G_OBJECT_CLASS(g_usb_device_event_parent_class)->finalize(object); +} + +static void +g_usb_device_event_class_init(GUsbDeviceEventClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + object_class->finalize = g_usb_device_event_finalize; +} + +static void +g_usb_device_event_init(GUsbDeviceEvent *self) +{ +} + +gboolean +_g_usb_device_event_load(GUsbDeviceEvent *self, JsonObject *json_object, GError **error) +{ + const gchar *str; + + g_return_val_if_fail(G_USB_IS_DEVICE_EVENT(self), FALSE); + g_return_val_if_fail(json_object != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, -1); + + /* optional properties */ + self->id = g_strdup(json_object_get_string_member_with_default(json_object, "Id", NULL)); + self->status = json_object_get_int_member_with_default(json_object, + "Status", + LIBUSB_TRANSFER_COMPLETED); + self->rc = json_object_get_int_member_with_default(json_object, "Error", LIBUSB_SUCCESS); + + /* extra data */ + str = json_object_get_string_member_with_default(json_object, "Data", NULL); + if (str != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = g_base64_decode(str, &bufsz); + self->bytes = g_bytes_new_take(g_steal_pointer(&buf), bufsz); + } + + /* success */ + return TRUE; +} + +gboolean +_g_usb_device_event_save(GUsbDeviceEvent *self, JsonBuilder *json_builder, GError **error) +{ + g_return_val_if_fail(G_USB_IS_DEVICE_EVENT(self), FALSE); + g_return_val_if_fail(json_builder != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* start */ + json_builder_begin_object(json_builder); + + if (self->id != NULL) { + json_builder_set_member_name(json_builder, "Id"); + json_builder_add_string_value(json_builder, self->id); + } + if (self->status != LIBUSB_TRANSFER_COMPLETED) { + json_builder_set_member_name(json_builder, "Status"); + json_builder_add_int_value(json_builder, self->status); + } + if (self->rc != LIBUSB_SUCCESS) { + json_builder_set_member_name(json_builder, "Error"); + json_builder_add_int_value(json_builder, self->rc); + } + if (self->bytes != NULL) { + g_autofree gchar *str = g_base64_encode(g_bytes_get_data(self->bytes, NULL), + g_bytes_get_size(self->bytes)); + json_builder_set_member_name(json_builder, "Data"); + json_builder_add_string_value(json_builder, str); + } + + /* success */ + json_builder_end_object(json_builder); + return TRUE; +} + +/** + * _g_usb_device_event_new: + * @id: a cache key + * + * Return value: a new #GUsbDeviceEvent object. + * + * Since: 0.4.0 + **/ +GUsbDeviceEvent * +_g_usb_device_event_new(const gchar *id) +{ + GUsbDeviceEvent *self; + self = g_object_new(G_USB_TYPE_DEVICE_EVENT, NULL); + self->id = g_strdup(id); + return G_USB_DEVICE_EVENT(self); +} + +/** + * g_usb_device_event_get_id: + * @self: a #GUsbDeviceEvent + * + * Gets the event ID. + * + * Return value: string, or %NULL + * + * Since: 0.4.0 + **/ +const gchar * +g_usb_device_event_get_id(GUsbDeviceEvent *self) +{ + g_return_val_if_fail(G_USB_IS_DEVICE_EVENT(self), NULL); + return self->id; +} + +/** + * g_usb_device_event_get_status: + * @self: a #GUsbDeviceEvent + * + * Gets any status data from the event. + * + * Return value: a `enum libusb_transfer_status`, or -1 for failure + * + * Since: 0.4.0 + **/ +gint +g_usb_device_event_get_status(GUsbDeviceEvent *self) +{ + g_return_val_if_fail(G_USB_IS_DEVICE_EVENT(self), -1); + return self->status; +} + +/** + * _g_usb_device_event_set_status: + * @self: a #GUsbDeviceEvent + * @status: `enum libusb_transfer_status` + * + * Set the status of the event, e.g. `LIBUSB_TRANSFER_COMPLETED`. + * + * Since: 0.4.0 + **/ +void +_g_usb_device_event_set_status(GUsbDeviceEvent *self, gint status) +{ + g_return_if_fail(G_USB_IS_DEVICE_EVENT(self)); + self->status = status; +} + +/** + * g_usb_device_event_get_rc: + * @self: a #GUsbDeviceEvent + * + * Gets any return code from the event. + * + * Return value: a `enum libusb_error` + * + * Since: 0.4.5 + **/ +gint +g_usb_device_event_get_rc(GUsbDeviceEvent *self) +{ + g_return_val_if_fail(G_USB_IS_DEVICE_EVENT(self), LIBUSB_ERROR_OTHER); + return self->rc; +} + +/** + * _g_usb_device_event_set_rc: + * @self: a #GUsbDeviceEvent + * @status: `enum libusb_error` + * + * Set the return code of the event, e.g. `LIBUSB_ERROR_TIMEOUT`. + * + * Since: 0.4.5 + **/ +void +_g_usb_device_event_set_rc(GUsbDeviceEvent *self, gint rc) +{ + g_return_if_fail(G_USB_IS_DEVICE_EVENT(self)); + g_return_if_fail(rc <= 0); + self->rc = rc; +} + +/** + * g_usb_device_event_get_bytes: + * @self: a #GUsbDeviceEvent + * + * Gets any bytes data from the event. + * + * Return value: (transfer none): a #GBytes, or %NULL + * + * Since: 0.4.0 + **/ +GBytes * +g_usb_device_event_get_bytes(GUsbDeviceEvent *self) +{ + g_return_val_if_fail(G_USB_IS_DEVICE_EVENT(self), NULL); + return self->bytes; +} + +/** + * g_usb_device_event_set_bytes: + * @self: a #GUsbDeviceEvent + * @bytes: a #GBytes + * + * Set the bytes data to the event. + * + * Since: 0.4.0 + **/ +void +g_usb_device_event_set_bytes(GUsbDeviceEvent *self, GBytes *bytes) +{ + g_return_if_fail(G_USB_IS_DEVICE_EVENT(self)); + g_return_if_fail(bytes != NULL); + if (self->bytes != NULL) + g_bytes_unref(self->bytes); + self->bytes = g_bytes_ref(bytes); +} + +void +_g_usb_device_event_set_bytes_raw(GUsbDeviceEvent *self, gconstpointer buf, gsize bufsz) +{ + g_return_if_fail(G_USB_IS_DEVICE_EVENT(self)); + g_return_if_fail(buf != NULL); + if (self->bytes != NULL) + g_bytes_unref(self->bytes); + self->bytes = g_bytes_new(buf, bufsz); +}
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device-event.h
Added
@@ -0,0 +1,28 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define G_USB_TYPE_DEVICE_EVENT (g_usb_device_event_get_type()) +G_DECLARE_FINAL_TYPE(GUsbDeviceEvent, g_usb_device_event, G_USB, DEVICE_EVENT, GObject) + +const gchar * +g_usb_device_event_get_id(GUsbDeviceEvent *self); +GBytes * +g_usb_device_event_get_bytes(GUsbDeviceEvent *self); +gint +g_usb_device_event_get_status(GUsbDeviceEvent *self); +gint +g_usb_device_event_get_rc(GUsbDeviceEvent *self); +void +g_usb_device_event_set_bytes(GUsbDeviceEvent *self, GBytes *bytes); + +G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-device-list.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device-list.c
Changed
@@ -1,7 +1,7 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> - * Copyright (C) 2011-2014 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -15,188 +15,179 @@ #include "config.h" -#include <string.h> -#include <stdlib.h> #include <libusb.h> +#include <stdlib.h> +#include <string.h> -#include "gusb-context.h" #include "gusb-context-private.h" -#include "gusb-device.h" #include "gusb-device-list.h" #include "gusb-device-private.h" -enum { - PROP_0, - PROP_CONTEXT -}; +enum { PROP_0, PROP_CONTEXT }; -enum -{ - DEVICE_ADDED_SIGNAL, - DEVICE_REMOVED_SIGNAL, - LAST_SIGNAL -}; +enum { DEVICE_ADDED_SIGNAL, DEVICE_REMOVED_SIGNAL, LAST_SIGNAL }; -struct _GUsbDeviceListPrivate { +typedef struct { GUsbContext *context; -}; +} GUsbDeviceListPrivate; -static guint signalsLAST_SIGNAL = { 0 }; +static guint signalsLAST_SIGNAL = {0}; -G_DEFINE_TYPE_WITH_PRIVATE (GUsbDeviceList, g_usb_device_list, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE(GUsbDeviceList, g_usb_device_list, G_TYPE_OBJECT); + +#define GET_PRIVATE(o) (g_usb_device_list_get_instance_private(o)) static void -g_usb_device_list_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +g_usb_device_list_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - GUsbDeviceList *list = G_USB_DEVICE_LIST (object); - GUsbDeviceListPrivate *priv = list->priv; + GUsbDeviceList *self = G_USB_DEVICE_LIST(object); + GUsbDeviceListPrivate *priv = GET_PRIVATE(self); switch (prop_id) { case PROP_CONTEXT: - g_value_set_object (value, priv->context); + g_value_set_object(value, priv->context); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void -g_usb_device_added_cb (GUsbContext *context, - GUsbDevice *device, - GUsbDeviceList *list) +g_usb_device_added_cb(GUsbContext *context, GUsbDevice *device, GUsbDeviceList *self) { - g_signal_emit (list, signalsDEVICE_ADDED_SIGNAL, 0, device); + g_signal_emit(self, signalsDEVICE_ADDED_SIGNAL, 0, device); } static void -g_usb_device_removed_cb (GUsbContext *context, - GUsbDevice *device, - GUsbDeviceList *list) +g_usb_device_removed_cb(GUsbContext *context, GUsbDevice *device, GUsbDeviceList *self) { - g_signal_emit (list, signalsDEVICE_REMOVED_SIGNAL, 0, device); + g_signal_emit(self, signalsDEVICE_REMOVED_SIGNAL, 0, device); } static void -g_usb_device_list_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +g_usb_device_list_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - GUsbDeviceList *list = G_USB_DEVICE_LIST (object); - GUsbDeviceListPrivate *priv = list->priv; + GUsbDeviceList *self = G_USB_DEVICE_LIST(object); + GUsbDeviceListPrivate *priv = GET_PRIVATE(self); switch (prop_id) { case PROP_CONTEXT: - priv->context = g_value_get_object (value); - g_signal_connect (priv->context, "device-added", - G_CALLBACK (g_usb_device_added_cb), list); - g_signal_connect (priv->context, "device-removed", - G_CALLBACK (g_usb_device_removed_cb), list); + priv->context = g_value_get_object(value); + g_signal_connect(priv->context, + "device-added", + G_CALLBACK(g_usb_device_added_cb), + self); + g_signal_connect(priv->context, + "device-removed", + G_CALLBACK(g_usb_device_removed_cb), + self); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void -g_usb_device_list_class_init (GUsbDeviceListClass *klass) +g_usb_device_list_class_init(GUsbDeviceListClass *klass) { GParamSpec *pspec; - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); - object_class->get_property = g_usb_device_list_get_property; - object_class->set_property = g_usb_device_list_set_property; + object_class->get_property = g_usb_device_list_get_property; + object_class->set_property = g_usb_device_list_set_property; /** * GUsbDeviceList:context: */ - pspec = g_param_spec_object ("context", NULL, NULL, - G_USB_TYPE_CONTEXT, - G_PARAM_CONSTRUCT_ONLY| - G_PARAM_READWRITE); - g_object_class_install_property (object_class, PROP_CONTEXT, pspec); + pspec = g_param_spec_object("context", + NULL, + NULL, + G_USB_TYPE_CONTEXT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + g_object_class_install_property(object_class, PROP_CONTEXT, pspec); /** * GUsbDeviceList::device-added: - * @list: the #GUsbDeviceList instance that emitted the signal + * @self: the #GUsbDeviceList instance that emitted the signal * @device: A #GUsbDevice * * This signal is emitted when a USB device is added. **/ - signalsDEVICE_ADDED_SIGNAL = g_signal_new ("device-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GUsbDeviceListClass, device_added), - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - G_USB_TYPE_DEVICE); + signalsDEVICE_ADDED_SIGNAL = + g_signal_new("device-added", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GUsbDeviceListClass, device_added), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_USB_TYPE_DEVICE); /** * GUsbDeviceList::device-removed: - * @list: the #GUsbDeviceList instance that emitted the signal + * @self: the #GUsbDeviceList instance that emitted the signal * @device: A #GUsbDevice * * This signal is emitted when a USB device is removed. **/ - signalsDEVICE_REMOVED_SIGNAL = g_signal_new ("device-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GUsbDeviceListClass, device_removed), - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - G_USB_TYPE_DEVICE); + signalsDEVICE_REMOVED_SIGNAL = + g_signal_new("device-removed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GUsbDeviceListClass, device_removed), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_USB_TYPE_DEVICE); } static void -g_usb_device_list_init (GUsbDeviceList *list) +g_usb_device_list_init(GUsbDeviceList *self) { - list->priv = g_usb_device_list_get_instance_private (list); } /** * g_usb_device_list_get_devices: - * @list: a #GUsbDeviceList + * @self: a #GUsbDeviceList * * Return value: (transfer full) (element-type GUsbDevice): a new #GPtrArray of #GUsbDevice's. * * Since: 0.1.0 **/ GPtrArray * -g_usb_device_list_get_devices (GUsbDeviceList *list) +g_usb_device_list_get_devices(GUsbDeviceList *self) { - g_return_val_if_fail (G_USB_IS_DEVICE_LIST (list), NULL); - - return g_usb_context_get_devices (list->priv->context); + GUsbDeviceListPrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE_LIST(self), NULL); + return g_usb_context_get_devices(priv->context); } /** * g_usb_device_list_coldplug: - * @list: a #GUsbDeviceList + * @self: a #GUsbDeviceList * * This function does nothing. * * Since: 0.1.0 **/ void -g_usb_device_list_coldplug (GUsbDeviceList *list) +g_usb_device_list_coldplug(GUsbDeviceList *self) { return; } /** * g_usb_device_list_find_by_bus_address: - * @list: a #GUsbDeviceList + * @self: a #GUsbDeviceList * @bus: a bus number * @address: a bus address * @error: A #GError or %NULL @@ -208,21 +199,20 @@ * Since: 0.1.0 **/ GUsbDevice * -g_usb_device_list_find_by_bus_address (GUsbDeviceList *list, - guint8 bus, - guint8 address, - GError **error) +g_usb_device_list_find_by_bus_address(GUsbDeviceList *self, + guint8 bus, + guint8 address, + GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE_LIST (list), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - return g_usb_context_find_by_bus_address (list->priv->context, - bus, address, error); + GUsbDeviceListPrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE_LIST(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); + return g_usb_context_find_by_bus_address(priv->context, bus, address, error); } /** * g_usb_device_list_find_by_vid_pid: - * @list: a #GUsbDeviceList + * @self: a #GUsbDeviceList * @vid: a vendor ID * @pid: a product ID * @error: A #GError or %NULL @@ -234,16 +224,12 @@ * Since: 0.1.0 **/ GUsbDevice * -g_usb_device_list_find_by_vid_pid (GUsbDeviceList *list, - guint16 vid, - guint16 pid, - GError **error) +g_usb_device_list_find_by_vid_pid(GUsbDeviceList *self, guint16 vid, guint16 pid, GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE_LIST (list), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - return g_usb_context_find_by_vid_pid (list->priv->context, - vid, pid, error); + GUsbDeviceListPrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE_LIST(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); + return g_usb_context_find_by_vid_pid(priv->context, vid, pid, error); } /** @@ -260,7 +246,7 @@ * Since: 0.1.0 **/ GUsbDeviceList * -g_usb_device_list_new (GUsbContext *context) +g_usb_device_list_new(GUsbContext *context) { - return g_object_new (G_USB_TYPE_DEVICE_LIST, "context", context, NULL); + return g_object_new(G_USB_TYPE_DEVICE_LIST, "context", context, NULL); }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-device-list.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device-list.h
Changed
@@ -1,42 +1,26 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> - * Copyright (C) 2011-2014 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include <glib-object.h> - #include <gusb/gusb-context.h> -#include <gusb/gusb-device.h> G_BEGIN_DECLS -#define G_USB_TYPE_DEVICE_LIST (g_usb_device_list_get_type ()) -#define G_USB_DEVICE_LIST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_USB_TYPE_DEVICE_LIST, GUsbDeviceList)) -#define G_USB_IS_DEVICE_LIST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_USB_TYPE_DEVICE_LIST)) - -typedef struct _GUsbDeviceListPrivate GUsbDeviceListPrivate; -typedef struct _GUsbDeviceList GUsbDeviceList; -typedef struct _GUsbDeviceListClass GUsbDeviceListClass; +#define G_USB_TYPE_DEVICE_LIST (g_usb_device_list_get_type()) -struct _GUsbDeviceList -{ - GObject parent; - GUsbDeviceListPrivate *priv; -}; +G_DECLARE_DERIVABLE_TYPE(GUsbDeviceList, g_usb_device_list, G_USB, DEVICE_LIST, GObject) -struct _GUsbDeviceListClass -{ - GObjectClass parent_class; +struct _GUsbDeviceListClass { + GObjectClass parent_class; /* Signals */ - void (*device_added) (GUsbDeviceList *list, - GUsbDevice *device); - void (*device_removed) (GUsbDeviceList *list, - GUsbDevice *device); + void (*device_added)(GUsbDeviceList *self, GUsbDevice *device); + void (*device_removed)(GUsbDeviceList *self, GUsbDevice *device); /*< private >*/ /* * If adding fields to this struct, remove corresponding @@ -45,27 +29,27 @@ gchar _gusb_reserved64; }; -GType g_usb_device_list_get_type (void); - G_DEPRECATED_FOR(g_usb_context_new) -GUsbDeviceList *g_usb_device_list_new (GUsbContext *context); +GUsbDeviceList * +g_usb_device_list_new(GUsbContext *context); G_DEPRECATED -void g_usb_device_list_coldplug (GUsbDeviceList *list); +void +g_usb_device_list_coldplug(GUsbDeviceList *self); G_DEPRECATED_FOR(g_usb_context_get_devices) -GPtrArray *g_usb_device_list_get_devices (GUsbDeviceList *list); +GPtrArray * +g_usb_device_list_get_devices(GUsbDeviceList *self); G_DEPRECATED_FOR(g_usb_context_find_by_bus_address) -GUsbDevice *g_usb_device_list_find_by_bus_address (GUsbDeviceList *list, - guint8 bus, - guint8 address, - GError **error); +GUsbDevice * +g_usb_device_list_find_by_bus_address(GUsbDeviceList *self, + guint8 bus, + guint8 address, + GError **error); G_DEPRECATED_FOR(g_usb_context_find_by_vid_pid) -GUsbDevice *g_usb_device_list_find_by_vid_pid (GUsbDeviceList *list, - guint16 vid, - guint16 pid, - GError **error); +GUsbDevice * +g_usb_device_list_find_by_vid_pid(GUsbDeviceList *self, guint16 vid, guint16 pid, GError **error); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-device-private.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device-private.h
Changed
@@ -7,16 +7,23 @@ #pragma once +#include <gusb/gusb-device-event.h> #include <gusb/gusb-device.h> G_BEGIN_DECLS -GUsbDevice *_g_usb_device_new (GUsbContext *context, - libusb_device *device, - GError **error); +GUsbDevice * +_g_usb_device_new(GUsbContext *context, libusb_device *device, GError **error); +gboolean +_g_usb_device_load(GUsbDevice *self, JsonObject *json_object, GError **error); +gboolean +_g_usb_device_save(GUsbDevice *self, JsonBuilder *json_builder, GError **error); +void +_g_usb_device_add_event(GUsbDevice *self, GUsbDeviceEvent *event); -libusb_device *_g_usb_device_get_device (GUsbDevice *device); -gboolean _g_usb_device_open_internal (GUsbDevice *device, - GError **error); +libusb_device * +_g_usb_device_get_device(GUsbDevice *self); +gboolean +_g_usb_device_open_internal(GUsbDevice *self, GError **error); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-device.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device.c
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2010-2015 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * Copyright (C) 2011 Debarshi Ray <debarshir@src.gnome.org> * @@ -16,48 +16,58 @@ #include "config.h" -#include <string.h> - #include <libusb.h> +#include <string.h> -#include "gusb-context.h" +#include "gusb-bos-descriptor-private.h" #include "gusb-context-private.h" -#include "gusb-util.h" -#include "gusb-device.h" +#include "gusb-device-event-private.h" #include "gusb-device-private.h" #include "gusb-interface-private.h" +#include "gusb-json-common.h" +#include "gusb-util.h" /** * GUsbDevicePrivate: * * Private #GUsbDevice data **/ -struct _GUsbDevicePrivate -{ - gchar *platform_id; - GUsbContext *context; - libusb_device *device; - libusb_device_handle *handle; +typedef struct { + gchar *platform_id; + GUsbContext *context; + libusb_device *device; + libusb_device_handle *handle; struct libusb_device_descriptor desc; + gboolean interfaces_valid; + gboolean bos_descriptors_valid; + GPtrArray *interfaces; /* of GUsbInterface */ + GPtrArray *bos_descriptors; /* of GUsbBosDescriptor */ + GPtrArray *events; /* of GUsbDeviceEvent */ + GPtrArray *tags; /* of utf-8 */ + guint event_idx; + GDateTime *created; +} GUsbDevicePrivate; + +enum { PROP_0, PROP_LIBUSB_DEVICE, PROP_CONTEXT, PROP_PLATFORM_ID, N_PROPERTIES }; + +static GParamSpec *pspecsN_PROPERTIES = { + NULL, }; -enum { - PROP_0, - PROP_LIBUSB_DEVICE, - PROP_CONTEXT, - PROP_PLATFORM_ID, - N_PROPERTIES -}; - -static GParamSpec *pspecsN_PROPERTIES = { NULL, }; +static void +g_usb_device_initable_iface_init(GInitableIface *iface); -static void g_usb_device_initable_iface_init (GInitableIface *iface); +G_DEFINE_TYPE_EXTENDED(GUsbDevice, + g_usb_device, + G_TYPE_OBJECT, + 0, + G_ADD_PRIVATE(GUsbDevice) + G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, + g_usb_device_initable_iface_init)); -G_DEFINE_TYPE_WITH_CODE (GUsbDevice, g_usb_device, G_TYPE_OBJECT, - G_ADD_PRIVATE (GUsbDevice) - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - g_usb_device_initable_iface_init)) +#define GET_PRIVATE(o) (g_usb_device_get_instance_private(o)) +/* clang-format off */ /** * g_usb_device_error_quark: * @@ -66,110 +76,105 @@ * Since: 0.1.0 **/ G_DEFINE_QUARK (g-usb-device-error-quark, g_usb_device_error) +/* clang-format on */ static void -g_usb_device_finalize (GObject *object) +g_usb_device_finalize(GObject *object) { - GUsbDevice *device = G_USB_DEVICE (object); - GUsbDevicePrivate *priv = device->priv; + GUsbDevice *self = G_USB_DEVICE(object); + GUsbDevicePrivate *priv = GET_PRIVATE(self); - g_free (priv->platform_id); + g_free(priv->platform_id); + g_date_time_unref(priv->created); + g_ptr_array_unref(priv->interfaces); + g_ptr_array_unref(priv->bos_descriptors); + g_ptr_array_unref(priv->events); + g_ptr_array_unref(priv->tags); - G_OBJECT_CLASS (g_usb_device_parent_class)->finalize (object); + G_OBJECT_CLASS(g_usb_device_parent_class)->finalize(object); } static void -g_usb_device_dispose (GObject *object) +g_usb_device_dispose(GObject *object) { - GUsbDevice *device = G_USB_DEVICE (object); - GUsbDevicePrivate *priv = device->priv; + GUsbDevice *self = G_USB_DEVICE(object); + GUsbDevicePrivate *priv = GET_PRIVATE(self); - g_clear_pointer (&priv->device, libusb_unref_device); - g_clear_object (&priv->context); + g_clear_pointer(&priv->device, libusb_unref_device); + g_clear_object(&priv->context); - G_OBJECT_CLASS (g_usb_device_parent_class)->dispose (object); + G_OBJECT_CLASS(g_usb_device_parent_class)->dispose(object); } static void -g_usb_device_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +g_usb_device_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - GUsbDevice *device = G_USB_DEVICE (object); - GUsbDevicePrivate *priv = device->priv; + GUsbDevice *self = G_USB_DEVICE(object); + GUsbDevicePrivate *priv = GET_PRIVATE(self); switch (prop_id) { case PROP_LIBUSB_DEVICE: - g_value_set_pointer (value, priv->device); + g_value_set_pointer(value, priv->device); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void -set_libusb_device (GUsbDevice *device, - struct libusb_device *dev) +set_libusb_device(GUsbDevice *self, struct libusb_device *dev) { - GUsbDevicePrivate *priv = device->priv; + GUsbDevicePrivate *priv = GET_PRIVATE(self); - g_clear_pointer (&priv->device, libusb_unref_device); + g_clear_pointer(&priv->device, libusb_unref_device); if (dev != NULL) - priv->device = libusb_ref_device (dev); + priv->device = libusb_ref_device(dev); } static void -g_usb_device_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +g_usb_device_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GUsbDevice *device = G_USB_DEVICE (object); - GUsbDevicePrivate *priv = device->priv; + GUsbDevice *self = G_USB_DEVICE(object); + GUsbDevicePrivate *priv = GET_PRIVATE(self); switch (prop_id) { case PROP_LIBUSB_DEVICE: - set_libusb_device (device, g_value_get_pointer (value)); + set_libusb_device(self, g_value_get_pointer(value)); break; case PROP_CONTEXT: - priv->context = g_value_dup_object (value); + priv->context = g_value_dup_object(value); break; case PROP_PLATFORM_ID: - priv->platform_id = g_value_dup_string (value); + priv->platform_id = g_value_dup_string(value); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void -g_usb_device_constructed (GObject *object) +g_usb_device_constructed(GObject *object) { - GUsbDevice *device = G_USB_DEVICE (object); - GUsbDevicePrivate *priv; - gint rc; - - priv = device->priv; - - if (!priv->device) - g_error("constructed without a libusb_device"); + GUsbDevice *self = G_USB_DEVICE(object); + GUsbDevicePrivate *priv = GET_PRIVATE(self); - rc = libusb_get_device_descriptor (priv->device, &priv->desc); - if (rc != LIBUSB_SUCCESS) - g_warning ("Failed to get USB descriptor for device: %s", - g_usb_strerror (rc)); + if (priv->device != NULL) { + gint rc = libusb_get_device_descriptor(priv->device, &priv->desc); + if (rc != LIBUSB_SUCCESS) + g_warning("Failed to get USB descriptor for device: %s", + g_usb_strerror(rc)); + } - G_OBJECT_CLASS (g_usb_device_parent_class)->constructed (object); + G_OBJECT_CLASS(g_usb_device_parent_class)->constructed(object); } static void -g_usb_device_class_init (GUsbDeviceClass *klass) +g_usb_device_class_init(GUsbDeviceClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = g_usb_device_finalize; object_class->dispose = g_usb_device_dispose; @@ -181,41 +186,411 @@ * GUsbDevice:libusb_device: */ pspecsPROP_LIBUSB_DEVICE = - g_param_spec_pointer ("libusb-device", NULL, NULL, - G_PARAM_CONSTRUCT_ONLY| - G_PARAM_READWRITE); + g_param_spec_pointer("libusb-device", + NULL, + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); /** * GUsbDevice:context: */ - pspecsPROP_CONTEXT = - g_param_spec_object ("context", NULL, NULL, - G_USB_TYPE_CONTEXT, - G_PARAM_CONSTRUCT_ONLY| - G_PARAM_WRITABLE); + pspecsPROP_CONTEXT = g_param_spec_object("context", + NULL, + NULL, + G_USB_TYPE_CONTEXT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); /** * GUsbDevice:platform-id: */ - pspecsPROP_PLATFORM_ID = - g_param_spec_string ("platform-id", NULL, NULL, - NULL, - G_PARAM_CONSTRUCT_ONLY| - G_PARAM_WRITABLE); + pspecsPROP_PLATFORM_ID = g_param_spec_string("platform-id", + NULL, + NULL, + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); - g_object_class_install_properties (object_class, N_PROPERTIES, pspecs); + g_object_class_install_properties(object_class, N_PROPERTIES, pspecs); } static void -g_usb_device_init (GUsbDevice *device) +g_usb_device_init(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + priv->created = g_date_time_new_now_utc(); + priv->interfaces = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + priv->bos_descriptors = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + priv->events = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + priv->tags = g_ptr_array_new_with_free_func(g_free); +} + +/* private */ +void +_g_usb_device_add_event(GUsbDevice *self, GUsbDeviceEvent *event) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_if_fail(G_USB_IS_DEVICE(self)); + g_return_if_fail(G_USB_IS_DEVICE_EVENT(event)); + g_ptr_array_add(priv->events, g_object_ref(event)); +} + +gboolean +_g_usb_device_load(GUsbDevice *self, JsonObject *json_object, GError **error) { - device->priv = g_usb_device_get_instance_private (device); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + const gchar *tmp; + + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(json_object != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* optional properties */ + tmp = json_object_get_string_member_with_default(json_object, "PlatformId", NULL); + if (tmp != NULL) { + g_free(priv->platform_id); + priv->platform_id = g_strdup(tmp); + } + tmp = json_object_get_string_member_with_default(json_object, "Created", NULL); + if (tmp != NULL) { + g_autoptr(GDateTime) created_new = g_date_time_new_from_iso8601(tmp, NULL); + if (created_new == NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Cannot parse ISO8601 date: %s", + tmp); + return FALSE; + } + if (!g_date_time_equal(priv->created, created_new)) { + g_date_time_unref(priv->created); + priv->created = g_steal_pointer(&created_new); + } + } + priv->desc.idVendor = json_object_get_int_member_with_default(json_object, "IdVendor", 0x0); + priv->desc.idProduct = + json_object_get_int_member_with_default(json_object, "IdProduct", 0x0); + priv->desc.bcdDevice = json_object_get_int_member_with_default(json_object, "Device", 0x0); + priv->desc.bcdUSB = json_object_get_int_member_with_default(json_object, "USB", 0x0); + priv->desc.iManufacturer = + json_object_get_int_member_with_default(json_object, "Manufacturer", 0x0); + priv->desc.bDeviceClass = + json_object_get_int_member_with_default(json_object, "DeviceClass", 0x0); + priv->desc.bDeviceSubClass = + json_object_get_int_member_with_default(json_object, "DeviceSubClass", 0x0); + priv->desc.bDeviceProtocol = + json_object_get_int_member_with_default(json_object, "DeviceProtocol", 0x0); + priv->desc.iProduct = json_object_get_int_member_with_default(json_object, "Product", 0x0); + priv->desc.iSerialNumber = + json_object_get_int_member_with_default(json_object, "SerialNumber", 0x0); + + /* array of BOS descriptors */ + if (json_object_has_member(json_object, "UsbBosDescriptors")) { + JsonArray *json_array = + json_object_get_array_member(json_object, "UsbBosDescriptors"); + for (guint i = 0; i < json_array_get_length(json_array); i++) { + JsonNode *node_tmp = json_array_get_element(json_array, i); + JsonObject *obj_tmp = json_node_get_object(node_tmp); + g_autoptr(GUsbBosDescriptor) bos_descriptor = + g_object_new(G_USB_TYPE_BOS_DESCRIPTOR, NULL); + if (!_g_usb_bos_descriptor_load(bos_descriptor, obj_tmp, error)) + return FALSE; + g_ptr_array_add(priv->bos_descriptors, g_object_ref(bos_descriptor)); + } + } + + /* array of interfaces */ + if (json_object_has_member(json_object, "UsbInterfaces")) { + JsonArray *json_array = json_object_get_array_member(json_object, "UsbInterfaces"); + for (guint i = 0; i < json_array_get_length(json_array); i++) { + JsonNode *node_tmp = json_array_get_element(json_array, i); + JsonObject *obj_tmp = json_node_get_object(node_tmp); + g_autoptr(GUsbInterface) interface = + g_object_new(G_USB_TYPE_INTERFACE, NULL); + if (!_g_usb_interface_load(interface, obj_tmp, error)) + return FALSE; + g_ptr_array_add(priv->interfaces, g_object_ref(interface)); + } + } + + /* array of events */ + if (json_object_has_member(json_object, "UsbEvents")) { + JsonArray *json_array = json_object_get_array_member(json_object, "UsbEvents"); + for (guint i = 0; i < json_array_get_length(json_array); i++) { + JsonNode *node_tmp = json_array_get_element(json_array, i); + JsonObject *obj_tmp = json_node_get_object(node_tmp); + g_autoptr(GUsbDeviceEvent) event = _g_usb_device_event_new(NULL); + if (!_g_usb_device_event_load(event, obj_tmp, error)) + return FALSE; + g_ptr_array_add(priv->events, g_steal_pointer(&event)); + } + } + + /* array of tags */ + if (json_object_has_member(json_object, "Tags")) { + JsonArray *json_array = json_object_get_array_member(json_object, "Tags"); + for (guint i = 0; i < json_array_get_length(json_array); i++) { + JsonNode *node_tmp = json_array_get_element(json_array, i); + const gchar *str = json_node_get_string(node_tmp); + if (str != NULL && str0 != '\0') + g_ptr_array_add(priv->tags, g_strdup(str)); + } + } + + /* success */ + priv->interfaces_valid = TRUE; + priv->bos_descriptors_valid = TRUE; + priv->event_idx = 0; + return TRUE; +} + +gboolean +_g_usb_device_save(GUsbDevice *self, JsonBuilder *json_builder, GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_autoptr(GPtrArray) bos_descriptors = NULL; + g_autoptr(GPtrArray) interfaces = NULL; + g_autoptr(GError) error_bos = NULL; + g_autoptr(GError) error_interfaces = NULL; + + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(json_builder != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* start */ + json_builder_begin_object(json_builder); + + /* optional properties */ + if (priv->platform_id != NULL) { + json_builder_set_member_name(json_builder, "PlatformId"); + json_builder_add_string_value(json_builder, priv->platform_id); + } +#if GLIB_CHECK_VERSION(2, 62, 0) + if (priv->created != NULL) { + g_autofree gchar *str = g_date_time_format_iso8601(priv->created); + json_builder_set_member_name(json_builder, "Created"); + json_builder_add_string_value(json_builder, str); + } +#endif + if (priv->tags->len > 0) { + json_builder_set_member_name(json_builder, "Tags"); + json_builder_begin_array(json_builder); + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag = g_ptr_array_index(priv->tags, i); + json_builder_add_string_value(json_builder, tag); + } + json_builder_end_array(json_builder); + } + if (priv->desc.idVendor != 0) { + json_builder_set_member_name(json_builder, "IdVendor"); + json_builder_add_int_value(json_builder, priv->desc.idVendor); + } + if (priv->desc.idProduct != 0) { + json_builder_set_member_name(json_builder, "IdProduct"); + json_builder_add_int_value(json_builder, priv->desc.idProduct); + } + if (priv->desc.bcdDevice != 0) { + json_builder_set_member_name(json_builder, "Device"); + json_builder_add_int_value(json_builder, priv->desc.bcdDevice); + } + if (priv->desc.bcdUSB != 0) { + json_builder_set_member_name(json_builder, "USB"); + json_builder_add_int_value(json_builder, priv->desc.bcdUSB); + } + if (priv->desc.iManufacturer != 0) { + json_builder_set_member_name(json_builder, "Manufacturer"); + json_builder_add_int_value(json_builder, priv->desc.iManufacturer); + } + if (priv->desc.bDeviceClass != 0) { + json_builder_set_member_name(json_builder, "DeviceClass"); + json_builder_add_int_value(json_builder, priv->desc.bDeviceClass); + } + if (priv->desc.bDeviceSubClass != 0) { + json_builder_set_member_name(json_builder, "DeviceSubClass"); + json_builder_add_int_value(json_builder, priv->desc.bDeviceSubClass); + } + if (priv->desc.bDeviceProtocol != 0) { + json_builder_set_member_name(json_builder, "DeviceProtocol"); + json_builder_add_int_value(json_builder, priv->desc.bDeviceProtocol); + } + if (priv->desc.iProduct != 0) { + json_builder_set_member_name(json_builder, "Product"); + json_builder_add_int_value(json_builder, priv->desc.iProduct); + } + if (priv->desc.iSerialNumber != 0) { + json_builder_set_member_name(json_builder, "SerialNumber"); + json_builder_add_int_value(json_builder, priv->desc.iSerialNumber); + } + + /* array of BOS descriptors */ + bos_descriptors = g_usb_device_get_bos_descriptors(self, &error_bos); + if (bos_descriptors == NULL) { + if (_g_usb_context_has_flag(priv->context, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("%s", error_bos->message); + } else if (bos_descriptors->len > 0) { + json_builder_set_member_name(json_builder, "UsbBosDescriptors"); + json_builder_begin_array(json_builder); + for (guint i = 0; i < bos_descriptors->len; i++) { + GUsbBosDescriptor *bos_descriptor = g_ptr_array_index(bos_descriptors, i); + if (!_g_usb_bos_descriptor_save(bos_descriptor, json_builder, error)) + return FALSE; + } + json_builder_end_array(json_builder); + } + + /* array of interfaces */ + interfaces = g_usb_device_get_interfaces(self, &error_interfaces); + if (interfaces == NULL) { + if (_g_usb_context_has_flag(priv->context, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("%s", error_interfaces->message); + } else if (interfaces->len > 0) { + json_builder_set_member_name(json_builder, "UsbInterfaces"); + json_builder_begin_array(json_builder); + for (guint i = 0; i < interfaces->len; i++) { + GUsbInterface *interface = g_ptr_array_index(interfaces, i); + if (!_g_usb_interface_save(interface, json_builder, error)) + return FALSE; + } + json_builder_end_array(json_builder); + } + + /* events */ + if (priv->events->len > 0) { + json_builder_set_member_name(json_builder, "UsbEvents"); + json_builder_begin_array(json_builder); + for (guint i = 0; i < priv->events->len; i++) { + GUsbDeviceEvent *event = g_ptr_array_index(priv->events, i); + if (!_g_usb_device_event_save(event, json_builder, error)) + return FALSE; + } + json_builder_end_array(json_builder); + } + + /* success */ + json_builder_end_object(json_builder); + return TRUE; +} + +/** + * g_usb_device_get_created: + * @self: a #GUsbDevice + * + * Gets the date and time that the #GUsbDevice was created. + * + * This can be used as an indicator if the device replugged, as the vendor and product IDs may not + * change for some devices. Use `g_date_time_equal()` to verify equality. + * + * Returns: (transfer none): a #GDateTime + * + * Since: 0.4.5 + **/ +GDateTime * +g_usb_device_get_created(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + return priv->created; +} + +/** + * g_usb_device_get_tags: + * @self: a #GUsbDevice + * + * Gets all the tags. + * + * Returns: (transfer container) (element-type utf8): string tags + * + * Since: 0.4.4 + **/ +GPtrArray * +g_usb_device_get_tags(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + return g_ptr_array_ref(priv->tags); +} + +/** + * g_usb_device_has_tag: + * @self: a #GUsbDevice + * @tag: a tag, for example `bootloader` or `runtime-reload` + * + * Checks if a tag has been used to identify the specific device. + * + * Return value: %TRUE on success + * + * Since: 0.4.3 + **/ +gboolean +g_usb_device_has_tag(GUsbDevice *self, const gchar *tag) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(tag != NULL, FALSE); + + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag_tmp = g_ptr_array_index(priv->tags, i); + if (g_strcmp0(tag_tmp, tag) == 0) + return TRUE; + } + return FALSE; +} + +/** + * g_usb_device_add_tag: + * @self: a #GUsbDevice + * @tag: a tag, for example `bootloader` or `runtime-reload` + * + * Adds a tag, which is included in the JSON log to identify the specific device. + * + * For instance, there might be a pre-update runtime, a bootloader and a post-update runtime + * and allowing tags to be saved to the backend object allows us to identify each version of + * the same physical device. + * + * Since: 0.4.1 + **/ +void +g_usb_device_add_tag(GUsbDevice *self, const gchar *tag) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_if_fail(G_USB_IS_DEVICE(self)); + g_return_if_fail(tag != NULL); + + if (g_usb_device_has_tag(self, tag)) + return; + g_ptr_array_add(priv->tags, g_strdup(tag)); +} + +/** + * g_usb_device_remove_tag: + * @self: a #GUsbDevice + * @tag: a tag, for example `bootloader` or `runtime-reload` + * + * Removes a tag, which is included in the JSON log to identify the specific device. + * + * Since: 0.4.4 + **/ +void +g_usb_device_remove_tag(GUsbDevice *self, const gchar *tag) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_if_fail(G_USB_IS_DEVICE(self)); + g_return_if_fail(tag != NULL); + + for (guint i = 0; i < priv->tags->len; i++) { + const gchar *tag_tmp = g_ptr_array_index(priv->tags, i); + if (g_strcmp0(tag_tmp, tag) == 0) { + g_ptr_array_remove_index(priv->tags, i); + return; + } + } } /* not defined in FreeBSD */ #ifndef HAVE_LIBUSB_GET_PARENT static libusb_device * -libusb_get_parent (libusb_device *dev) +libusb_get_parent(libusb_device *dev) { return NULL; } @@ -224,67 +599,69 @@ /* not defined in DragonFlyBSD */ #ifndef HAVE_LIBUSB_GET_PORT_NUMBER static guint8 -libusb_get_port_number (libusb_device *dev) +libusb_get_port_number(libusb_device *dev) { return 0xff; } #endif static void -g_usb_device_build_parent_port_number (GString *str, libusb_device *dev) +g_usb_device_build_parent_port_number(GString *str, libusb_device *dev) { - libusb_device *parent = libusb_get_parent (dev); + libusb_device *parent = libusb_get_parent(dev); if (parent != NULL) - g_usb_device_build_parent_port_number (str, parent); - g_string_append_printf (str, "%02x:", libusb_get_port_number (dev)); + g_usb_device_build_parent_port_number(str, parent); + g_string_append_printf(str, "%02x:", libusb_get_port_number(dev)); } static gchar * -g_usb_device_build_platform_id (struct libusb_device *dev) +g_usb_device_build_platform_id(struct libusb_device *dev) { GString *platform_id; /* build a topology of the device */ - platform_id = g_string_new ("usb:"); - g_string_append_printf (platform_id, "%02x:", libusb_get_bus_number (dev)); - g_usb_device_build_parent_port_number (platform_id, dev); - g_string_truncate (platform_id, platform_id->len - 1); - return g_string_free (platform_id, FALSE); + platform_id = g_string_new("usb:"); + g_string_append_printf(platform_id, "%02x:", libusb_get_bus_number(dev)); + g_usb_device_build_parent_port_number(platform_id, dev); + g_string_truncate(platform_id, platform_id->len - 1); + return g_string_free(platform_id, FALSE); } static gboolean -g_usb_device_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) +g_usb_device_initable_init(GInitable *initable, GCancellable *cancellable, GError **error) { - GUsbDevice *device = G_USB_DEVICE (initable); + GUsbDevice *self = G_USB_DEVICE(initable); GUsbDevicePrivate *priv; gint rc; - priv = device->priv; + priv = GET_PRIVATE(self); - if (!priv->device) { - g_set_error_literal (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_INTERNAL, - "Constructed without a libusb_device"); + if (priv->device == NULL) { + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_INTERNAL, + "Constructed without a libusb_device"); return FALSE; } - rc = libusb_get_device_descriptor (priv->device, &priv->desc); + rc = libusb_get_device_descriptor(priv->device, &priv->desc); if (rc != LIBUSB_SUCCESS) { - g_set_error (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_INTERNAL, - "Failed to get USB descriptor for device: %s", - g_usb_strerror (rc)); + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_INTERNAL, + "Failed to get USB descriptor for device: %s", + g_usb_strerror(rc)); return FALSE; } /* this does not change on plug->unplug->plug */ - priv->platform_id = g_usb_device_build_platform_id (priv->device); + priv->platform_id = g_usb_device_build_platform_id(priv->device); return TRUE; } static void -g_usb_device_initable_iface_init (GInitableIface *iface) +g_usb_device_initable_iface_init(GInitableIface *iface) { iface->init = g_usb_device_initable_init; } @@ -297,35 +674,52 @@ * Since: 0.1.0 **/ GUsbDevice * -_g_usb_device_new (GUsbContext *context, - libusb_device *device, - GError **error) +_g_usb_device_new(GUsbContext *context, libusb_device *device, GError **error) { - return g_initable_new (G_USB_TYPE_DEVICE, - NULL, error, - "context", context, - "libusb-device", device, - NULL); + return g_initable_new(G_USB_TYPE_DEVICE, + NULL, + error, + "context", + context, + "libusb-device", + device, + NULL); } /** * _g_usb_device_get_device: - * @device: a #GUsbDevice instance + * @self: a #GUsbDevice instance * * Gets the low-level libusb_device * * Return value: The #libusb_device or %NULL. Do not unref this value. **/ libusb_device * -_g_usb_device_get_device (GUsbDevice *device) +_g_usb_device_get_device(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + return priv->device; +} + +/** + * g_usb_device_is_emulated: + * @self: a #GUsbDevice instance + * + * Gets if the device is emulated. + * + * Return value: %TRUE if the device is emulated and not backed by a physical device. + * + * Since: 0.4.4 + **/ +gboolean +g_usb_device_is_emulated(GUsbDevice *self) { - return device->priv->device; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + return priv->device == NULL; } static gboolean -g_usb_device_libusb_error_to_gerror (GUsbDevice *device, - gint rc, - GError **error) +g_usb_device_libusb_error_to_gerror(GUsbDevice *self, gint rc, GError **error) { gint error_code = G_USB_DEVICE_ERROR_INTERNAL; /* Put the rc in libusb's error enum so that gcc warns us if we're @@ -364,65 +758,75 @@ break; } - g_set_error (error, G_USB_DEVICE_ERROR, error_code, - "USB error on device %04x:%04x : %s %i", - g_usb_device_get_vid (device), - g_usb_device_get_pid (device), - g_usb_strerror (rc), rc); + g_set_error(error, + G_USB_DEVICE_ERROR, + error_code, + "USB error on device %04x:%04x : %s %i", + g_usb_device_get_vid(self), + g_usb_device_get_pid(self), + g_usb_strerror(rc), + rc); return FALSE; } static gboolean -g_usb_device_not_open_error (GUsbDevice *device, - GError **error) -{ - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_OPEN, - "Device %04x:%04x has not been opened", - g_usb_device_get_vid (device), - g_usb_device_get_pid (device)); +g_usb_device_not_open_error(GUsbDevice *self, GError **error) +{ + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_OPEN, + "Device %04x:%04x has not been opened", + g_usb_device_get_vid(self), + g_usb_device_get_pid(self)); return FALSE; } static void -g_usb_device_async_not_open_error (GUsbDevice *device, - GAsyncReadyCallback callback, - gpointer user_data, - gpointer source_tag) -{ - g_task_report_new_error (device, callback, user_data, source_tag, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_OPEN, - "Device %04x:%04x has not been opened", - g_usb_device_get_vid (device), - g_usb_device_get_pid (device)); +g_usb_device_async_not_open_error(GUsbDevice *self, + GAsyncReadyCallback callback, + gpointer user_data, + gpointer source_tag) +{ + g_task_report_new_error(self, + callback, + user_data, + source_tag, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_OPEN, + "Device %04x:%04x has not been opened", + g_usb_device_get_vid(self), + g_usb_device_get_pid(self)); } gboolean -_g_usb_device_open_internal (GUsbDevice *device, GError **error) +_g_usb_device_open_internal(GUsbDevice *self, GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; - if (device->priv->handle != NULL) { - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_ALREADY_OPEN, - "Device %04x:%04x is already open", - g_usb_device_get_vid (device), - g_usb_device_get_pid (device)); + /* sanity check */ + if (priv->device == NULL) + return TRUE; + + if (priv->handle != NULL) { + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_ALREADY_OPEN, + "Device %04x:%04x is already open", + g_usb_device_get_vid(self), + g_usb_device_get_pid(self)); return FALSE; } /* open device */ - rc = libusb_open (device->priv->device, &device->priv->handle); - return g_usb_device_libusb_error_to_gerror (device, rc, error); + rc = libusb_open(priv->device, &priv->handle); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } /** * g_usb_device_open: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @error: a #GError, or %NULL * * Opens the device for use. @@ -434,22 +838,83 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_open (GUsbDevice *device, GError **error) +g_usb_device_open(GUsbDevice *self, GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* emulated */ + if (priv->device == NULL) + return TRUE; /* ignore */ - if (g_usb_context_get_flags (device->priv->context) & G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES) + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES) return TRUE; /* open */ - return _g_usb_device_open_internal (device, error); + return _g_usb_device_open_internal(self, error); +} + +/* transfer none */ +static GUsbDeviceEvent * +g_usb_device_load_event(GUsbDevice *self, const gchar *id) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + /* reset back to the beginning */ + if (priv->event_idx >= priv->events->len) { + if (_g_usb_context_has_flag(priv->context, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("resetting event index"); + priv->event_idx = 0; + } + + /* look for the next event in the sequence */ + for (guint i = priv->event_idx; i < priv->events->len; i++) { + GUsbDeviceEvent *event = g_ptr_array_index(priv->events, i); + if (g_strcmp0(g_usb_device_event_get_id(event), id) == 0) { + if (_g_usb_context_has_flag(priv->context, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("found in-order %s at position %u", id, i); + priv->event_idx = i + 1; + return event; + } + } + + /* look for *any* event that matches */ + for (guint i = 0; i < priv->events->len; i++) { + GUsbDeviceEvent *event = g_ptr_array_index(priv->events, i); + if (g_strcmp0(g_usb_device_event_get_id(event), id) == 0) { + if (_g_usb_context_has_flag(priv->context, G_USB_CONTEXT_FLAGS_DEBUG)) + g_debug("found out-of-order %s at position %u", id, i); + priv->event_idx = i + 1; + return event; + } + } + + /* nothing found */ + return NULL; +} + +/* transfer none */ +static GUsbDeviceEvent * +g_usb_device_save_event(GUsbDevice *self, const gchar *id) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + GUsbDeviceEvent *event; + + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(id != NULL, NULL); + + /* success */ + event = _g_usb_device_event_new(id); + g_ptr_array_add(priv->events, event); + return event; } /** * g_usb_device_get_custom_index: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @class_id: a device class, e.g. 0xff for VENDOR * @subclass_id: a device subclass * @protocol_id: a protocol number @@ -462,24 +927,64 @@ * Since: 0.2.5 **/ guint8 -g_usb_device_get_custom_index (GUsbDevice *device, - guint8 class_id, - guint8 subclass_id, - guint8 protocol_id, - GError **error) -{ +g_usb_device_get_custom_index(GUsbDevice *self, + guint8 class_id, + guint8 subclass_id, + guint8 protocol_id, + GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + GUsbDeviceEvent *event; const struct libusb_interface_descriptor *ifp; gint rc; guint8 idx = 0x00; - guint i; struct libusb_config_descriptor *config; + g_autofree gchar *event_id = NULL; + + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + event_id = g_strdup_printf( + "GetCustomIndex:ClassId=0x%02x,SubclassId=0x%02x,ProtocolId=0x%02x", + class_id, + subclass_id, + protocol_id); + } + + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event for %s", + event_id); + return 0x00; + } + if (!g_usb_device_libusb_error_to_gerror(self, + g_usb_device_event_get_rc(event), + error)) + return 0x00; + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL || g_bytes_get_size(bytes) != 1) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return 0x00; + } + return ((const guint8 *)g_bytes_get_data(bytes, NULL))0; + } - rc = libusb_get_active_config_descriptor (device->priv->device, &config); - if (!g_usb_device_libusb_error_to_gerror (device, rc, error)) + rc = libusb_get_active_config_descriptor(priv->device, &config); + if (!g_usb_device_libusb_error_to_gerror(self, rc, error)) return 0x00; /* find the right data */ - for (i = 0; i < config->bNumInterfaces; i++) { + for (guint i = 0; i < config->bNumInterfaces; i++) { ifp = &config->interfacei.altsetting0; if (ifp->bInterfaceClass != class_id) continue; @@ -493,21 +998,28 @@ /* nothing matched */ if (idx == 0x00) { - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_SUPPORTED, - "no vendor descriptor for class 0x%02x, " - "subclass 0x%02x and protocol 0x%02x", - class_id, subclass_id, protocol_id); + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED, + "no vendor descriptor for class 0x%02x, " + "subclass 0x%02x and protocol 0x%02x", + class_id, + subclass_id, + protocol_id); + + } else if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + /* save */ + event = g_usb_device_save_event(self, event_id); + _g_usb_device_event_set_bytes_raw(event, &idx, sizeof(idx)); } - libusb_free_config_descriptor (config); + libusb_free_config_descriptor(config); return idx; } /** * g_usb_device_get_interface: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @class_id: a device class, e.g. 0xff for VENDOR * @subclass_id: a device subclass * @protocol_id: a protocol number @@ -523,98 +1035,266 @@ * Since: 0.2.8 **/ GUsbInterface * -g_usb_device_get_interface (GUsbDevice *device, - guint8 class_id, - guint8 subclass_id, - guint8 protocol_id, - GError **error) +g_usb_device_get_interface(GUsbDevice *self, + guint8 class_id, + guint8 subclass_id, + guint8 protocol_id, + GError **error) { - const struct libusb_interface_descriptor *ifp; - gint rc; - GUsbInterface *interface = NULL; - guint i; - struct libusb_config_descriptor *config; - - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_autoptr(GPtrArray) interfaces = NULL; - rc = libusb_get_active_config_descriptor (device->priv->device, &config); - if (!g_usb_device_libusb_error_to_gerror (device, rc, error)) - return NULL; + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* find the right data */ - for (i = 0; i < config->bNumInterfaces; i++) { - ifp = &config->interfacei.altsetting0; - if (ifp->bInterfaceClass != class_id) + interfaces = g_usb_device_get_interfaces(self, error); + if (interfaces == NULL) + return NULL; + for (guint i = 0; i < interfaces->len; i++) { + GUsbInterface *interface = g_ptr_array_index(interfaces, i); + if (g_usb_interface_get_class(interface) != class_id) continue; - if (ifp->bInterfaceSubClass != subclass_id) + if (g_usb_interface_get_subclass(interface) != subclass_id) continue; - if (ifp->bInterfaceProtocol != protocol_id) + if (g_usb_interface_get_protocol(interface) != protocol_id) continue; - interface = _g_usb_interface_new (ifp); - break; + return g_object_ref(interface); } /* nothing matched */ - if (interface == NULL) { - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_SUPPORTED, - "no interface for class 0x%02x, " - "subclass 0x%02x and protocol 0x%02x", - class_id, subclass_id, protocol_id); - } - - libusb_free_config_descriptor (config); - return interface; + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED, + "no interface for class 0x%02x, " + "subclass 0x%02x and protocol 0x%02x", + class_id, + subclass_id, + protocol_id); + return NULL; } /** * g_usb_device_get_interfaces: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @error: a #GError, or %NULL * * Gets all the interfaces exported by the device. * - * Return value: (transfer container) (element-type GUsbInterface): an array of interfaces or %NULL for error + * The first time this method is used the hardware is queried and then after that cached results + * are returned. To invalidate the caches use g_usb_device_invalidate(). + * + * Return value: (transfer container) (element-type GUsbInterface): an array of interfaces or %NULL + *for error * * Since: 0.2.8 **/ GPtrArray * -g_usb_device_get_interfaces (GUsbDevice *device, GError **error) +g_usb_device_get_interfaces(GUsbDevice *self, GError **error) { - const struct libusb_interface_descriptor *ifp; - gint rc; - guint i; - guint j; - struct libusb_config_descriptor *config; - GPtrArray *array = NULL; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); + + /* get all interfaces */ + if (!priv->interfaces_valid) { + gint rc; + struct libusb_config_descriptor *config; + + /* sanity check */ + if (priv->device == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "not supported for emulated device"); + return NULL; + } + + rc = libusb_get_active_config_descriptor(priv->device, &config); + if (!g_usb_device_libusb_error_to_gerror(self, rc, error)) + return NULL; + + for (guint i = 0; i < config->bNumInterfaces; i++) { + for (guint j = 0; j < (guint)config->interfacei.num_altsetting; j++) { + const struct libusb_interface_descriptor *ifp = + &config->interfacei.altsettingj; + GUsbInterface *interface = _g_usb_interface_new(ifp); + g_ptr_array_add(priv->interfaces, interface); + } + } + libusb_free_config_descriptor(config); + priv->interfaces_valid = TRUE; + } + + /* success */ + return g_ptr_array_ref(priv->interfaces); +} + +/** + * g_usb_device_get_events: + * @self: a #GUsbDevice + * + * Gets all the events saved by the device. + * + * Events are only collected when the `G_USB_CONTEXT_FLAGS_SAVE_EVENTS` flag is used before + * enumerating the context. Events can be used to replay device transactions. + * + * Return value: (transfer container) (element-type GUsbDeviceEvent): an array of events + * + * Since: 0.4.0 + **/ +GPtrArray * +g_usb_device_get_events(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + return g_ptr_array_ref(priv->events); +} + +/** + * g_usb_device_clear_events: + * @self: a #GUsbDevice + * + * Clear all the events saved by the device. + * + * Since: 0.4.4 + **/ +void +g_usb_device_clear_events(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_if_fail(G_USB_IS_DEVICE(self)); + priv->event_idx = 0; + g_ptr_array_set_size(priv->events, 0); +} - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); +/** + * g_usb_device_invalidate: + * @self: a #GUsbDevice + * + * Invalidates the caches used in g_usb_device_get_interfaces(). + * + * Since: 0.4.0 + **/ +void +g_usb_device_invalidate(GUsbDevice *self) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_if_fail(G_USB_IS_DEVICE(self)); + priv->interfaces_valid = FALSE; + priv->bos_descriptors_valid = FALSE; + g_ptr_array_set_size(priv->interfaces, 0); + g_ptr_array_set_size(priv->bos_descriptors, 0); +} + +/** + * g_usb_device_get_bos_descriptor: + * @self: a #GUsbDevice + * @capability: a BOS capability type + * @error: a #GError, or %NULL + * + * Gets the first bos_descriptor that matches the descriptor capability. + * If you want to find all the BOS descriptors that match (there may be other matching BOS + * descriptors you have to use `g_usb_device_get_bos_descriptors()` and check each one manually. + * + * Return value: (transfer full): a #GUsbBosDescriptor or %NULL for not found + * + * Since: 0.4.0 + **/ +GUsbBosDescriptor * +g_usb_device_get_bos_descriptor(GUsbDevice *self, guint8 capability, GError **error) +{ + g_autoptr(GPtrArray) bos_descriptors = NULL; + + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); - rc = libusb_get_active_config_descriptor (device->priv->device, &config); - if (!g_usb_device_libusb_error_to_gerror (device, rc, error)) + /* find the right data */ + bos_descriptors = g_usb_device_get_bos_descriptors(self, error); + if (bos_descriptors == NULL) return NULL; + for (guint i = 0; i < bos_descriptors->len; i++) { + GUsbBosDescriptor *bos_descriptor = g_ptr_array_index(bos_descriptors, i); + if (g_usb_bos_descriptor_get_capability(bos_descriptor) == capability) + return g_object_ref(bos_descriptor); + } - /* get all interfaces */ - array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - for (i = 0; i < config->bNumInterfaces; i++) { - GUsbInterface *interface = NULL; - for (j = 0; j < (guint) config->interfacei.num_altsetting; j++) { - ifp = &config->interfacei.altsettingj; - interface = _g_usb_interface_new (ifp); - g_ptr_array_add (array, interface); + /* nothing matched */ + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED, + "no BOS descriptor for capability 0x%02x", + capability); + return NULL; +} + +/** + * g_usb_device_get_bos_descriptors: + * @self: a #GUsbDevice + * @error: a #GError, or %NULL + * + * Gets all the BOS descriptors exported by the device. + * + * The first time this method is used the hardware is queried and then after that cached results + * are returned. To invalidate the caches use g_usb_device_invalidate(). + * + * Return value: (transfer container) (element-type GUsbBosDescriptor): an array of BOS descriptors + * + * Since: 0.4.0 + **/ +GPtrArray * +g_usb_device_get_bos_descriptors(GUsbDevice *self, GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); + + /* get all BOS descriptors */ + if (!priv->bos_descriptors_valid) { + gint rc; + guint8 num_device_caps; + struct libusb_bos_descriptor *bos = NULL; + + /* sanity check */ + if (priv->device == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "not supported for emulated device"); + return NULL; } + if (priv->handle == NULL) { + g_usb_device_not_open_error(self, error); + return NULL; + } + + rc = libusb_get_bos_descriptor(priv->handle, &bos); + if (!g_usb_device_libusb_error_to_gerror(self, rc, error)) + return NULL; +#ifdef __FreeBSD__ + num_device_caps = bos->bNumDeviceCapabilities; +#else + num_device_caps = bos->bNumDeviceCaps; +#endif + for (guint i = 0; i < num_device_caps; i++) { + GUsbBosDescriptor *bos_descriptor = NULL; + struct libusb_bos_dev_capability_descriptor *bos_cap = + bos->dev_capabilityi; + bos_descriptor = _g_usb_bos_descriptor_new(bos_cap); + g_ptr_array_add(priv->bos_descriptors, bos_descriptor); + } + libusb_free_bos_descriptor(bos); + priv->bos_descriptors_valid = TRUE; } - libusb_free_config_descriptor (config); - return array; + /* success */ + return g_ptr_array_ref(priv->bos_descriptors); } /** * g_usb_device_close: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @error: a #GError, or %NULL * * Closes the device when it is no longer required. @@ -624,33 +1304,38 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_close (GUsbDevice *device, - GError **error) +g_usb_device_close(GUsbDevice *self, GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* emulated */ + if (priv->device == NULL) + return TRUE; /* ignore */ - if (g_usb_context_get_flags (device->priv->context) & G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES) + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES) return TRUE; - if (device->priv->handle == NULL) - return g_usb_device_not_open_error (device, error); + if (priv->handle == NULL) + return g_usb_device_not_open_error(self, error); - libusb_close (device->priv->handle); - device->priv->handle = NULL; + libusb_close(priv->handle); + priv->handle = NULL; return TRUE; } /** * g_usb_device_reset: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @error: a #GError, or %NULL * * Perform a USB port reset to reinitialize a device. * * If the reset succeeds, the device will appear to disconnected and reconnected. - * This means the @device will no longer be valid and should be closed and + * This means the @self will no longer be valid and should be closed and * rediscovered. * * This is a blocking function which usually incurs a noticeable delay. @@ -660,25 +1345,29 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_reset (GUsbDevice *device, - GError **error) +g_usb_device_reset(GUsbDevice *self, GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); - if (device->priv->handle == NULL) - return g_usb_device_not_open_error (device, error); + /* emulated */ + if (priv->device == NULL) + return TRUE; + + if (priv->handle == NULL) + return g_usb_device_not_open_error(self, error); - rc = libusb_reset_device (device->priv->handle); + rc = libusb_reset_device(priv->handle); if (rc == LIBUSB_ERROR_NOT_FOUND) return TRUE; - return g_usb_device_libusb_error_to_gerror (device, rc, error); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } /** * g_usb_device_get_configuration: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @error: a #GError, or %NULL * * Get the bConfigurationValue for the active configuration of the device. @@ -690,23 +1379,27 @@ * Since: 0.1.0 **/ gint -g_usb_device_get_configuration (GUsbDevice *device, - GError **error) +g_usb_device_get_configuration(GUsbDevice *self, GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; int config; - g_return_val_if_fail (G_USB_IS_DEVICE (device), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); + g_return_val_if_fail(G_USB_IS_DEVICE(self), -1); + g_return_val_if_fail(error == NULL || *error == NULL, -1); + + /* emulated */ + if (priv->device == NULL) + return 0x0; - if (device->priv->handle == NULL) { - g_usb_device_not_open_error (device, error); + if (priv->handle == NULL) { + g_usb_device_not_open_error(self, error); return -1; } - rc = libusb_get_configuration (device->priv->handle, &config); + rc = libusb_get_configuration(priv->handle, &config); if (rc != LIBUSB_SUCCESS) { - g_usb_device_libusb_error_to_gerror (device, rc, error); + g_usb_device_libusb_error_to_gerror(self, rc, error); return -1; } @@ -715,7 +1408,7 @@ /** * g_usb_device_set_configuration: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @configuration: the configuration value to set * @error: a #GError, or %NULL * @@ -728,38 +1421,38 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_set_configuration (GUsbDevice *device, - gint configuration, - GError **error) +g_usb_device_set_configuration(GUsbDevice *self, gint configuration, GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; gint config_tmp = 0; - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* emulated */ + if (priv->device == NULL) + return TRUE; - if (device->priv->handle == NULL) - return g_usb_device_not_open_error (device, error); + if (priv->handle == NULL) + return g_usb_device_not_open_error(self, error); /* verify we've not already set the same configuration */ - rc = libusb_get_configuration (device->priv->handle, - &config_tmp); + rc = libusb_get_configuration(priv->handle, &config_tmp); if (rc != LIBUSB_SUCCESS) { - return g_usb_device_libusb_error_to_gerror (device, - rc, - error); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } if (config_tmp == configuration) return TRUE; /* different, so change */ - rc = libusb_set_configuration (device->priv->handle, configuration); - return g_usb_device_libusb_error_to_gerror (device, rc, error); + rc = libusb_set_configuration(priv->handle, configuration); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } /** * g_usb_device_claim_interface: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @interface: bInterfaceNumber of the interface you wish to claim * @flags: #GUsbDeviceClaimInterfaceFlags * @error: a #GError, or %NULL @@ -771,37 +1464,39 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_claim_interface (GUsbDevice *device, - gint interface, - GUsbDeviceClaimInterfaceFlags flags, - GError **error) +g_usb_device_claim_interface(GUsbDevice *self, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); - if (device->priv->handle == NULL) - return g_usb_device_not_open_error (device, error); + /* emulated */ + if (priv->device == NULL) + return TRUE; + + if (priv->handle == NULL) + return g_usb_device_not_open_error(self, error); if (flags & G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER) { - rc = libusb_detach_kernel_driver (device->priv->handle, - interface); - if (rc != LIBUSB_SUCCESS && - rc != LIBUSB_ERROR_NOT_FOUND && /* No driver attached */ - rc != LIBUSB_ERROR_NOT_SUPPORTED && /* win32 */ + rc = libusb_detach_kernel_driver(priv->handle, interface); + if (rc != LIBUSB_SUCCESS && rc != LIBUSB_ERROR_NOT_FOUND && /* No driver attached */ + rc != LIBUSB_ERROR_NOT_SUPPORTED && /* win32 */ rc != LIBUSB_ERROR_BUSY /* driver rebound already */) - return g_usb_device_libusb_error_to_gerror (device, rc, - error); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } - rc = libusb_claim_interface (device->priv->handle, interface); - return g_usb_device_libusb_error_to_gerror (device, rc, error); + rc = libusb_claim_interface(priv->handle, interface); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } /** * g_usb_device_release_interface: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @interface: bInterfaceNumber of the interface you wish to release * @flags: #GUsbDeviceClaimInterfaceFlags * @error: a #GError, or %NULL @@ -813,32 +1508,34 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_release_interface (GUsbDevice *device, - gint interface, - GUsbDeviceClaimInterfaceFlags flags, - GError **error) +g_usb_device_release_interface(GUsbDevice *self, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* emulated */ + if (priv->device == NULL) + return TRUE; - if (device->priv->handle == NULL) - return g_usb_device_not_open_error (device, error); + if (priv->handle == NULL) + return g_usb_device_not_open_error(self, error); - rc = libusb_release_interface (device->priv->handle, interface); + rc = libusb_release_interface(priv->handle, interface); if (rc != LIBUSB_SUCCESS) - return g_usb_device_libusb_error_to_gerror (device, rc, error); + return g_usb_device_libusb_error_to_gerror(self, rc, error); if (flags & G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER) { - rc = libusb_attach_kernel_driver (device->priv->handle, - interface); - if (rc != LIBUSB_SUCCESS && - rc != LIBUSB_ERROR_NOT_FOUND && /* No driver attached */ - rc != LIBUSB_ERROR_NOT_SUPPORTED && /* win32 */ + rc = libusb_attach_kernel_driver(priv->handle, interface); + if (rc != LIBUSB_SUCCESS && rc != LIBUSB_ERROR_NOT_FOUND && /* No driver attached */ + rc != LIBUSB_ERROR_NOT_SUPPORTED && /* win32 */ rc != LIBUSB_ERROR_BUSY /* driver rebound already */) - return g_usb_device_libusb_error_to_gerror (device, rc, - error); + return g_usb_device_libusb_error_to_gerror(self, rc, error); } return TRUE; @@ -846,7 +1543,7 @@ /** * g_usb_device_set_interface_alt: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @interface: bInterfaceNumber of the interface you wish to release * @alt: alternative setting number * @error: a #GError, or %NULL @@ -858,20 +1555,24 @@ * Since: 0.2.8 **/ gboolean -g_usb_device_set_interface_alt (GUsbDevice *device, gint interface, - guint8 alt, GError **error) +g_usb_device_set_interface_alt(GUsbDevice *self, gint interface, guint8 alt, GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); gint rc; - g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail(G_USB_IS_DEVICE(self), FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* emulated */ + if (priv->device == NULL) + return TRUE; - if (device->priv->handle == NULL) - return g_usb_device_not_open_error (device, error); + if (priv->handle == NULL) + return g_usb_device_not_open_error(self, error); - rc = libusb_set_interface_alt_setting (device->priv->handle, interface, (gint) alt); + rc = libusb_set_interface_alt_setting(priv->handle, interface, (gint)alt); if (rc != LIBUSB_SUCCESS) - return g_usb_device_libusb_error_to_gerror (device, rc, error); + return g_usb_device_libusb_error_to_gerror(self, rc, error); return TRUE; } @@ -889,30 +1590,69 @@ * Since: 0.1.0 **/ gchar * -g_usb_device_get_string_descriptor (GUsbDevice *device, - guint8 desc_index, - GError **error) +g_usb_device_get_string_descriptor(GUsbDevice *self, guint8 desc_index, GError **error) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); + GUsbDeviceEvent *event; gint rc; /* libusb_get_string_descriptor_ascii returns max 128 bytes */ unsigned char buf128; + g_autofree gchar *event_id = NULL; - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); - if (device->priv->handle == NULL) { - g_usb_device_not_open_error (device, error); + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + event_id = g_strdup_printf("GetStringDescriptor:DescIndex=0x%02x", desc_index); + } + + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return NULL; + } + if (!g_usb_device_libusb_error_to_gerror(self, + g_usb_device_event_get_rc(event), + error)) + return NULL; + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return NULL; + } + return g_strndup(g_bytes_get_data(bytes, NULL), g_bytes_get_size(bytes)); + } + if (priv->handle == NULL) { + g_usb_device_not_open_error(self, error); return NULL; } - rc = libusb_get_string_descriptor_ascii (device->priv->handle, - desc_index, buf, sizeof(buf)); + rc = libusb_get_string_descriptor_ascii(priv->handle, desc_index, buf, sizeof(buf)); if (rc < 0) { - g_usb_device_libusb_error_to_gerror (device, rc, error); + g_usb_device_libusb_error_to_gerror(self, rc, error); return NULL; } - return g_strdup ((const gchar *)buf); + /* save */ + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + event = g_usb_device_save_event(self, event_id); + _g_usb_device_event_set_bytes_raw(event, buf, sizeof(buf)); + } + + return g_strdup((const gchar *)buf); } /** @@ -930,32 +1670,77 @@ * Since: 0.3.8 **/ GBytes * -g_usb_device_get_string_descriptor_bytes_full (GUsbDevice *device, - guint8 desc_index, - guint16 langid, - gsize length, - GError **error) -{ +g_usb_device_get_string_descriptor_bytes_full(GUsbDevice *self, + guint8 desc_index, + guint16 langid, + gsize length, + GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); + GUsbDeviceEvent *event; gint rc; g_autofree guint8 *buf = g_malloc0(length); + g_autofree gchar *event_id = NULL; + + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + g_return_val_if_fail(error == NULL || *error == NULL, NULL); + + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + event_id = g_strdup_printf( + "GetStringDescriptorBytes:DescIndex=0x%02x,Langid=0x%04x,Length=0x%x", + desc_index, + langid, + (guint)length); + } - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event for %s", + event_id); + return NULL; + } + if (!g_usb_device_libusb_error_to_gerror(self, + g_usb_device_event_get_rc(event), + error)) + return 0x00; + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL) { + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return NULL; + } + return g_bytes_ref(bytes); + } - if (device->priv->handle == NULL) { - g_usb_device_not_open_error (device, error); + if (priv->handle == NULL) { + g_usb_device_not_open_error(self, error); return NULL; } - rc = libusb_get_string_descriptor (device->priv->handle, - desc_index, langid, - buf, length); + rc = libusb_get_string_descriptor(priv->handle, desc_index, langid, buf, length); if (rc < 0) { - g_usb_device_libusb_error_to_gerror (device, rc, error); + g_usb_device_libusb_error_to_gerror(self, rc, error); return NULL; } - return g_bytes_new (buf, rc); + /* save */ + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + event = g_usb_device_save_event(self, event_id); + _g_usb_device_event_set_bytes_raw(event, buf, rc); + } + + return g_bytes_new(buf, rc); } /** @@ -975,40 +1760,34 @@ * Since: 0.3.6 **/ GBytes * -g_usb_device_get_string_descriptor_bytes (GUsbDevice *device, - guint8 desc_index, - guint16 langid, - GError **error) +g_usb_device_get_string_descriptor_bytes(GUsbDevice *self, + guint8 desc_index, + guint16 langid, + GError **error) { - return g_usb_device_get_string_descriptor_bytes_full(device, - desc_index, - langid, - 128, - error); + return g_usb_device_get_string_descriptor_bytes_full(self, desc_index, langid, 128, error); } -typedef gssize (GUsbDeviceTransferFinishFunc) (GUsbDevice *device, GAsyncResult *res, GError **error); +typedef gssize(GUsbDeviceTransferFinishFunc)(GUsbDevice *self, GAsyncResult *res, GError **error); typedef struct { - GError **error; - GMainContext *context; - GMainLoop *loop; - GUsbDeviceTransferFinishFunc *finish_func; - gssize ret; + GError **error; + GMainContext *context; + GMainLoop *loop; + GUsbDeviceTransferFinishFunc *finish_func; + gssize ret; } GUsbSyncHelper; static void -g_usb_device_sync_transfer_cb (GUsbDevice *device, - GAsyncResult *res, - GUsbSyncHelper *helper) +g_usb_device_sync_transfer_cb(GUsbDevice *self, GAsyncResult *res, GUsbSyncHelper *helper) { - helper->ret = (*helper->finish_func) (device, res, helper->error); - g_main_loop_quit (helper->loop); + helper->ret = (*helper->finish_func)(self, res, helper->error); + g_main_loop_quit(helper->loop); } /** * g_usb_device_control_transfer: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @request_type: the request type field for the setup packet * @request: the request field for the setup packet * @value: the value field for the setup packet @@ -1032,53 +1811,54 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_control_transfer (GUsbDevice *device, - GUsbDeviceDirection direction, - GUsbDeviceRequestType request_type, - GUsbDeviceRecipient recipient, - guint8 request, - guint16 value, - guint16 idx, - guint8 *data, - gsize length, - gsize *actual_length, - guint timeout, - GCancellable *cancellable, - GError **error) -{ +g_usb_device_control_transfer(GUsbDevice *self, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 idx, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); GUsbSyncHelper helper; helper.ret = -1; - helper.context = g_usb_context_get_main_context (device->priv->context); - helper.loop = g_main_loop_new (helper.context, FALSE); + helper.context = g_usb_context_get_main_context(priv->context); + helper.loop = g_main_loop_new(helper.context, FALSE); helper.error = error; helper.finish_func = g_usb_device_control_transfer_finish; - g_usb_device_control_transfer_async (device, - direction, - request_type, - recipient, - request, - value, - idx, - data, - length, - timeout, - cancellable, - (GAsyncReadyCallback) g_usb_device_sync_transfer_cb, - &helper); - g_main_loop_run (helper.loop); - g_main_loop_unref (helper.loop); + g_usb_device_control_transfer_async(self, + direction, + request_type, + recipient, + request, + value, + idx, + data, + length, + timeout, + cancellable, + (GAsyncReadyCallback)g_usb_device_sync_transfer_cb, + &helper); + g_main_loop_run(helper.loop); + g_main_loop_unref(helper.loop); if (actual_length != NULL) - *actual_length = (gsize) helper.ret; + *actual_length = (gsize)helper.ret; return helper.ret != -1; } /** * g_usb_device_bulk_transfer: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @endpoint: the address of a valid endpoint to communicate with * @data: (array length=length): a suitably-sized data buffer for * either input or output @@ -1099,43 +1879,44 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_bulk_transfer (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - gsize *actual_length, - guint timeout, - GCancellable *cancellable, - GError **error) -{ +g_usb_device_bulk_transfer(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); GUsbSyncHelper helper; helper.ret = -1; - helper.context = g_usb_context_get_main_context (device->priv->context); - helper.loop = g_main_loop_new (helper.context, FALSE); + helper.context = g_usb_context_get_main_context(priv->context); + helper.loop = g_main_loop_new(helper.context, FALSE); helper.error = error; helper.finish_func = g_usb_device_bulk_transfer_finish; - g_usb_device_bulk_transfer_async (device, - endpoint, - data, - length, - timeout, - cancellable, - (GAsyncReadyCallback) g_usb_device_sync_transfer_cb, - &helper); - g_main_loop_run (helper.loop); - g_main_loop_unref (helper.loop); + g_usb_device_bulk_transfer_async(self, + endpoint, + data, + length, + timeout, + cancellable, + (GAsyncReadyCallback)g_usb_device_sync_transfer_cb, + &helper); + g_main_loop_run(helper.loop); + g_main_loop_unref(helper.loop); if (actual_length != NULL) - *actual_length = (gsize) helper.ret; + *actual_length = (gsize)helper.ret; return helper.ret != -1; } /** * g_usb_device_interrupt_transfer: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @endpoint: the address of a valid endpoint to communicate with * @data: (array length=length): a suitably-sized data buffer for * either input or output @@ -1156,33 +1937,34 @@ * Since: 0.1.0 **/ gboolean -g_usb_device_interrupt_transfer (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - gsize *actual_length, - guint timeout, - GCancellable *cancellable, - GError **error) -{ +g_usb_device_interrupt_transfer(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); GUsbSyncHelper helper; helper.ret = -1; - helper.context = g_usb_context_get_main_context (device->priv->context); - helper.loop = g_main_loop_new (helper.context, FALSE); + helper.context = g_usb_context_get_main_context(priv->context); + helper.loop = g_main_loop_new(helper.context, FALSE); helper.error = error; helper.finish_func = g_usb_device_interrupt_transfer_finish; - g_usb_device_interrupt_transfer_async (device, - endpoint, - data, - length, - timeout, - cancellable, - (GAsyncReadyCallback) g_usb_device_sync_transfer_cb, - &helper); - g_main_loop_run (helper.loop); - g_main_loop_unref (helper.loop); + g_usb_device_interrupt_transfer_async(self, + endpoint, + data, + length, + timeout, + cancellable, + (GAsyncReadyCallback)g_usb_device_sync_transfer_cb, + &helper); + g_main_loop_run(helper.loop); + g_main_loop_unref(helper.loop); if (actual_length != NULL) *actual_length = helper.ret; @@ -1191,30 +1973,29 @@ } typedef struct { - GCancellable *cancellable; - gulong cancellable_id; - struct libusb_transfer *transfer; - guint8 *data; /* owned by the user */ - guint8 *data_raw; /* owned by the task */ + GCancellable *cancellable; + gulong cancellable_id; + struct libusb_transfer *transfer; + guint8 *data; /* owned by the user */ + guint8 *data_raw; /* owned by the task */ + GUsbDeviceEvent *event; /* no-ref */ } GcmDeviceReq; static void -g_usb_device_req_free (GcmDeviceReq *req) +g_usb_device_req_free(GcmDeviceReq *req) { - g_free (req->data_raw); + g_free(req->data_raw); if (req->cancellable_id > 0) { - g_cancellable_disconnect (req->cancellable, - req->cancellable_id); - g_object_unref (req->cancellable); + g_cancellable_disconnect(req->cancellable, req->cancellable_id); + g_object_unref(req->cancellable); } - libusb_free_transfer (req->transfer); - g_slice_free (GcmDeviceReq, req); + libusb_free_transfer(req->transfer); + g_slice_free(GcmDeviceReq, req); } static gboolean -g_usb_device_libusb_status_to_gerror (gint status, - GError **error) +g_usb_device_libusb_status_to_gerror(gint status, GError **error) { gboolean ret = FALSE; @@ -1223,101 +2004,140 @@ ret = TRUE; break; case LIBUSB_TRANSFER_ERROR: - g_set_error_literal (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_FAILED, - "transfer failed"); + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_FAILED, + "transfer failed"); break; case LIBUSB_TRANSFER_TIMED_OUT: - g_set_error_literal (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_TIMED_OUT, - "transfer timed out"); + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_TIMED_OUT, + "transfer timed out"); break; case LIBUSB_TRANSFER_CANCELLED: - g_set_error_literal (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_CANCELLED, - "transfer cancelled"); + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_CANCELLED, + "transfer cancelled"); break; case LIBUSB_TRANSFER_STALL: - g_set_error_literal (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_SUPPORTED, - "endpoint stalled or request not supported"); + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NOT_SUPPORTED, + "endpoint stalled or request not supported"); break; case LIBUSB_TRANSFER_NO_DEVICE: - g_set_error_literal (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NO_DEVICE, - "device was disconnected"); + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_NO_DEVICE, + "device was disconnected"); break; case LIBUSB_TRANSFER_OVERFLOW: - g_set_error_literal (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_INTERNAL, - "device sent more data than requested"); + g_set_error_literal(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_INTERNAL, + "device sent more data than requested"); break; default: - g_set_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_INTERNAL, - "unknown status %i", status); + g_set_error(error, + G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_INTERNAL, + "unknown status %i", + status); } return ret; } static void -g_usb_device_async_transfer_cb (struct libusb_transfer *transfer) +g_usb_device_async_transfer_cb(struct libusb_transfer *transfer) { GTask *task = transfer->user_data; + GcmDeviceReq *req = g_task_get_task_data(task); gboolean ret; GError *error = NULL; /* did request fail? */ - ret = g_usb_device_libusb_status_to_gerror (transfer->status, &error); + ret = g_usb_device_libusb_status_to_gerror(transfer->status, &error); if (!ret) { - g_task_return_error (task, error); + if (req->event != NULL) + _g_usb_device_event_set_status(req->event, transfer->status); + g_task_return_error(task, error); } else { - g_task_return_int (task, transfer->actual_length); + if (req->event != NULL) { + _g_usb_device_event_set_bytes_raw(req->event, + transfer->buffer, + (gsize)transfer->actual_length); + } + g_task_return_int(task, transfer->actual_length); } - g_object_unref (task); + g_object_unref(task); } static void -g_usb_device_cancelled_cb (GCancellable *cancellable, - GcmDeviceReq *req) +g_usb_device_cancelled_cb(GCancellable *cancellable, GcmDeviceReq *req) { - libusb_cancel_transfer (req->transfer); + libusb_cancel_transfer(req->transfer); } static void -g_usb_device_control_transfer_cb (struct libusb_transfer *transfer) +g_usb_device_control_transfer_cb(struct libusb_transfer *transfer) { GTask *task = transfer->user_data; - GcmDeviceReq *req = g_task_get_task_data (task); + GcmDeviceReq *req = g_task_get_task_data(task); gboolean ret; GError *error = NULL; /* did request fail? */ - ret = g_usb_device_libusb_status_to_gerror (transfer->status, - &error); + ret = g_usb_device_libusb_status_to_gerror(transfer->status, &error); if (!ret) { - g_task_return_error (task, error); + if (req->event != NULL) + _g_usb_device_event_set_status(req->event, transfer->status); + g_task_return_error(task, error); } else { - memmove (req->data, - transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, - (gsize) transfer->actual_length); - g_task_return_int (task, transfer->actual_length); + memmove(req->data, + transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, + (gsize)transfer->actual_length); + if (req->event != NULL) { + _g_usb_device_event_set_bytes_raw(req->event, + transfer->buffer + + LIBUSB_CONTROL_SETUP_SIZE, + (gsize)transfer->actual_length); + } + g_task_return_int(task, transfer->actual_length); } - g_object_unref (task); + g_object_unref(task); +} + +static gboolean +gusb_memcpy_bytes_safe(guint8 *dst, gsize dstsz, GBytes *bytes, GError **error) +{ + /* sanity check */ + if (dstsz < g_bytes_get_size(bytes)) { + g_set_error( + error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "cannot copy source buffer of size 0x%x into destination buffer of size 0x%x", + (guint)g_bytes_get_size(bytes), + (guint)dstsz); + return FALSE; + } + + /* data is the same */ + if (memcmp(dst, g_bytes_get_data(bytes, NULL), dstsz) == 0) + return TRUE; + + /* if this explodes it's because the caller has cast an immutable buffer to a guint8* */ + memcpy(dst, g_bytes_get_data(bytes, NULL), dstsz); + return TRUE; } /** * g_usb_device_control_transfer_async: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * @data: (array length=length): a suitably-sized data buffer for * either input or output * @length: the length field for the setup packet. @@ -1333,43 +2153,129 @@ * Since: 0.1.0 **/ void -g_usb_device_control_transfer_async (GUsbDevice *device, - GUsbDeviceDirection direction, - GUsbDeviceRequestType request_type, - GUsbDeviceRecipient recipient, - guint8 request, - guint16 value, - guint16 idx, - guint8 *data, - gsize length, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ +g_usb_device_control_transfer_async(GUsbDevice *self, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 idx, + guint8 *data, + gsize length, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); GTask *task; GcmDeviceReq *req; gint rc; guint8 request_type_raw = 0; GError *error = NULL; + GUsbDeviceEvent *event = NULL; + g_autofree gchar *event_id = NULL; + + g_return_if_fail(G_USB_IS_DEVICE(self)); + + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + g_autofree gchar *data_base64 = g_base64_encode(data, length); + event_id = g_strdup_printf("ControlTransfer:" + "Direction=0x%02x," + "RequestType=0x%02x," + "Recipient=0x%02x," + "Request=0x%02x," + "Value=0x%04x," + "Idx=0x%04x," + "Data=%s," + "Length=0x%x", + direction, + request_type, + recipient, + request, + value, + idx, + data_base64, + (guint)length); + } - g_return_if_fail (G_USB_IS_DEVICE (device)); + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) { + g_task_report_new_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event for %s", + event_id); + return; + } + if (!g_usb_device_libusb_error_to_gerror(self, + g_usb_device_event_get_rc(event), + &error) || + !g_usb_device_libusb_status_to_gerror(g_usb_device_event_get_status(event), + &error)) { + g_task_report_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + error); + return; + } + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL) { + g_task_report_new_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return; + } + if (!gusb_memcpy_bytes_safe(data, length, bytes, &error)) { + g_task_report_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + error); + return; + } + task = g_task_new(self, cancellable, callback, user_data); + g_task_return_int(task, g_bytes_get_size(bytes)); + g_object_unref(task); + return; + } - if (device->priv->handle == NULL) { - g_usb_device_async_not_open_error (device, callback, user_data, - g_usb_device_control_transfer_async); + if (priv->handle == NULL) { + g_usb_device_async_not_open_error(self, + callback, + user_data, + g_usb_device_control_transfer_async); return; } - req = g_slice_new0 (GcmDeviceReq); - req->transfer = libusb_alloc_transfer (0); + /* save */ + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) + event = g_usb_device_save_event(self, event_id); + + req = g_slice_new0(GcmDeviceReq); + req->transfer = libusb_alloc_transfer(0); req->data = data; + req->event = event; - task = g_task_new (device, cancellable, callback, user_data); - g_task_set_task_data (task, req, (GDestroyNotify)g_usb_device_req_free); + task = g_task_new(self, cancellable, callback, user_data); + g_task_set_task_data(task, req, (GDestroyNotify)g_usb_device_req_free); - if (g_task_return_error_if_cancelled (task)) { - g_object_unref (task); + if (g_task_return_error_if_cancelled(task)) { + g_object_unref(task); return; } @@ -1379,42 +2285,43 @@ request_type_raw |= (request_type << 5); request_type_raw |= recipient; - req->data_raw = g_malloc0 (length + LIBUSB_CONTROL_SETUP_SIZE); - memmove (req->data_raw + LIBUSB_CONTROL_SETUP_SIZE, data, length); + req->data_raw = g_malloc0(length + LIBUSB_CONTROL_SETUP_SIZE); + memmove(req->data_raw + LIBUSB_CONTROL_SETUP_SIZE, data, length); /* fill in setup packet */ - libusb_fill_control_setup (req->data_raw, request_type_raw, - request, value, idx, length); + libusb_fill_control_setup(req->data_raw, request_type_raw, request, value, idx, length); /* fill in transfer details */ - libusb_fill_control_transfer (req->transfer, - device->priv->handle, - req->data_raw, - g_usb_device_control_transfer_cb, - task, - timeout); + libusb_fill_control_transfer(req->transfer, + priv->handle, + req->data_raw, + g_usb_device_control_transfer_cb, + task, + timeout); /* submit transfer */ - rc = libusb_submit_transfer (req->transfer); + rc = libusb_submit_transfer(req->transfer); if (rc < 0) { - g_usb_device_libusb_error_to_gerror (device, rc, &error); - g_task_return_error (task, error); - g_object_unref (task); + if (event != NULL) + _g_usb_device_event_set_rc(event, rc); + g_usb_device_libusb_error_to_gerror(self, rc, &error); + g_task_return_error(task, error); + g_object_unref(task); } /* setup cancellation after submission */ if (cancellable != NULL) { - req->cancellable = g_object_ref (cancellable); - req->cancellable_id = g_cancellable_connect (req->cancellable, - G_CALLBACK (g_usb_device_cancelled_cb), - req, - NULL); + req->cancellable = g_object_ref(cancellable); + req->cancellable_id = g_cancellable_connect(req->cancellable, + G_CALLBACK(g_usb_device_cancelled_cb), + req, + NULL); } } /** * g_usb_device_control_transfer_finish: - * @device: a #GUsbDevice instance. + * @self: a #GUsbDevice instance. * @res: the #GAsyncResult * @error: A #GError or %NULL * @@ -1425,20 +2332,18 @@ * Since: 0.1.0 **/ gssize -g_usb_device_control_transfer_finish (GUsbDevice *device, - GAsyncResult *res, - GError **error) +g_usb_device_control_transfer_finish(GUsbDevice *self, GAsyncResult *res, GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), -1); - g_return_val_if_fail (g_task_is_valid (res, device), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); + g_return_val_if_fail(G_USB_IS_DEVICE(self), -1); + g_return_val_if_fail(g_task_is_valid(res, self), -1); + g_return_val_if_fail(error == NULL || *error == NULL, -1); - return g_task_propagate_int (G_TASK (res), error); + return g_task_propagate_int(G_TASK(res), error); } /** * g_usb_device_bulk_transfer_async: - * @device: a #GUsbDevice instance. + * @self: a #GUsbDevice instance. * @endpoint: the address of a valid endpoint to communicate with * @data: (array length=length): a suitably-sized data buffer for * either input or output @@ -1455,70 +2360,148 @@ * Since: 0.1.0 **/ void -g_usb_device_bulk_transfer_async (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ +g_usb_device_bulk_transfer_async(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); GTask *task; GcmDeviceReq *req; gint rc; GError *error = NULL; + GUsbDeviceEvent *event = NULL; + g_autofree gchar *event_id = NULL; + + g_return_if_fail(G_USB_IS_DEVICE(self)); + + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + g_autofree gchar *data_base64 = g_base64_encode(data, length); + event_id = g_strdup_printf("BulkTransfer:" + "Endpoint=0x%02x," + "Data=%s," + "Length=0x%x", + endpoint, + data_base64, + (guint)length); + } - g_return_if_fail (G_USB_IS_DEVICE (device)); + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) { + g_task_report_new_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event for %s", + event_id); + return; + } + if (!g_usb_device_libusb_error_to_gerror(self, + g_usb_device_event_get_rc(event), + &error) || + !g_usb_device_libusb_status_to_gerror(g_usb_device_event_get_status(event), + &error)) { + g_task_report_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + error); + return; + } + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL) { + g_task_report_new_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return; + } + if (!gusb_memcpy_bytes_safe(data, length, bytes, &error)) { + g_task_report_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + error); + return; + } + task = g_task_new(self, cancellable, callback, user_data); + g_task_return_int(task, g_bytes_get_size(bytes)); + g_object_unref(task); + return; + } - if (device->priv->handle == NULL) { - g_usb_device_async_not_open_error (device, callback, user_data, - g_usb_device_bulk_transfer_async); + if (priv->handle == NULL) { + g_usb_device_async_not_open_error(self, + callback, + user_data, + g_usb_device_bulk_transfer_async); return; } - req = g_slice_new0 (GcmDeviceReq); - req->transfer = libusb_alloc_transfer (0); + /* save */ + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) + event = g_usb_device_save_event(self, event_id); + + req = g_slice_new0(GcmDeviceReq); + req->transfer = libusb_alloc_transfer(0); + req->event = event; - task = g_task_new (device, cancellable, callback, user_data); - g_task_set_task_data (task, req, (GDestroyNotify)g_usb_device_req_free); + task = g_task_new(self, cancellable, callback, user_data); + g_task_set_task_data(task, req, (GDestroyNotify)g_usb_device_req_free); - if (g_task_return_error_if_cancelled (task)) { - g_object_unref (task); + if (g_task_return_error_if_cancelled(task)) { + g_object_unref(task); return; } /* fill in transfer details */ - libusb_fill_bulk_transfer (req->transfer, - device->priv->handle, - endpoint, - data, - length, - g_usb_device_async_transfer_cb, - task, - timeout); + libusb_fill_bulk_transfer(req->transfer, + priv->handle, + endpoint, + data, + length, + g_usb_device_async_transfer_cb, + task, + timeout); /* submit transfer */ - rc = libusb_submit_transfer (req->transfer); + rc = libusb_submit_transfer(req->transfer); if (rc < 0) { - g_usb_device_libusb_error_to_gerror (device, rc, &error); - g_task_return_error (task, error); - g_object_unref (task); + if (event != NULL) + _g_usb_device_event_set_rc(event, rc); + g_usb_device_libusb_error_to_gerror(self, rc, &error); + g_task_return_error(task, error); + g_object_unref(task); } /* setup cancellation after submission */ if (cancellable != NULL) { - req->cancellable = g_object_ref (cancellable); - req->cancellable_id = g_cancellable_connect (req->cancellable, - G_CALLBACK (g_usb_device_cancelled_cb), - req, - NULL); + req->cancellable = g_object_ref(cancellable); + req->cancellable_id = g_cancellable_connect(req->cancellable, + G_CALLBACK(g_usb_device_cancelled_cb), + req, + NULL); } } /** * g_usb_device_bulk_transfer_finish: - * @device: a #GUsbDevice instance. + * @self: a #GUsbDevice instance. * @res: the #GAsyncResult * @error: A #GError or %NULL * @@ -1529,20 +2512,18 @@ * Since: 0.1.0 **/ gssize -g_usb_device_bulk_transfer_finish (GUsbDevice *device, - GAsyncResult *res, - GError **error) +g_usb_device_bulk_transfer_finish(GUsbDevice *self, GAsyncResult *res, GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), -1); - g_return_val_if_fail (g_task_is_valid (res, device), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); + g_return_val_if_fail(G_USB_IS_DEVICE(self), -1); + g_return_val_if_fail(g_task_is_valid(res, self), -1); + g_return_val_if_fail(error == NULL || *error == NULL, -1); - return g_task_propagate_int (G_TASK (res), error); + return g_task_propagate_int(G_TASK(res), error); } /** * g_usb_device_interrupt_transfer_async: - * @device: a #GUsbDevice instance. + * @self: a #GUsbDevice instance. * @endpoint: the address of a valid endpoint to communicate with * @data: (array length=length): a suitably-sized data buffer for * either input or output @@ -1559,70 +2540,148 @@ * Since: 0.1.0 **/ void -g_usb_device_interrupt_transfer_async (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ +g_usb_device_interrupt_transfer_async(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GUsbDevicePrivate *priv = GET_PRIVATE(self); GTask *task; GcmDeviceReq *req; GError *error = NULL; gint rc; + GUsbDeviceEvent *event = NULL; + g_autofree gchar *event_id = NULL; + + g_return_if_fail(G_USB_IS_DEVICE(self)); + + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + g_autofree gchar *data_base64 = g_base64_encode(data, length); + event_id = g_strdup_printf("InterruptTransfer:" + "Endpoint=0x%02x," + "Data=%s," + "Length=0x%x", + endpoint, + data_base64, + (guint)length); + } - g_return_if_fail (G_USB_IS_DEVICE (device)); + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) { + g_task_report_new_error(self, + callback, + user_data, + g_usb_device_interrupt_transfer_async, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event for %s", + event_id); + return; + } + if (!g_usb_device_libusb_error_to_gerror(self, + g_usb_device_event_get_rc(event), + &error) || + !g_usb_device_libusb_status_to_gerror(g_usb_device_event_get_status(event), + &error)) { + g_task_report_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + error); + return; + } + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL) { + g_task_report_new_error(self, + callback, + user_data, + g_usb_device_interrupt_transfer_async, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no matching event data for %s", + event_id); + return; + } + if (!gusb_memcpy_bytes_safe(data, length, bytes, &error)) { + g_task_report_error(self, + callback, + user_data, + g_usb_device_control_transfer_async, + error); + return; + } + task = g_task_new(self, cancellable, callback, user_data); + g_task_return_int(task, g_bytes_get_size(bytes)); + g_object_unref(task); + return; + } - if (device->priv->handle == NULL) { - g_usb_device_async_not_open_error (device, callback, user_data, - g_usb_device_interrupt_transfer_async); + if (priv->handle == NULL) { + g_usb_device_async_not_open_error(self, + callback, + user_data, + g_usb_device_interrupt_transfer_async); return; } - req = g_slice_new0 (GcmDeviceReq); - req->transfer = libusb_alloc_transfer (0); + /* save */ + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) + event = g_usb_device_save_event(self, event_id); - task = g_task_new (device, cancellable, callback, user_data); - g_task_set_task_data (task, req, (GDestroyNotify)g_usb_device_req_free); + req = g_slice_new0(GcmDeviceReq); + req->transfer = libusb_alloc_transfer(0); + req->event = event; - if (g_task_return_error_if_cancelled (task)) { - g_object_unref (task); + task = g_task_new(self, cancellable, callback, user_data); + g_task_set_task_data(task, req, (GDestroyNotify)g_usb_device_req_free); + + if (g_task_return_error_if_cancelled(task)) { + g_object_unref(task); return; } /* fill in transfer details */ - libusb_fill_interrupt_transfer (req->transfer, - device->priv->handle, - endpoint, - data, - length, - g_usb_device_async_transfer_cb, - task, - timeout); + libusb_fill_interrupt_transfer(req->transfer, + priv->handle, + endpoint, + data, + length, + g_usb_device_async_transfer_cb, + task, + timeout); /* submit transfer */ - rc = libusb_submit_transfer (req->transfer); + rc = libusb_submit_transfer(req->transfer); if (rc < 0) { - g_usb_device_libusb_error_to_gerror (device, rc, &error); - g_task_return_error (task, error); - g_object_unref (task); + if (event != NULL) + _g_usb_device_event_set_rc(event, rc); + g_usb_device_libusb_error_to_gerror(self, rc, &error); + g_task_return_error(task, error); + g_object_unref(task); } /* setup cancellation after submission */ if (cancellable != NULL) { - req->cancellable = g_object_ref (cancellable); - req->cancellable_id = g_cancellable_connect (req->cancellable, - G_CALLBACK (g_usb_device_cancelled_cb), - req, - NULL); + req->cancellable = g_object_ref(cancellable); + req->cancellable_id = g_cancellable_connect(req->cancellable, + G_CALLBACK(g_usb_device_cancelled_cb), + req, + NULL); } } /** * g_usb_device_interrupt_transfer_finish: - * @device: a #GUsbDevice instance. + * @self: a #GUsbDevice instance. * @res: the #GAsyncResult * @error: A #GError or %NULL * @@ -1633,20 +2692,18 @@ * Since: 0.1.0 **/ gssize -g_usb_device_interrupt_transfer_finish (GUsbDevice *device, - GAsyncResult *res, - GError **error) +g_usb_device_interrupt_transfer_finish(GUsbDevice *self, GAsyncResult *res, GError **error) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), -1); - g_return_val_if_fail (g_task_is_valid (res, device), -1); - g_return_val_if_fail (error == NULL || *error == NULL, -1); + g_return_val_if_fail(G_USB_IS_DEVICE(self), -1); + g_return_val_if_fail(g_task_is_valid(res, self), -1); + g_return_val_if_fail(error == NULL || *error == NULL, -1); - return g_task_propagate_int (G_TASK (res), error); + return g_task_propagate_int(G_TASK(res), error); } /** * g_usb_device_get_platform_id: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the platform identifier for the device. * @@ -1658,16 +2715,16 @@ * Since: 0.1.1 **/ const gchar * -g_usb_device_get_platform_id (GUsbDevice *device) +g_usb_device_get_platform_id(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - - return device->priv->platform_id; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + return priv->platform_id; } /** * g_usb_device_get_parent: - * @device: a #GUsbDevice instance + * @self: a #GUsbDevice instance * * Gets the device parent if one exists. * @@ -1676,24 +2733,28 @@ * Since: 0.2.4 **/ GUsbDevice * -g_usb_device_get_parent (GUsbDevice *device) +g_usb_device_get_parent(GUsbDevice *self) { - GUsbDevicePrivate *priv = device->priv; + GUsbDevicePrivate *priv = GET_PRIVATE(self); libusb_device *parent; - parent = libusb_get_parent (priv->device); + /* sanity check */ + if (priv->device == NULL) + return NULL; + + parent = libusb_get_parent(priv->device); if (parent == NULL) return NULL; - return g_usb_context_find_by_bus_address (priv->context, - libusb_get_bus_number (parent), - libusb_get_device_address (parent), - NULL); + return g_usb_context_find_by_bus_address(priv->context, + libusb_get_bus_number(parent), + libusb_get_device_address(parent), + NULL); } /** * g_usb_device_get_children: - * @device: a #GUsbDevice instance + * @self: a #GUsbDevice instance * * Gets the device children if any exist. * @@ -1702,31 +2763,30 @@ * Since: 0.2.4 **/ GPtrArray * -g_usb_device_get_children (GUsbDevice *device) +g_usb_device_get_children(GUsbDevice *self) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); GPtrArray *children; - GUsbDevice *device_tmp; - GUsbDevicePrivate *priv = device->priv; - guint i; - GPtrArray *devices = NULL; - - /* find any devices that have @device as a parent */ - children = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); - devices = g_usb_context_get_devices (priv->context); - for (i = 0; i < devices->len; i++) { - device_tmp = g_ptr_array_index (devices, i); - if (priv->device == libusb_get_parent (device_tmp->priv->device)) - g_ptr_array_add (children, g_object_ref (device_tmp)); + g_autoptr(GPtrArray) devices = NULL; + + /* find any devices that have @self as a parent */ + children = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); + devices = g_usb_context_get_devices(priv->context); + for (guint i = 0; i < devices->len; i++) { + GUsbDevice *device_tmp = g_ptr_array_index(devices, i); + GUsbDevicePrivate *priv_tmp = GET_PRIVATE(device_tmp); + if (priv->device == NULL) + continue; + if (priv->device == libusb_get_parent(priv_tmp->device)) + g_ptr_array_add(children, g_object_ref(device_tmp)); } - g_ptr_array_unref (devices); - return children; } /** * g_usb_device_get_bus: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the USB bus number for the device. * @@ -1735,16 +2795,19 @@ * Since: 0.1.0 **/ guint8 -g_usb_device_get_bus (GUsbDevice *device) +g_usb_device_get_bus(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return libusb_get_bus_number (device->priv->device); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + /* sanity check */ + if (priv->device == NULL) + return 0x0; + return libusb_get_bus_number(priv->device); } /** * g_usb_device_get_address: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the USB address for the device. * @@ -1753,16 +2816,19 @@ * Since: 0.1.0 **/ guint8 -g_usb_device_get_address (GUsbDevice *device) +g_usb_device_get_address(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return libusb_get_device_address (device->priv->device); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + /* sanity check */ + if (priv->device == NULL) + return 0x0; + return libusb_get_device_address(priv->device); } /** * g_usb_device_get_port_number: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the USB port number for the device. * @@ -1771,15 +2837,19 @@ * Since: 0.2.4 **/ guint8 -g_usb_device_get_port_number (GUsbDevice *device) +g_usb_device_get_port_number(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - return libusb_get_port_number (device->priv->device); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + /* sanity check */ + if (priv->device == NULL) + return 0x0; + return libusb_get_port_number(priv->device); } /** * g_usb_device_get_vid: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the vendor ID for the device. * @@ -1788,16 +2858,16 @@ * Since: 0.1.0 **/ guint16 -g_usb_device_get_vid (GUsbDevice *device) +g_usb_device_get_vid(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.idVendor; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.idVendor; } /** * g_usb_device_get_pid: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the product ID for the device. * @@ -1806,16 +2876,16 @@ * Since: 0.1.0 **/ guint16 -g_usb_device_get_pid (GUsbDevice *device) +g_usb_device_get_pid(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.idProduct; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.idProduct; } /** * g_usb_device_get_release: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the BCD firmware version number for the device. * @@ -1824,16 +2894,16 @@ * Since: 0.2.8 **/ guint16 -g_usb_device_get_release (GUsbDevice *device) +g_usb_device_get_release(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.bcdDevice; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.bcdDevice; } /** * g_usb_device_get_spec: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the BCD specification revision for the device. For example, * `0x0110` indicates USB 1.1 and 0x0320 indicates USB 3.2 @@ -1843,16 +2913,16 @@ * Since: 0.3.1 **/ guint16 -g_usb_device_get_spec (GUsbDevice *device) +g_usb_device_get_spec(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.bcdUSB; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.bcdUSB; } /** * g_usb_device_get_vid_as_str: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the vendor ID for the device as a string. * @@ -1861,17 +2931,16 @@ * Since: 0.2.4 **/ const gchar * -g_usb_device_get_vid_as_str (GUsbDevice *device) +g_usb_device_get_vid_as_str(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - return _g_usb_context_lookup_vendor (device->priv->context, - device->priv->desc.idVendor, - NULL); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + return _g_usb_context_lookup_vendor(priv->context, priv->desc.idVendor, NULL); } /** * g_usb_device_get_pid_as_str: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the product ID for the device as a string. * @@ -1880,18 +2949,19 @@ * Since: 0.2.4 **/ const gchar * -g_usb_device_get_pid_as_str (GUsbDevice *device) +g_usb_device_get_pid_as_str(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL); - return _g_usb_context_lookup_product (device->priv->context, - device->priv->desc.idVendor, - device->priv->desc.idProduct, - NULL); + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), NULL); + return _g_usb_context_lookup_product(priv->context, + priv->desc.idVendor, + priv->desc.idProduct, + NULL); } /** * g_usb_device_get_configuration_index - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Get the index for the active Configuration string descriptor * ie, iConfiguration. @@ -1901,27 +2971,52 @@ * Since: 0.3.5 **/ guint8 -g_usb_device_get_configuration_index (GUsbDevice *device) +g_usb_device_get_configuration_index(GUsbDevice *self) { + GUsbDevicePrivate *priv = GET_PRIVATE(self); + GUsbDeviceEvent *event = NULL; struct libusb_config_descriptor *config; gint rc; guint8 index; + g_autofree gchar *event_id = NULL; + + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + + /* build event key either for load or save */ + if (priv->device == NULL || + g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) + event_id = g_strdup_printf("GetConfigurationIndex"); + + /* emulated */ + if (priv->device == NULL) { + GBytes *bytes; + event = g_usb_device_load_event(self, event_id); + if (event == NULL) + return 0x0; + bytes = g_usb_device_event_get_bytes(event); + if (bytes == NULL && g_bytes_get_size(bytes) != 1) + return 0x0; + return ((const guint8 *)g_bytes_get_data(bytes, NULL))0; + } - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - rc = libusb_get_active_config_descriptor (device->priv->device, &config); - g_return_val_if_fail (rc == 0, 0); + rc = libusb_get_active_config_descriptor(priv->device, &config); + g_return_val_if_fail(rc == 0, 0); index = config->iConfiguration; - libusb_free_config_descriptor (config); + /* save */ + if (g_usb_context_get_flags(priv->context) & G_USB_CONTEXT_FLAGS_SAVE_EVENTS) { + event = g_usb_device_save_event(self, event_id); + _g_usb_device_event_set_bytes_raw(event, &index, sizeof(index)); + } + + libusb_free_config_descriptor(config); return index; } - /** * g_usb_device_get_manufacturer_index: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the index for the Manufacturer string descriptor. * @@ -1930,16 +3025,16 @@ * Since: 0.1.0 **/ guint8 -g_usb_device_get_manufacturer_index (GUsbDevice *device) +g_usb_device_get_manufacturer_index(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.iManufacturer; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.iManufacturer; } /** * g_usb_device_get_device_class: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the device class, typically a #GUsbDeviceClassCode. * @@ -1948,16 +3043,16 @@ * Since: 0.1.7 **/ guint8 -g_usb_device_get_device_class (GUsbDevice *device) +g_usb_device_get_device_class(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.bDeviceClass; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.bDeviceClass; } /** * g_usb_device_get_device_subclass: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the device subclass qualified by the class number. * See g_usb_device_get_device_class(). @@ -1967,16 +3062,16 @@ * Since: 0.2.4 **/ guint8 -g_usb_device_get_device_subclass (GUsbDevice *device) +g_usb_device_get_device_subclass(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.bDeviceSubClass; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.bDeviceSubClass; } /** * g_usb_device_get_device_protocol: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the device protocol qualified by the class and subclass numbers. * See g_usb_device_get_device_class() and g_usb_device_get_device_subclass(). @@ -1986,16 +3081,16 @@ * Since: 0.2.4 **/ guint8 -g_usb_device_get_device_protocol (GUsbDevice *device) +g_usb_device_get_device_protocol(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.bDeviceProtocol; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.bDeviceProtocol; } /** * g_usb_device_get_product_index: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the index for the Product string descriptor. * @@ -2004,16 +3099,16 @@ * Since: 0.1.0 **/ guint8 -g_usb_device_get_product_index (GUsbDevice *device) +g_usb_device_get_product_index(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.iProduct; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.iProduct; } /** * g_usb_device_get_serial_number_index: - * @device: a #GUsbDevice + * @self: a #GUsbDevice * * Gets the index for the Serial Number string descriptor. * @@ -2022,9 +3117,9 @@ * Since: 0.1.0 **/ guint8 -g_usb_device_get_serial_number_index (GUsbDevice *device) +g_usb_device_get_serial_number_index(GUsbDevice *self) { - g_return_val_if_fail (G_USB_IS_DEVICE (device), 0); - - return device->priv->desc.iSerialNumber; + GUsbDevicePrivate *priv = GET_PRIVATE(self); + g_return_val_if_fail(G_USB_IS_DEVICE(self), 0); + return priv->desc.iSerialNumber; }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-device.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-device.h
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2010-2015 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * * SPDX-License-Identifier: LGPL-2.1+ @@ -8,22 +8,18 @@ #pragma once -#include <glib-object.h> #include <gio/gio.h> - -#include <gusb/gusb-util.h> +#include <gusb/gusb-bos-descriptor.h> #include <gusb/gusb-interface.h> +#include <gusb/gusb-util.h> +#include <json-glib/json-glib.h> G_BEGIN_DECLS -#define G_USB_TYPE_DEVICE (g_usb_device_get_type ()) -#define G_USB_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_USB_TYPE_DEVICE, GUsbDevice)) -#define G_USB_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_USB_TYPE_DEVICE)) -#define G_USB_DEVICE_ERROR (g_usb_device_error_quark ()) +#define G_USB_TYPE_DEVICE (g_usb_device_get_type()) +#define G_USB_DEVICE_ERROR (g_usb_device_error_quark()) -typedef struct _GUsbDevicePrivate GUsbDevicePrivate; -typedef struct _GUsbDevice GUsbDevice; -typedef struct _GUsbDeviceClass GUsbDeviceClass; +G_DECLARE_DERIVABLE_TYPE(GUsbDevice, g_usb_device, G_USB, DEVICE, GObject) /** * GUsbDeviceDirection: @@ -85,8 +81,8 @@ * g_usb_device_release_interface methods flags parameters. **/ typedef enum { - G_USB_DEVICE_CLAIM_INTERFACE_NONE = 0, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER = 1 << 0, + G_USB_DEVICE_CLAIM_INTERFACE_NONE = 0, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER = 1 << 0, } GUsbDeviceClaimInterfaceFlags; /** @@ -95,49 +91,41 @@ * The USB device class. **/ typedef enum { - G_USB_DEVICE_CLASS_INTERFACE_DESC = 0x00, - G_USB_DEVICE_CLASS_AUDIO = 0x01, - G_USB_DEVICE_CLASS_COMMUNICATIONS = 0x02, - G_USB_DEVICE_CLASS_HID = 0x03, - G_USB_DEVICE_CLASS_PHYSICAL = 0x05, - G_USB_DEVICE_CLASS_IMAGE = 0x06, - G_USB_DEVICE_CLASS_PRINTER = 0x07, - G_USB_DEVICE_CLASS_MASS_STORAGE = 0x08, - G_USB_DEVICE_CLASS_HUB = 0x09, - G_USB_DEVICE_CLASS_CDC_DATA = 0x0a, - G_USB_DEVICE_CLASS_SMART_CARD = 0x0b, - G_USB_DEVICE_CLASS_CONTENT_SECURITY = 0x0d, - G_USB_DEVICE_CLASS_VIDEO = 0x0e, - G_USB_DEVICE_CLASS_PERSONAL_HEALTHCARE = 0x0f, - G_USB_DEVICE_CLASS_AUDIO_VIDEO = 0x10, - G_USB_DEVICE_CLASS_BILLBOARD = 0x11, - G_USB_DEVICE_CLASS_DIAGNOSTIC = 0xdc, - G_USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xe0, - G_USB_DEVICE_CLASS_MISCELLANEOUS = 0xef, - G_USB_DEVICE_CLASS_APPLICATION_SPECIFIC = 0xfe, - G_USB_DEVICE_CLASS_VENDOR_SPECIFIC = 0xff + G_USB_DEVICE_CLASS_INTERFACE_DESC = 0x00, + G_USB_DEVICE_CLASS_AUDIO = 0x01, + G_USB_DEVICE_CLASS_COMMUNICATIONS = 0x02, + G_USB_DEVICE_CLASS_HID = 0x03, + G_USB_DEVICE_CLASS_PHYSICAL = 0x05, + G_USB_DEVICE_CLASS_IMAGE = 0x06, + G_USB_DEVICE_CLASS_PRINTER = 0x07, + G_USB_DEVICE_CLASS_MASS_STORAGE = 0x08, + G_USB_DEVICE_CLASS_HUB = 0x09, + G_USB_DEVICE_CLASS_CDC_DATA = 0x0a, + G_USB_DEVICE_CLASS_SMART_CARD = 0x0b, + G_USB_DEVICE_CLASS_CONTENT_SECURITY = 0x0d, + G_USB_DEVICE_CLASS_VIDEO = 0x0e, + G_USB_DEVICE_CLASS_PERSONAL_HEALTHCARE = 0x0f, + G_USB_DEVICE_CLASS_AUDIO_VIDEO = 0x10, + G_USB_DEVICE_CLASS_BILLBOARD = 0x11, + G_USB_DEVICE_CLASS_DIAGNOSTIC = 0xdc, + G_USB_DEVICE_CLASS_WIRELESS_CONTROLLER = 0xe0, + G_USB_DEVICE_CLASS_MISCELLANEOUS = 0xef, + G_USB_DEVICE_CLASS_APPLICATION_SPECIFIC = 0xfe, + G_USB_DEVICE_CLASS_VENDOR_SPECIFIC = 0xff } GUsbDeviceClassCode; - /** * GUsbDeviceLangid: * * The USB language ID. **/ typedef enum { - G_USB_DEVICE_LANGID_INVALID = 0x0000, - G_USB_DEVICE_LANGID_ENGLISH_UNITED_STATES = 0x0409, + G_USB_DEVICE_LANGID_INVALID = 0x0000, + G_USB_DEVICE_LANGID_ENGLISH_UNITED_STATES = 0x0409, } GUsbDeviceLangid; -struct _GUsbDevice -{ - GObject parent; - GUsbDevicePrivate *priv; -}; - -struct _GUsbDeviceClass -{ - GObjectClass parent_class; +struct _GUsbDeviceClass { + GObjectClass parent_class; /*< private >*/ /* * If adding fields to this struct, remove corresponding @@ -146,159 +134,208 @@ gchar _gusb_reserved64; }; -GType g_usb_device_get_type (void); -GQuark g_usb_device_error_quark (void); - -const gchar *g_usb_device_get_platform_id (GUsbDevice *device); -GUsbDevice *g_usb_device_get_parent (GUsbDevice *device); -GPtrArray *g_usb_device_get_children (GUsbDevice *device); - -guint8 g_usb_device_get_bus (GUsbDevice *device); -guint8 g_usb_device_get_address (GUsbDevice *device); -guint8 g_usb_device_get_port_number (GUsbDevice *device); - -guint16 g_usb_device_get_vid (GUsbDevice *device); -guint16 g_usb_device_get_pid (GUsbDevice *device); -guint16 g_usb_device_get_release (GUsbDevice *device); -guint16 g_usb_device_get_spec (GUsbDevice *device); -const gchar *g_usb_device_get_vid_as_str (GUsbDevice *device); -const gchar *g_usb_device_get_pid_as_str (GUsbDevice *device); -guint8 g_usb_device_get_device_class (GUsbDevice *device); -guint8 g_usb_device_get_device_subclass (GUsbDevice *device); -guint8 g_usb_device_get_device_protocol (GUsbDevice *device); - -guint8 g_usb_device_get_configuration_index (GUsbDevice *device); -guint8 g_usb_device_get_manufacturer_index (GUsbDevice *device); -guint8 g_usb_device_get_product_index (GUsbDevice *device); -guint8 g_usb_device_get_serial_number_index (GUsbDevice *device); -guint8 g_usb_device_get_custom_index (GUsbDevice *device, - guint8 class_id, - guint8 subclass_id, - guint8 protocol_id, - GError **error); - -GUsbInterface *g_usb_device_get_interface (GUsbDevice *device, - guint8 class_id, - guint8 subclass_id, - guint8 protocol_id, - GError **error); -GPtrArray *g_usb_device_get_interfaces (GUsbDevice *device, - GError **error); - -gboolean g_usb_device_open (GUsbDevice *device, - GError **error); -gboolean g_usb_device_close (GUsbDevice *device, - GError **error); - -gboolean g_usb_device_reset (GUsbDevice *device, - GError **error); - -gint g_usb_device_get_configuration (GUsbDevice *device, - GError **error); -gboolean g_usb_device_set_configuration (GUsbDevice *device, - gint configuration, - GError **error); - -gboolean g_usb_device_claim_interface (GUsbDevice *device, - gint interface, - GUsbDeviceClaimInterfaceFlags flags, - GError **error); -gboolean g_usb_device_release_interface (GUsbDevice *device, - gint interface, - GUsbDeviceClaimInterfaceFlags flags, - GError **error); -gboolean g_usb_device_set_interface_alt (GUsbDevice *device, - gint interface, - guint8 alt, - GError **error); - -gchar *g_usb_device_get_string_descriptor (GUsbDevice *device, - guint8 desc_index, - GError **error); -GBytes *g_usb_device_get_string_descriptor_bytes (GUsbDevice *device, - guint8 desc_index, - guint16 langid, - GError **error); -GBytes *g_usb_device_get_string_descriptor_bytes_full (GUsbDevice *device, - guint8 desc_index, - guint16 langid, - gsize length, - GError **error); +GQuark +g_usb_device_error_quark(void); + +const gchar * +g_usb_device_get_platform_id(GUsbDevice *self); +gboolean +g_usb_device_is_emulated(GUsbDevice *self); +GDateTime * +g_usb_device_get_created(GUsbDevice *self); +GUsbDevice * +g_usb_device_get_parent(GUsbDevice *self); +GPtrArray * +g_usb_device_get_children(GUsbDevice *self); + +guint8 +g_usb_device_get_bus(GUsbDevice *self); +guint8 +g_usb_device_get_address(GUsbDevice *self); +guint8 +g_usb_device_get_port_number(GUsbDevice *self); + +guint16 +g_usb_device_get_vid(GUsbDevice *self); +guint16 +g_usb_device_get_pid(GUsbDevice *self); +guint16 +g_usb_device_get_release(GUsbDevice *self); +guint16 +g_usb_device_get_spec(GUsbDevice *self); +const gchar * +g_usb_device_get_vid_as_str(GUsbDevice *self); +const gchar * +g_usb_device_get_pid_as_str(GUsbDevice *self); +guint8 +g_usb_device_get_device_class(GUsbDevice *self); +guint8 +g_usb_device_get_device_subclass(GUsbDevice *self); +guint8 +g_usb_device_get_device_protocol(GUsbDevice *self); + +void +g_usb_device_add_tag(GUsbDevice *self, const gchar *tag); +void +g_usb_device_remove_tag(GUsbDevice *self, const gchar *tag); +gboolean +g_usb_device_has_tag(GUsbDevice *self, const gchar *tag); +GPtrArray * +g_usb_device_get_tags(GUsbDevice *self); + +guint8 +g_usb_device_get_configuration_index(GUsbDevice *self); +guint8 +g_usb_device_get_manufacturer_index(GUsbDevice *self); +guint8 +g_usb_device_get_product_index(GUsbDevice *self); +guint8 +g_usb_device_get_serial_number_index(GUsbDevice *self); +guint8 +g_usb_device_get_custom_index(GUsbDevice *self, + guint8 class_id, + guint8 subclass_id, + guint8 protocol_id, + GError **error); + +GUsbInterface * +g_usb_device_get_interface(GUsbDevice *self, + guint8 class_id, + guint8 subclass_id, + guint8 protocol_id, + GError **error); +GPtrArray * +g_usb_device_get_interfaces(GUsbDevice *self, GError **error); + +GPtrArray * +g_usb_device_get_events(GUsbDevice *self); +void +g_usb_device_clear_events(GUsbDevice *self); + +GPtrArray * +g_usb_device_get_bos_descriptors(GUsbDevice *self, GError **error); +GUsbBosDescriptor * +g_usb_device_get_bos_descriptor(GUsbDevice *self, guint8 capability, GError **error); + +gboolean +g_usb_device_open(GUsbDevice *self, GError **error); +gboolean +g_usb_device_close(GUsbDevice *self, GError **error); + +gboolean +g_usb_device_reset(GUsbDevice *self, GError **error); +void +g_usb_device_invalidate(GUsbDevice *self); + +gint +g_usb_device_get_configuration(GUsbDevice *self, GError **error); +gboolean +g_usb_device_set_configuration(GUsbDevice *self, gint configuration, GError **error); + +gboolean +g_usb_device_claim_interface(GUsbDevice *self, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error); +gboolean +g_usb_device_release_interface(GUsbDevice *self, + gint interface, + GUsbDeviceClaimInterfaceFlags flags, + GError **error); +gboolean +g_usb_device_set_interface_alt(GUsbDevice *self, gint interface, guint8 alt, GError **error); + +gchar * +g_usb_device_get_string_descriptor(GUsbDevice *self, guint8 desc_index, GError **error); +GBytes * +g_usb_device_get_string_descriptor_bytes(GUsbDevice *self, + guint8 desc_index, + guint16 langid, + GError **error); +GBytes * +g_usb_device_get_string_descriptor_bytes_full(GUsbDevice *self, + guint8 desc_index, + guint16 langid, + gsize length, + GError **error); /* sync -- TODO: use GCancellable and GUsbSource */ -gboolean g_usb_device_control_transfer (GUsbDevice *device, - GUsbDeviceDirection direction, - GUsbDeviceRequestType request_type, - GUsbDeviceRecipient recipient, - guint8 request, - guint16 value, - guint16 idx, - guint8 *data, - gsize length, - gsize *actual_length, - guint timeout, - GCancellable *cancellable, - GError **error); - -gboolean g_usb_device_bulk_transfer (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - gsize *actual_length, - guint timeout, - GCancellable *cancellable, - GError **error); - -gboolean g_usb_device_interrupt_transfer (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - gsize *actual_length, - guint timeout, - GCancellable *cancellable, - GError **error); +gboolean +g_usb_device_control_transfer(GUsbDevice *self, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 idx, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error); + +gboolean +g_usb_device_bulk_transfer(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error); + +gboolean +g_usb_device_interrupt_transfer(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + gsize *actual_length, + guint timeout, + GCancellable *cancellable, + GError **error); /* async */ -void g_usb_device_control_transfer_async (GUsbDevice *device, - GUsbDeviceDirection direction, - GUsbDeviceRequestType request_type, - GUsbDeviceRecipient recipient, - guint8 request, - guint16 value, - guint16 idx, - guint8 *data, - gsize length, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gssize g_usb_device_control_transfer_finish (GUsbDevice *device, - GAsyncResult *res, - GError **error); - -void g_usb_device_bulk_transfer_async (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gssize g_usb_device_bulk_transfer_finish (GUsbDevice *device, - GAsyncResult *res, - GError **error); - -void g_usb_device_interrupt_transfer_async (GUsbDevice *device, - guint8 endpoint, - guint8 *data, - gsize length, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gssize g_usb_device_interrupt_transfer_finish (GUsbDevice *device, - GAsyncResult *res, - GError **error); +void +g_usb_device_control_transfer_async(GUsbDevice *self, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 idx, + guint8 *data, + gsize length, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gssize +g_usb_device_control_transfer_finish(GUsbDevice *self, GAsyncResult *res, GError **error); + +void +g_usb_device_bulk_transfer_async(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gssize +g_usb_device_bulk_transfer_finish(GUsbDevice *self, GAsyncResult *res, GError **error); + +void +g_usb_device_interrupt_transfer_async(GUsbDevice *self, + guint8 endpoint, + guint8 *data, + gsize length, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gssize +g_usb_device_interrupt_transfer_finish(GUsbDevice *self, GAsyncResult *res, GError **error); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-endpoint-private.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-endpoint-private.h
Changed
@@ -1,18 +1,25 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2020 Emmanuel Pacaud <emmanuel@gnome.org> + * Copyright (C) 2022 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -#include <libusb.h> - #include <gusb/gusb-endpoint.h> +#include <json-glib/json-glib.h> +#include <libusb.h> G_BEGIN_DECLS -GUsbEndpoint *_g_usb_endpoint_new (const struct libusb_endpoint_descriptor *endpoint); +GUsbEndpoint * +_g_usb_endpoint_new(const struct libusb_endpoint_descriptor *endpoint); + +gboolean +_g_usb_endpoint_load(GUsbEndpoint *self, JsonObject *json_object, GError **error); +gboolean +_g_usb_endpoint_save(GUsbEndpoint *self, JsonBuilder *json_builder, GError **error); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-endpoint.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-endpoint.c
Changed
@@ -19,40 +19,126 @@ #include <string.h> -#include "gusb-endpoint.h" #include "gusb-endpoint-private.h" +#include "gusb-json-common.h" -struct _GUsbEndpoint -{ +struct _GUsbEndpoint { GObject parent_instance; struct libusb_endpoint_descriptor endpoint_descriptor; GBytes *extra; }; -G_DEFINE_TYPE (GUsbEndpoint, g_usb_endpoint, G_TYPE_OBJECT) +G_DEFINE_TYPE(GUsbEndpoint, g_usb_endpoint, G_TYPE_OBJECT) static void -g_usb_endpoint_finalize (GObject *object) +g_usb_endpoint_finalize(GObject *object) { - GUsbEndpoint *endpoint = G_USB_ENDPOINT (object); + GUsbEndpoint *self = G_USB_ENDPOINT(object); - g_bytes_unref (endpoint->extra); + g_bytes_unref(self->extra); - G_OBJECT_CLASS (g_usb_endpoint_parent_class)->finalize (object); + G_OBJECT_CLASS(g_usb_endpoint_parent_class)->finalize(object); } static void -g_usb_endpoint_class_init (GUsbEndpointClass *klass) +g_usb_endpoint_class_init(GUsbEndpointClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = g_usb_endpoint_finalize; } static void -g_usb_endpoint_init (GUsbEndpoint *endpoint) +g_usb_endpoint_init(GUsbEndpoint *self) +{ +} + +gboolean +_g_usb_endpoint_load(GUsbEndpoint *self, JsonObject *json_object, GError **error) { + const gchar *str; + + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), FALSE); + g_return_val_if_fail(json_object != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* optional properties */ + self->endpoint_descriptor.bDescriptorType = + json_object_get_int_member_with_default(json_object, "DescriptorType", 0x0); + self->endpoint_descriptor.bEndpointAddress = + json_object_get_int_member_with_default(json_object, "EndpointAddress", 0x0); + self->endpoint_descriptor.bRefresh = + json_object_get_int_member_with_default(json_object, "Refresh", 0x0); + self->endpoint_descriptor.bInterval = + json_object_get_int_member_with_default(json_object, "Interval", 0x0); + self->endpoint_descriptor.bSynchAddress = + json_object_get_int_member_with_default(json_object, "SynchAddress", 0x0); + self->endpoint_descriptor.wMaxPacketSize = + json_object_get_int_member_with_default(json_object, "MaxPacketSize", 0x0); + + /* extra data */ + str = json_object_get_string_member_with_default(json_object, "ExtraData", NULL); + if (str != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = g_base64_decode(str, &bufsz); + if (self->extra != NULL) + g_bytes_unref(self->extra); + self->extra = g_bytes_new_take(g_steal_pointer(&buf), bufsz); + } + + /* success */ + return TRUE; +} + +gboolean +_g_usb_endpoint_save(GUsbEndpoint *self, JsonBuilder *json_builder, GError **error) +{ + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), FALSE); + g_return_val_if_fail(json_builder != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* start */ + json_builder_begin_object(json_builder); + + /* optional properties */ + if (self->endpoint_descriptor.bDescriptorType != 0) { + json_builder_set_member_name(json_builder, "DescriptorType"); + json_builder_add_int_value(json_builder, self->endpoint_descriptor.bDescriptorType); + } + if (self->endpoint_descriptor.bEndpointAddress != 0) { + json_builder_set_member_name(json_builder, "EndpointAddress"); + json_builder_add_int_value(json_builder, + self->endpoint_descriptor.bEndpointAddress); + } + if (self->endpoint_descriptor.bRefresh != 0) { + json_builder_set_member_name(json_builder, "Refresh"); + json_builder_add_int_value(json_builder, self->endpoint_descriptor.bRefresh); + } + if (self->endpoint_descriptor.bInterval != 0) { + json_builder_set_member_name(json_builder, "Interval"); + json_builder_add_int_value(json_builder, self->endpoint_descriptor.bInterval); + } + if (self->endpoint_descriptor.bSynchAddress != 0) { + json_builder_set_member_name(json_builder, "SynchAddress"); + json_builder_add_int_value(json_builder, self->endpoint_descriptor.bSynchAddress); + } + if (self->endpoint_descriptor.wMaxPacketSize != 0) { + json_builder_set_member_name(json_builder, "MaxPacketSize"); + json_builder_add_int_value(json_builder, self->endpoint_descriptor.wMaxPacketSize); + } + + /* extra data */ + if (self->extra != NULL && g_bytes_get_size(self->extra) > 0) { + g_autofree gchar *str = g_base64_encode(g_bytes_get_data(self->extra, NULL), + g_bytes_get_size(self->extra)); + json_builder_set_member_name(json_builder, "ExtraData"); + json_builder_add_string_value(json_builder, str); + } + + /* success */ + json_builder_end_object(json_builder); + return TRUE; } /** @@ -63,23 +149,23 @@ * Since: 0.3.3 **/ GUsbEndpoint * -_g_usb_endpoint_new (const struct libusb_endpoint_descriptor *endpoint_descriptor) +_g_usb_endpoint_new(const struct libusb_endpoint_descriptor *endpoint_descriptor) { - GUsbEndpoint *endpoint; - endpoint = g_object_new (G_USB_TYPE_ENDPOINT, NULL); + GUsbEndpoint *self; + self = g_object_new(G_USB_TYPE_ENDPOINT, NULL); /* copy the data */ - memcpy (&endpoint->endpoint_descriptor, - endpoint_descriptor, - sizeof (struct libusb_endpoint_descriptor)); - endpoint->extra = g_bytes_new (endpoint_descriptor->extra, endpoint_descriptor->extra_length); + memcpy(&self->endpoint_descriptor, + endpoint_descriptor, + sizeof(struct libusb_endpoint_descriptor)); + self->extra = g_bytes_new(endpoint_descriptor->extra, endpoint_descriptor->extra_length); - return G_USB_ENDPOINT (endpoint); + return G_USB_ENDPOINT(self); } /** * g_usb_endpoint_get_kind: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the type of endpoint. * @@ -88,15 +174,15 @@ * Since: 0.3.3 **/ guint8 -g_usb_endpoint_get_kind (GUsbEndpoint *endpoint) +g_usb_endpoint_get_kind(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return endpoint->endpoint_descriptor.bDescriptorType; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return self->endpoint_descriptor.bDescriptorType; } /** * g_usb_endpoint_get_maximum_packet_size: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the maximum packet size this endpoint is capable of sending/receiving. * @@ -105,15 +191,15 @@ * Since: 0.3.3 **/ guint16 -g_usb_endpoint_get_maximum_packet_size (GUsbEndpoint *endpoint) +g_usb_endpoint_get_maximum_packet_size(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return endpoint->endpoint_descriptor.wMaxPacketSize; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return self->endpoint_descriptor.wMaxPacketSize; } /** * g_usb_endpoint_get_polling_interval: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the endpoint polling interval. * @@ -122,15 +208,15 @@ * Since: 0.3.3 **/ guint8 -g_usb_endpoint_get_polling_interval (GUsbEndpoint *endpoint) +g_usb_endpoint_get_polling_interval(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return endpoint->endpoint_descriptor.bInterval; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return self->endpoint_descriptor.bInterval; } /** * g_usb_endpoint_get_refresh: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the rate at which synchronization feedback is provided, for audio device only. * @@ -139,15 +225,15 @@ * Since: 0.3.3 **/ guint8 -g_usb_endpoint_get_refresh (GUsbEndpoint *endpoint) +g_usb_endpoint_get_refresh(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return endpoint->endpoint_descriptor.bRefresh; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return self->endpoint_descriptor.bRefresh; } /** * g_usb_endpoint_get_synch_address: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the address if the synch endpoint, for audio device only. * @@ -156,15 +242,15 @@ * Since: 0.3.3 **/ guint8 -g_usb_endpoint_get_synch_address (GUsbEndpoint *endpoint) +g_usb_endpoint_get_synch_address(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return endpoint->endpoint_descriptor.bSynchAddress; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return self->endpoint_descriptor.bSynchAddress; } /** * g_usb_endpoint_get_address: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the address of the endpoint. * @@ -173,15 +259,15 @@ * Since: 0.3.3 **/ guint8 -g_usb_endpoint_get_address (GUsbEndpoint *endpoint) +g_usb_endpoint_get_address(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return endpoint->endpoint_descriptor.bEndpointAddress; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return self->endpoint_descriptor.bEndpointAddress; } /** * g_usb_endpoint_get_number: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the number part of endpoint address. * @@ -190,15 +276,15 @@ * Since: 0.3.3 **/ guint8 -g_usb_endpoint_get_number (GUsbEndpoint *endpoint) +g_usb_endpoint_get_number(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return (endpoint->endpoint_descriptor.bEndpointAddress) & 0xf; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return (self->endpoint_descriptor.bEndpointAddress) & 0xf; } /** * g_usb_endpoint_get_direction: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets the direction of the endpoint. * @@ -207,17 +293,17 @@ * Since: 0.3.3 **/ GUsbDeviceDirection -g_usb_endpoint_get_direction (GUsbEndpoint *endpoint) +g_usb_endpoint_get_direction(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), 0); - return (endpoint->endpoint_descriptor.bEndpointAddress & 0x80) ? - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST : - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); + return (self->endpoint_descriptor.bEndpointAddress & 0x80) + ? G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST + : G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE; } /** * g_usb_endpoint_get_extra: - * @endpoint: a #GUsbEndpoint + * @self: a #GUsbEndpoint * * Gets any extra data from the endpoint. * @@ -226,8 +312,8 @@ * Since: 0.3.3 **/ GBytes * -g_usb_endpoint_get_extra (GUsbEndpoint *endpoint) +g_usb_endpoint_get_extra(GUsbEndpoint *self) { - g_return_val_if_fail (G_USB_IS_ENDPOINT (endpoint), NULL); - return endpoint->extra; + g_return_val_if_fail(G_USB_IS_ENDPOINT(self), NULL); + return self->extra; }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-endpoint.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-endpoint.h
Changed
@@ -7,23 +7,30 @@ #pragma once -#include <glib-object.h> -#include <gio/gio.h> #include <gusb/gusb-device.h> G_BEGIN_DECLS -#define G_USB_TYPE_ENDPOINT (g_usb_endpoint_get_type ()) -G_DECLARE_FINAL_TYPE (GUsbEndpoint, g_usb_endpoint, G_USB, ENDPOINT, GObject) +#define G_USB_TYPE_ENDPOINT (g_usb_endpoint_get_type()) +G_DECLARE_FINAL_TYPE(GUsbEndpoint, g_usb_endpoint, G_USB, ENDPOINT, GObject) -guint8 g_usb_endpoint_get_kind (GUsbEndpoint *endpoint); -guint16 g_usb_endpoint_get_maximum_packet_size (GUsbEndpoint *endpoint); -guint8 g_usb_endpoint_get_polling_interval (GUsbEndpoint *endpoint); -guint8 g_usb_endpoint_get_refresh (GUsbEndpoint *endpoint); -guint8 g_usb_endpoint_get_synch_address (GUsbEndpoint *endpoint); -guint8 g_usb_endpoint_get_address (GUsbEndpoint *endpoint); -guint8 g_usb_endpoint_get_number (GUsbEndpoint *endpoint); -GUsbDeviceDirection g_usb_endpoint_get_direction (GUsbEndpoint *endpoint); -GBytes * g_usb_endpoint_get_extra (GUsbEndpoint *endpoint); +guint8 +g_usb_endpoint_get_kind(GUsbEndpoint *self); +guint16 +g_usb_endpoint_get_maximum_packet_size(GUsbEndpoint *self); +guint8 +g_usb_endpoint_get_polling_interval(GUsbEndpoint *self); +guint8 +g_usb_endpoint_get_refresh(GUsbEndpoint *self); +guint8 +g_usb_endpoint_get_synch_address(GUsbEndpoint *self); +guint8 +g_usb_endpoint_get_address(GUsbEndpoint *self); +guint8 +g_usb_endpoint_get_number(GUsbEndpoint *self); +GUsbDeviceDirection +g_usb_endpoint_get_direction(GUsbEndpoint *self); +GBytes * +g_usb_endpoint_get_extra(GUsbEndpoint *self); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-interface-private.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-interface-private.h
Changed
@@ -7,12 +7,18 @@ #pragma once -#include <libusb.h> - #include <gusb/gusb-interface.h> +#include <json-glib/json-glib.h> +#include <libusb.h> G_BEGIN_DECLS -GUsbInterface *_g_usb_interface_new (const struct libusb_interface_descriptor *iface); +GUsbInterface * +_g_usb_interface_new(const struct libusb_interface_descriptor *iface); + +gboolean +_g_usb_interface_load(GUsbInterface *self, JsonObject *json_object, GError **error); +gboolean +_g_usb_interface_save(GUsbInterface *self, JsonBuilder *json_builder, GError **error); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-interface.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-interface.c
Changed
@@ -20,12 +20,11 @@ #include <string.h> -#include "gusb-interface.h" -#include "gusb-interface-private.h" #include "gusb-endpoint-private.h" +#include "gusb-interface-private.h" +#include "gusb-json-common.h" -struct _GUsbInterface -{ +struct _GUsbInterface { GObject parent_instance; struct libusb_interface_descriptor iface; @@ -34,30 +33,155 @@ GPtrArray *endpoints; }; -G_DEFINE_TYPE (GUsbInterface, g_usb_interface, G_TYPE_OBJECT) +G_DEFINE_TYPE(GUsbInterface, g_usb_interface, G_TYPE_OBJECT) static void -g_usb_interface_finalize (GObject *object) +g_usb_interface_finalize(GObject *object) { - GUsbInterface *interface = G_USB_INTERFACE (object); + GUsbInterface *self = G_USB_INTERFACE(object); - g_bytes_unref (interface->extra); - g_ptr_array_unref (interface->endpoints); + if (self->extra != NULL) + g_bytes_unref(self->extra); + if (self->endpoints != NULL) + g_ptr_array_unref(self->endpoints); - G_OBJECT_CLASS (g_usb_interface_parent_class)->finalize (object); + G_OBJECT_CLASS(g_usb_interface_parent_class)->finalize(object); } static void -g_usb_interface_class_init (GUsbInterfaceClass *klass) +g_usb_interface_class_init(GUsbInterfaceClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = g_usb_interface_finalize; } static void -g_usb_interface_init (GUsbInterface *interface) +g_usb_interface_init(GUsbInterface *self) +{ +} + +gboolean +_g_usb_interface_load(GUsbInterface *self, JsonObject *json_object, GError **error) { + const gchar *str; + + g_return_val_if_fail(G_USB_IS_INTERFACE(self), FALSE); + g_return_val_if_fail(json_object != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, -1); + + /* optional properties */ + self->iface.bLength = json_object_get_int_member_with_default(json_object, "Length", 0x0); + self->iface.bDescriptorType = + json_object_get_int_member_with_default(json_object, "DescriptorType", 0x0); + self->iface.bInterfaceNumber = + json_object_get_int_member_with_default(json_object, "InterfaceNumber", 0x0); + self->iface.bAlternateSetting = + json_object_get_int_member_with_default(json_object, "AlternateSetting", 0x0); + self->iface.bInterfaceClass = + json_object_get_int_member_with_default(json_object, "InterfaceClass", 0x0); + self->iface.bInterfaceSubClass = + json_object_get_int_member_with_default(json_object, "InterfaceSubClass", 0x0); + self->iface.bInterfaceProtocol = + json_object_get_int_member_with_default(json_object, "InterfaceProtocol", 0x0); + self->iface.iInterface = + json_object_get_int_member_with_default(json_object, "Interface", 0x0); + + /* array of endpoints */ + if (json_object_has_member(json_object, "UsbEndpoints")) { + JsonArray *json_array = json_object_get_array_member(json_object, "UsbEndpoints"); + self->endpoints = g_ptr_array_new_with_free_func(g_object_unref); + for (guint i = 0; i < json_array_get_length(json_array); i++) { + JsonNode *node_tmp = json_array_get_element(json_array, i); + JsonObject *obj_tmp = json_node_get_object(node_tmp); + g_autoptr(GUsbEndpoint) endpoint = g_object_new(G_USB_TYPE_ENDPOINT, NULL); + if (!_g_usb_endpoint_load(endpoint, obj_tmp, error)) + return FALSE; + g_ptr_array_add(self->endpoints, g_object_ref(endpoint)); + } + } + + /* extra data */ + str = json_object_get_string_member_with_default(json_object, "ExtraData", NULL); + if (str != NULL) { + gsize bufsz = 0; + g_autofree guchar *buf = g_base64_decode(str, &bufsz); + if (self->extra != NULL) + g_bytes_unref(self->extra); + self->extra = g_bytes_new_take(g_steal_pointer(&buf), bufsz); + } + + /* success */ + return TRUE; +} + +gboolean +_g_usb_interface_save(GUsbInterface *self, JsonBuilder *json_builder, GError **error) +{ + g_return_val_if_fail(G_USB_IS_INTERFACE(self), FALSE); + g_return_val_if_fail(json_builder != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); + + /* start */ + json_builder_begin_object(json_builder); + + /* optional properties */ + if (self->iface.bLength != 0) { + json_builder_set_member_name(json_builder, "Length"); + json_builder_add_int_value(json_builder, self->iface.bLength); + } + if (self->iface.bDescriptorType != 0) { + json_builder_set_member_name(json_builder, "DescriptorType"); + json_builder_add_int_value(json_builder, self->iface.bDescriptorType); + } + if (self->iface.bInterfaceNumber != 0) { + json_builder_set_member_name(json_builder, "InterfaceNumber"); + json_builder_add_int_value(json_builder, self->iface.bInterfaceNumber); + } + if (self->iface.bAlternateSetting != 0) { + json_builder_set_member_name(json_builder, "AlternateSetting"); + json_builder_add_int_value(json_builder, self->iface.bAlternateSetting); + } + if (self->iface.bInterfaceClass != 0) { + json_builder_set_member_name(json_builder, "InterfaceClass"); + json_builder_add_int_value(json_builder, self->iface.bInterfaceClass); + } + if (self->iface.bInterfaceSubClass != 0) { + json_builder_set_member_name(json_builder, "InterfaceSubClass"); + json_builder_add_int_value(json_builder, self->iface.bInterfaceSubClass); + } + if (self->iface.bInterfaceProtocol != 0) { + json_builder_set_member_name(json_builder, "InterfaceProtocol"); + json_builder_add_int_value(json_builder, self->iface.bInterfaceProtocol); + } + if (self->iface.iInterface != 0) { + json_builder_set_member_name(json_builder, "Interface"); + json_builder_add_int_value(json_builder, self->iface.iInterface); + } + + /* array of endpoints */ + if (self->endpoints != NULL && self->endpoints->len > 0) { + json_builder_set_member_name(json_builder, "UsbEndpoints"); + json_builder_begin_array(json_builder); + for (guint i = 0; i < self->endpoints->len; i++) { + GUsbEndpoint *endpoint = g_ptr_array_index(self->endpoints, i); + if (!_g_usb_endpoint_save(endpoint, json_builder, error)) + return FALSE; + } + json_builder_end_array(json_builder); + } + + /* extra data */ + if (self->extra != NULL && g_bytes_get_size(self->extra) > 0) { + g_autofree gchar *str = g_base64_encode(g_bytes_get_data(self->extra, NULL), + g_bytes_get_size(self->extra)); + json_builder_set_member_name(json_builder, "ExtraData"); + json_builder_add_string_value(json_builder, str); + } + + /* success */ + json_builder_end_object(json_builder); + return TRUE; } /** @@ -68,27 +192,25 @@ * Since: 0.2.8 **/ GUsbInterface * -_g_usb_interface_new (const struct libusb_interface_descriptor *iface) +_g_usb_interface_new(const struct libusb_interface_descriptor *iface) { - GUsbInterface *interface; - interface = g_object_new (G_USB_TYPE_INTERFACE, NULL); + GUsbInterface *self; + self = g_object_new(G_USB_TYPE_INTERFACE, NULL); /* copy the data */ - memcpy (&interface->iface, - iface, - sizeof (struct libusb_interface_descriptor)); - interface->extra = g_bytes_new (iface->extra, iface->extra_length); + memcpy(&self->iface, iface, sizeof(struct libusb_interface_descriptor)); + self->extra = g_bytes_new(iface->extra, iface->extra_length); - interface->endpoints = g_ptr_array_new_with_free_func (g_object_unref); + self->endpoints = g_ptr_array_new_with_free_func(g_object_unref); for (guint i = 0; i < iface->bNumEndpoints; i++) - g_ptr_array_add (interface->endpoints, _g_usb_endpoint_new (&iface->endpointi)); + g_ptr_array_add(self->endpoints, _g_usb_endpoint_new(&iface->endpointi)); - return G_USB_INTERFACE (interface); + return G_USB_INTERFACE(self); } /** * g_usb_interface_get_length: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the USB bus number for the interface. * @@ -97,15 +219,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_length (GUsbInterface *interface) +g_usb_interface_get_length(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bLength; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bLength; } /** * g_usb_interface_get_kind: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the type of interface. * @@ -114,15 +236,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_kind (GUsbInterface *interface) +g_usb_interface_get_kind(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bDescriptorType; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bDescriptorType; } /** * g_usb_interface_get_number: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the interface number. * @@ -131,15 +253,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_number (GUsbInterface *interface) +g_usb_interface_get_number(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bInterfaceNumber; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bInterfaceNumber; } /** * g_usb_interface_get_alternate: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the alternate setting for the interface. * @@ -148,15 +270,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_alternate (GUsbInterface *interface) +g_usb_interface_get_alternate(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bAlternateSetting; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bAlternateSetting; } /** * g_usb_interface_get_class: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the interface class, typically a #GUsbInterfaceClassCode. * @@ -165,15 +287,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_class (GUsbInterface *interface) +g_usb_interface_get_class(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bInterfaceClass; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bInterfaceClass; } /** * g_usb_interface_get_subclass: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the interface subclass qualified by the class number. * See g_usb_interface_get_class(). @@ -183,15 +305,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_subclass (GUsbInterface *interface) +g_usb_interface_get_subclass(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bInterfaceSubClass; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bInterfaceSubClass; } /** * g_usb_interface_get_protocol: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the interface protocol qualified by the class and subclass numbers. * See g_usb_interface_get_class() and g_usb_interface_get_subclass(). @@ -201,15 +323,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_protocol (GUsbInterface *interface) +g_usb_interface_get_protocol(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.bInterfaceProtocol; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.bInterfaceProtocol; } /** * g_usb_interface_get_index: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets the index for the string descriptor. * @@ -218,15 +340,15 @@ * Since: 0.2.8 **/ guint8 -g_usb_interface_get_index (GUsbInterface *interface) +g_usb_interface_get_index(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), 0); - return interface->iface.iInterface; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), 0); + return self->iface.iInterface; } /** * g_usb_interface_get_extra: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets any extra data from the interface. * @@ -235,25 +357,28 @@ * Since: 0.2.8 **/ GBytes * -g_usb_interface_get_extra (GUsbInterface *interface) +g_usb_interface_get_extra(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), NULL); - return interface->extra; + g_return_val_if_fail(G_USB_IS_INTERFACE(self), NULL); + return self->extra; } /** * g_usb_interface_get_endpoints: - * @interface: a #GUsbInterface + * @self: a #GUsbInterface * * Gets interface endpoints. * - * Return value: (transfer container) (element-type GUsbEndpoint): an array of endpoints, or %NULL on failure + * Return value: (transfer container) (element-type GUsbEndpoint): an array of endpoints, + * or %NULL on failure. * * Since: 0.3.3 **/ GPtrArray * -g_usb_interface_get_endpoints (GUsbInterface *interface) +g_usb_interface_get_endpoints(GUsbInterface *self) { - g_return_val_if_fail (G_USB_IS_INTERFACE (interface), NULL); - return g_ptr_array_ref (interface->endpoints); + g_return_val_if_fail(G_USB_IS_INTERFACE(self), NULL); + if (self->endpoints == NULL) + return NULL; + return g_ptr_array_ref(self->endpoints); }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-interface.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-interface.h
Changed
@@ -9,22 +9,31 @@ #pragma once #include <glib-object.h> -#include <gio/gio.h> G_BEGIN_DECLS -#define G_USB_TYPE_INTERFACE (g_usb_interface_get_type ()) -G_DECLARE_FINAL_TYPE (GUsbInterface, g_usb_interface, G_USB, INTERFACE, GObject) +#define G_USB_TYPE_INTERFACE (g_usb_interface_get_type()) +G_DECLARE_FINAL_TYPE(GUsbInterface, g_usb_interface, G_USB, INTERFACE, GObject) -guint8 g_usb_interface_get_length (GUsbInterface *interface); -guint8 g_usb_interface_get_kind (GUsbInterface *interface); -guint8 g_usb_interface_get_number (GUsbInterface *interface); -guint8 g_usb_interface_get_alternate (GUsbInterface *interface); -guint8 g_usb_interface_get_class (GUsbInterface *interface); -guint8 g_usb_interface_get_subclass (GUsbInterface *interface); -guint8 g_usb_interface_get_protocol (GUsbInterface *interface); -guint8 g_usb_interface_get_index (GUsbInterface *interface); -GBytes *g_usb_interface_get_extra (GUsbInterface *interface); -GPtrArray *g_usb_interface_get_endpoints (GUsbInterface *interface); +guint8 +g_usb_interface_get_length(GUsbInterface *self); +guint8 +g_usb_interface_get_kind(GUsbInterface *self); +guint8 +g_usb_interface_get_number(GUsbInterface *self); +guint8 +g_usb_interface_get_alternate(GUsbInterface *self); +guint8 +g_usb_interface_get_class(GUsbInterface *self); +guint8 +g_usb_interface_get_subclass(GUsbInterface *self); +guint8 +g_usb_interface_get_protocol(GUsbInterface *self); +guint8 +g_usb_interface_get_index(GUsbInterface *self); +GBytes * +g_usb_interface_get_extra(GUsbInterface *self); +GPtrArray * +g_usb_interface_get_endpoints(GUsbInterface *self); G_END_DECLS
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-json-common.c
Added
@@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2023 Collabora Ltd. + * @author Frédéric Danis <frederic.danis@collabora.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "gusb-json-common.h" + +#if !JSON_CHECK_VERSION(1, 6, 0) +const char * +json_object_get_string_member_with_default(JsonObject *json_object, + const char *member_name, + const char *default_value) +{ + if (!json_object_has_member(json_object, member_name)) + return default_value; + return json_object_get_string_member(json_object, member_name); +} + +gint64 +json_object_get_int_member_with_default(JsonObject *json_object, + const char *member_name, + gint64 default_value) +{ + if (!json_object_has_member(json_object, member_name)) + return default_value; + return json_object_get_int_member(json_object, member_name); +} +#endif
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-json-common.h
Added
@@ -0,0 +1,27 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2023 Collabora Ltd. + * @author Frédéric Danis <frederic.danis@collabora.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include <glib.h> +#include <json-glib/json-glib.h> + +G_BEGIN_DECLS + +#if !JSON_CHECK_VERSION(1, 6, 0) +const char * +json_object_get_string_member_with_default(JsonObject *json_object, + const char *member_name, + const char *default_value); +gint64 +json_object_get_int_member_with_default(JsonObject *json_object, + const char *member_name, + gint64 default_value); +#endif + +G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-private.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-private.h
Changed
@@ -9,8 +9,8 @@ #define __GUSB_INSIDE__ -#include <gusb/gusb.h> #include <gusb/gusb-context-private.h> #include <gusb/gusb-device-private.h> +#include <gusb/gusb.h> #undef __GUSB_INSIDE__
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-self-test.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-self-test.c
Changed
@@ -7,535 +7,706 @@ #include "config.h" -#include <glib-object.h> - -#include "gusb-context.h" #include "gusb-context-private.h" -#include "gusb-device.h" static void -gusb_device_func (void) +gusb_device_func(void) { - GError *error = NULL; - GPtrArray *array; - GUsbContext *ctx; GUsbDevice *device; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) array = NULL; + g_autoptr(GUsbContext) ctx = NULL; #ifdef __FreeBSD__ - g_test_skip ("Root hubs on FreeBSD have vid and pid set to zero"); + g_test_skip("Root hubs on FreeBSD have vid and pid set to zero"); return; #endif - ctx = g_usb_context_new (&error); - g_assert_no_error (error); - g_assert (ctx != NULL); + ctx = g_usb_context_new(&error); + g_assert_no_error(error); + g_assert(ctx != NULL); - g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); + g_usb_context_set_debug(ctx, G_LOG_LEVEL_ERROR); - array = g_usb_context_get_devices (ctx); - g_assert (array != NULL); - g_assert_cmpint (array->len, >, 0); - device = G_USB_DEVICE (g_ptr_array_index (array, 0)); + array = g_usb_context_get_devices(ctx); + g_assert(array != NULL); + g_assert_cmpint(array->len, >, 0); + device = G_USB_DEVICE(g_ptr_array_index(array, 0)); - g_assert_cmpint (g_usb_device_get_vid (device), >, 0x0000); - g_assert_cmpint (g_usb_device_get_pid (device), >, 0x0000); + g_assert_cmpint(g_usb_device_get_vid(device), >, 0x0000); + g_assert_cmpint(g_usb_device_get_pid(device), >, 0x0000); - g_ptr_array_unref (array); + g_assert_false(g_usb_device_has_tag(device, "foobar")); + g_usb_device_add_tag(device, "foobar"); + g_usb_device_add_tag(device, "foobar"); + g_assert_true(g_usb_device_has_tag(device, "foobar")); + g_usb_device_remove_tag(device, "foobar"); + g_assert_false(g_usb_device_has_tag(device, "foobar")); } static void -gusb_context_lookup_func (void) +gusb_context_lookup_func(void) { - GUsbContext *ctx = NULL; GError *error = NULL; const gchar *tmp; - - ctx = g_usb_context_new (&error); - g_assert_no_error (error); - g_assert (ctx != NULL); - - tmp = _g_usb_context_lookup_vendor (ctx, 0x04d8, &error); - g_assert_no_error (error); - g_assert_cmpstr (tmp, ==, "Microchip Technology, Inc."); - tmp = _g_usb_context_lookup_product (ctx, 0x04d8, 0xf8da, &error); - g_assert_no_error (error); - g_assert_cmpstr (tmp, ==, "Hughski Ltd. ColorHug"); - g_object_unref (ctx); + g_autoptr(GUsbContext) ctx = NULL; + + ctx = g_usb_context_new(&error); + g_assert_no_error(error); + g_assert(ctx != NULL); + + tmp = _g_usb_context_lookup_vendor(ctx, 0x04d8, &error); + g_assert_no_error(error); + g_assert_cmpstr(tmp, ==, "Microchip Technology, Inc."); + tmp = _g_usb_context_lookup_product(ctx, 0x04d8, 0xf8da, &error); + g_assert_no_error(error); + g_assert_cmpstr(tmp, ==, "Hughski Ltd. ColorHug"); } static void -gusb_context_func (void) +gusb_context_func(void) { - GUsbContext *ctx; - GError *error = NULL; GPtrArray *array; guint old_number_of_devices; guint8 bus, address; GUsbDevice *device; - gchar *manufacturer; - gchar *product; - guint i; + g_autoptr(GError) error = NULL; + g_autoptr(GUsbContext) ctx = NULL; #ifdef __FreeBSD__ - g_test_skip ("Root hubs on FreeBSD have vid and pid set to zero"); + g_test_skip("Root hubs on FreeBSD have vid and pid set to zero"); return; #endif - ctx = g_usb_context_new (&error); - g_assert_no_error (error); - g_assert (ctx != NULL); + ctx = g_usb_context_new(&error); + g_assert_no_error(error); + g_assert(ctx != NULL); - g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); + g_usb_context_set_debug(ctx, G_LOG_LEVEL_ERROR); /* coldplug, and ensure we got some devices */ - array = g_usb_context_get_devices (ctx); - g_assert (array != NULL); - g_assert_cmpint (array->len, >, 0); + array = g_usb_context_get_devices(ctx); + g_assert(array != NULL); + g_assert_cmpint(array->len, >, 0); old_number_of_devices = array->len; /* Print a list (also exercising various bits of g_usb_device) */ - g_print ("\n"); - for (i = 0; i < array->len; i++) { - device = G_USB_DEVICE (g_ptr_array_index (array, i)); + g_print("\n"); + for (guint i = 0; i < array->len; i++) { + g_autofree gchar *manufacturer = NULL; + g_autofree gchar *product = NULL; + + device = G_USB_DEVICE(g_ptr_array_index(array, i)); - g_assert_cmpint (g_usb_device_get_vid (device), >, 0x0000); - g_assert_cmpint (g_usb_device_get_pid (device), >, 0x0000); + g_assert_cmpint(g_usb_device_get_vid(device), >, 0x0000); + g_assert_cmpint(g_usb_device_get_pid(device), >, 0x0000); /* Needed for g_usb_device_get_string_descriptor below, not error checked to allow running basic tests without needing r/w rights on /dev/bus/usb nodes */ - g_usb_context_set_debug (ctx, 0); - g_usb_device_open (device, NULL); - g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); + g_usb_context_set_debug(ctx, 0); + g_usb_device_open(device, NULL); + g_usb_context_set_debug(ctx, G_LOG_LEVEL_ERROR); /* We don't error check these as not all devices have these (and the device_open may have failed). */ - manufacturer = g_usb_device_get_string_descriptor (device, - g_usb_device_get_manufacturer_index (device), - NULL); - product = g_usb_device_get_string_descriptor (device, - g_usb_device_get_product_index (device), - NULL); - - g_usb_device_close (device, NULL); - - g_print ("Found %04x:%04x, %s %s\n", - g_usb_device_get_vid (device), - g_usb_device_get_pid (device), - manufacturer ? manufacturer : "", - product ? product : ""); - - g_free (manufacturer); - g_free (product); + manufacturer = + g_usb_device_get_string_descriptor(device, + g_usb_device_get_manufacturer_index(device), + NULL); + product = g_usb_device_get_string_descriptor(device, + g_usb_device_get_product_index(device), + NULL); + + g_usb_device_close(device, NULL); + + g_print("Found %04x:%04x, %s %s\n", + g_usb_device_get_vid(device), + g_usb_device_get_pid(device), + manufacturer ? manufacturer : "", + product ? product : ""); } - g_ptr_array_unref (array); + g_ptr_array_unref(array); /* coldplug again, and ensure we did not duplicate devices */ - array = g_usb_context_get_devices (ctx); - g_assert (array != NULL); - g_assert_cmpint (array->len, ==, old_number_of_devices); - device = G_USB_DEVICE (g_ptr_array_index (array, 0)); - bus = g_usb_device_get_bus (device); - address = g_usb_device_get_address (device); - g_ptr_array_unref (array); + array = g_usb_context_get_devices(ctx); + g_assert(array != NULL); + g_assert_cmpint(array->len, ==, old_number_of_devices); + device = G_USB_DEVICE(g_ptr_array_index(array, 0)); + bus = g_usb_device_get_bus(device); + address = g_usb_device_get_address(device); + g_ptr_array_unref(array); /* ensure we can search for the same device */ - device = g_usb_context_find_by_bus_address (ctx, - bus, - address, - &error); - g_assert_no_error (error); - g_assert (device != NULL); - g_assert_cmpint (bus, ==, g_usb_device_get_bus (device)); - g_assert_cmpint (address, ==, g_usb_device_get_address (device)); - g_object_unref (device); + device = g_usb_context_find_by_bus_address(ctx, bus, address, &error); + g_assert_no_error(error); + g_assert(device != NULL); + g_assert_cmpint(bus, ==, g_usb_device_get_bus(device)); + g_assert_cmpint(address, ==, g_usb_device_get_address(device)); + g_object_unref(device); /* get a device that can't exist */ - device = g_usb_context_find_by_vid_pid (ctx, - 0xffff, - 0xffff, - &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NO_DEVICE); - g_assert (device == NULL); - g_clear_error (&error); - - g_object_unref (ctx); + device = g_usb_context_find_by_vid_pid(ctx, 0xffff, 0xffff, &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NO_DEVICE); + g_assert(device == NULL); } static void -gusb_device_huey_func (void) +gusb_device_huey_func(void) { - GUsbContext *ctx; - GError *error = NULL; - GUsbDevice *device; gboolean ret; GCancellable *cancellable = NULL; - const gchar request8 = { 0x0e, 'G', 'r', 'M', 'b', 'k', 'e', 'd' }; + const gchar request8 = {0x0e, 'G', 'r', 'M', 'b', 'k', 'e', 'd'}; + g_autoptr(GError) error = NULL; + g_autoptr(GUsbContext) ctx = NULL; + g_autoptr(GUsbDevice) device = NULL; - ctx = g_usb_context_new (&error); - g_assert_no_error (error); - g_assert (ctx != NULL); + ctx = g_usb_context_new(&error); + g_assert_no_error(error); + g_assert(ctx != NULL); - g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); + g_usb_context_set_debug(ctx, G_LOG_LEVEL_ERROR); /* coldplug, and get the huey */ - device = g_usb_context_find_by_vid_pid (ctx, - 0x0971, - 0x2005, - &error); - if (device == NULL && - error->domain == G_USB_DEVICE_ERROR && + device = g_usb_context_find_by_vid_pid(ctx, 0x0971, 0x2005, &error); + if (device == NULL && error->domain == G_USB_DEVICE_ERROR && error->code == G_USB_DEVICE_ERROR_NO_DEVICE) { - g_print ("No device detected!\n"); - g_error_free (error); - goto out; + g_print("No device detected!\n"); + return; } - g_assert_no_error (error); - g_assert (device != NULL); + g_assert_no_error(error); + g_assert(device != NULL); /* close not opened */ - ret = g_usb_device_close (device, &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_OPEN); - g_assert (!ret); - g_clear_error (&error); + ret = g_usb_device_close(device, &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NOT_OPEN); + g_assert(!ret); + g_clear_error(&error); /* open */ - ret = g_usb_device_open (device, &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_open(device, &error); + g_assert_no_error(error); + g_assert(ret); /* open opened */ - ret = g_usb_device_open (device, &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_ALREADY_OPEN); - g_assert (!ret); - g_clear_error (&error); + ret = g_usb_device_open(device, &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_ALREADY_OPEN); + g_assert(!ret); + g_clear_error(&error); /* claim interface 0 */ - ret = g_usb_device_claim_interface (device, 0x00, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_claim_interface(device, + 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error(error); + g_assert(ret); /* do a request (unlock) */ - ret = g_usb_device_control_transfer (device, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - 0x09, /* request */ - 0x0200, /* value */ - 0, /* index */ - (guint8*) request, - 8, - NULL, - 2000, - cancellable, - &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_control_transfer(device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + 0x09, /* request */ + 0x0200, /* value */ + 0, /* index */ + (guint8 *)request, + 8, + NULL, + 2000, + cancellable, + &error); + g_assert_no_error(error); + g_assert(ret); /* do a request we know is going to fail */ - ret = g_usb_device_control_transfer (device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - 0x09, /* request */ - 0x0200, /* value */ - 0, /* index */ - (guint8*) request, - 8, - NULL, - 2000, - cancellable, - &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_SUPPORTED); - g_assert (!ret); - g_clear_error (&error); + ret = g_usb_device_control_transfer(device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + 0x09, /* request */ + 0x0200, /* value */ + 0, /* index */ + (guint8 *)request, + 8, + NULL, + 2000, + cancellable, + &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NOT_SUPPORTED); + g_assert(!ret); + g_clear_error(&error); /* release interface 0 */ - ret = g_usb_device_release_interface (device, 0x00, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_release_interface(device, + 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error(error); + g_assert(ret); /* close */ - ret = g_usb_device_close (device, &error); - g_assert_no_error (error); - g_assert (ret); - - g_object_unref (device); -out: - g_object_unref (ctx); + ret = g_usb_device_close(device, &error); + g_assert_no_error(error); + g_assert(ret); } typedef struct { - guint8 *buffer; - guint buffer_len; - GMainLoop *loop; + guint8 *buffer; + guint buffer_len; + GMainLoop *loop; } GUsbDeviceAsyncHelper; - static void -g_usb_device_print_data (const gchar *title, - const guchar *data, - gsize length) +g_usb_device_print_data(const gchar *title, const guchar *data, gsize length) { - guint i; - - if (g_strcmp0 (title, "request") == 0) - g_print ("%c%dm", 0x1B, 31); - if (g_strcmp0 (title, "reply") == 0) - g_print ("%c%dm", 0x1B, 34); - g_print ("%s\t", title); - - for (i=0; i< length; i++) - g_print ("%02x %c\t", - datai, - g_ascii_isprint (datai) ? datai : '?'); - - g_print ("%c%dm\n", 0x1B, 0); + if (g_strcmp0(title, "request") == 0) + g_print("%c%dm", 0x1B, 31); + if (g_strcmp0(title, "reply") == 0) + g_print("%c%dm", 0x1B, 34); + g_print("%s\t", title); + + for (guint i = 0; i < length; i++) { + g_print("%02x %c\t", datai, g_ascii_isprint(datai) ? datai : '?'); + } + g_print("%c%dm\n", 0x1B, 0); } static void -g_usb_test_button_pressed_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +g_usb_test_button_pressed_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) { - gboolean ret; - GError *error = NULL; - GUsbDeviceAsyncHelper *helper = (GUsbDeviceAsyncHelper *) user_data; - - ret = g_usb_device_interrupt_transfer_finish (G_USB_DEVICE (source_object), - res, &error); + gssize rc; + GUsbDeviceAsyncHelper *helper = (GUsbDeviceAsyncHelper *)user_data; + g_autoptr(GError) error = NULL; - if (!ret) { - g_error ("%s", error->message); - g_error_free (error); + rc = g_usb_device_interrupt_transfer_finish(G_USB_DEVICE(source_object), res, &error); + if (rc < 0) { + g_error("%s", error->message); return; } - g_usb_device_print_data ("button press", - helper->buffer, - helper->buffer_len); - g_main_loop_quit (helper->loop); - g_free (helper->buffer); + g_usb_device_print_data("button press", helper->buffer, helper->buffer_len); + g_main_loop_quit(helper->loop); + g_free(helper->buffer); } static void -gusb_device_munki_func (void) +gusb_device_munki_func(void) { - GError *error = NULL; - GUsbContext *ctx; - GUsbDevice *device; gboolean ret; GCancellable *cancellable = NULL; guint8 request24; GUsbDeviceAsyncHelper *helper; + g_autoptr(GError) error = NULL; + g_autoptr(GUsbContext) ctx = NULL; + g_autoptr(GUsbDevice) device = NULL; - ctx = g_usb_context_new (&error); - g_assert_no_error (error); - g_assert (ctx != NULL); + ctx = g_usb_context_new(&error); + g_assert_no_error(error); + g_assert(ctx != NULL); - g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); + g_usb_context_set_debug(ctx, G_LOG_LEVEL_ERROR); /* coldplug, and get the ColorMunki */ - device = g_usb_context_find_by_vid_pid (ctx, - 0x0971, - 0x2007, - &error); - if (device == NULL && - error->domain == G_USB_DEVICE_ERROR && + device = g_usb_context_find_by_vid_pid(ctx, 0x0971, 0x2007, &error); + if (device == NULL && error->domain == G_USB_DEVICE_ERROR && error->code == G_USB_DEVICE_ERROR_NO_DEVICE) { - g_print ("No device detected!\n"); - g_error_free (error); - goto out; + g_print("No device detected!\n"); + return; } - g_assert_no_error (error); - g_assert (device != NULL); + g_assert_no_error(error); + g_assert(device != NULL); /* close not opened */ - ret = g_usb_device_close (device, &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_NOT_OPEN); - g_assert (!ret); - g_clear_error (&error); + ret = g_usb_device_close(device, &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NOT_OPEN); + g_assert(!ret); + g_clear_error(&error); /* open */ - ret = g_usb_device_open (device, &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_open(device, &error); + g_assert_no_error(error); + g_assert(ret); /* open opened */ - ret = g_usb_device_open (device, &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_ALREADY_OPEN); - g_assert (!ret); - g_clear_error (&error); + ret = g_usb_device_open(device, &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_ALREADY_OPEN); + g_assert(!ret); + g_clear_error(&error); /* claim interface 0 */ - ret = g_usb_device_claim_interface (device, 0x00, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_claim_interface(device, + 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error(error); + g_assert(ret); /* do a request (get chip id) */ - ret = g_usb_device_control_transfer (device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0x86, /* request */ - 0x0000, /* value */ - 0, /* index */ - (guint8*) request, - 24, - NULL, - 2000, - cancellable, - &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_control_transfer(device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x86, /* request */ + 0x0000, /* value */ + 0, /* index */ + (guint8 *)request, + 24, + NULL, + 2000, + cancellable, + &error); + g_assert_no_error(error); + g_assert(ret); /* do a request we know is going to fail */ - ret = g_usb_device_control_transfer (device, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_CLASS, - G_USB_DEVICE_RECIPIENT_INTERFACE, - 0x00, /* request */ - 0x0200, /* value */ - 0, /* index */ - (guint8*) request, - 8, - NULL, - 100, - cancellable, - &error); - g_assert_error (error, - G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_TIMED_OUT); - g_assert (!ret); - g_clear_error (&error); + ret = g_usb_device_control_transfer(device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + 0x00, /* request */ + 0x0200, /* value */ + 0, /* index */ + (guint8 *)request, + 8, + NULL, + 100, + cancellable, + &error); + g_assert_error(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT); + g_assert(!ret); + g_clear_error(&error); /* do async read of button event */ - helper = g_slice_new0 (GUsbDeviceAsyncHelper); + helper = g_slice_new0(GUsbDeviceAsyncHelper); helper->buffer_len = 8; - helper->buffer = g_new0 (guint8, helper->buffer_len); - helper->loop = g_main_loop_new (NULL, FALSE); - g_usb_device_interrupt_transfer_async (device, - 0x83, - helper->buffer, - 8, - 30*1000, - cancellable, /* TODO; use GCancellable */ - g_usb_test_button_pressed_cb, - helper); - g_main_loop_run (helper->loop); - g_main_loop_unref (helper->loop); + helper->buffer = g_new0(guint8, helper->buffer_len); + helper->loop = g_main_loop_new(NULL, FALSE); + g_usb_device_interrupt_transfer_async(device, + 0x83, + helper->buffer, + 8, + 30 * 1000, + cancellable, /* TODO; use GCancellable */ + g_usb_test_button_pressed_cb, + helper); + g_main_loop_run(helper->loop); + g_main_loop_unref(helper->loop); /* release interface 0 */ - ret = g_usb_device_release_interface (device, 0x00, - G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, - &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_release_interface(device, + 0x00, + G_USB_DEVICE_CLAIM_INTERFACE_BIND_KERNEL_DRIVER, + &error); + g_assert_no_error(error); + g_assert(ret); /* close */ - ret = g_usb_device_close (device, &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_close(device, &error); + g_assert_no_error(error); + g_assert(ret); +} + +static void +_context_signal_count_cb(GUsbContext *ctx, GUsbDevice *usb_device, gpointer user_data) +{ + guint *cnt = (guint *)user_data; + (*cnt)++; +} + +static gboolean +_g_usb_context_load_json(GUsbContext *ctx, const gchar *json, GError **error) +{ + JsonObject *json_obj; + g_autoptr(JsonParser) parser = json_parser_new(); - g_object_unref (device); -out: - g_object_unref (ctx); + if (!json_parser_load_from_data(parser, json, -1, error)) + return FALSE; + json_obj = json_node_get_object(json_parser_get_root(parser)); + return g_usb_context_load_with_tag(ctx, json_obj, "emulation", error); } static void -gusb_device_ch2_func (void) +gusb_device_json_func(void) { - GError *error = NULL; - GUsbContext *ctx; - GUsbDevice *device; gboolean ret; - gchar *tmp = NULL; guint8 idx; + guint added_cnt = 0; + guint changed_cnt = 0; + guint removed_cnt = 0; + g_autoptr(GUsbDevice) device = NULL; + g_autoptr(GUsbDevice) device2 = NULL; + g_autoptr(GUsbDevice) device3 = NULL; + g_autofree gchar *tmp = NULL; + g_autoptr(GUsbContext) ctx = NULL; + g_autoptr(GError) error = NULL; + const gchar *json = + "{" + " \"UsbDevices\" : " + " {" + " \"PlatformId\" : \"usb:AA:AA:06\"," + " \"Created\" : \"2023-02-01T16:35:03.302027Z\"," + " \"Tags\" : " + " \"emulation\"" + " ," + " \"IdVendor\" : 10047," + " \"IdProduct\" : 4100," + " \"Device\" : 2," + " \"USB\" : 512," + " \"Manufacturer\" : 1," + " \"UsbInterfaces\" : " + " {" + " \"Length\" : 9," + " \"DescriptorType\" : 4," + " \"InterfaceNumber\" : 1," + " \"InterfaceClass\" : 255," + " \"InterfaceSubClass\" : 70," + " \"InterfaceProtocol\" : 87," + " \"Interface\" : 3" + " }," + " {" + " \"Length\" : 9," + " \"DescriptorType\" : 4," + " \"InterfaceNumber\" : 2," + " \"InterfaceClass\" : 255," + " \"InterfaceSubClass\" : 71," + " \"InterfaceProtocol\" : 85," + " \"Interface\" : 4" + " }," + " {" + " \"Length\" : 9," + " \"DescriptorType\" : 4," + " \"InterfaceClass\" : 3," + " \"UsbEndpoints\" : " + " {" + " \"DescriptorType\" : 5," + " \"EndpointAddress\" : 129," + " \"Interval\" : 1," + " \"MaxPacketSize\" : 64" + " }," + " {" + " \"DescriptorType\" : 5," + " \"EndpointAddress\" : 1," + " \"Interval\" : 1," + " \"MaxPacketSize\" : 64" + " }" + " ," + " \"ExtraData\" : \"CSERAQABIh0A\"" + " }" + " ," + " \"UsbEvents\" : " + " {" + " \"Id\" : " + "\"GetCustomIndex:ClassId=0xff,SubclassId=0x46,ProtocolId=0x57\"," + " \"Data\" : \"Aw==\"" + " }," + " {" + " \"Id\" : " + "\"GetCustomIndex:ClassId=0xff,SubclassId=0x46,ProtocolId=0x57\"," + " \"Data\" : \"Aw==\"" + " }," + " {" + " \"Id\" : \"GetStringDescriptor:DescIndex=0x03\"," + " \"Data\" : " + "\"Mi4wLjcAAAAR3HzMiH8AAAAAAAAAAAAA8HBIAQAAAACQ6AsW/n8AADeVQAAAAAAAsOgLFv5/" + "AABNkkAAVwAAAEboCxb/" + "fwAAkAZLAQAAAAAAZkAAAAAAAwAAAAAAAAAAsPpJAQAAAAAwBksBAAAAAJAZTwEAAAAAAFZZJp63C7g=\"" + " }" + " " + " }" + " " + "}"; + const gchar *json_new = "{" + " \"UsbDevices\" : " + " {" + " \"PlatformId\" : \"usb:FF:FF:06\"," + " \"Created\" : \"2099-02-01T16:35:03.302027Z\"," + " \"Tags\" : " + " \"emulation\"" + " ," + " \"IdVendor\" : 10047," + " \"IdProduct\" : 4101," + " \"Device\" : 2," + " \"USB\" : 512," + " \"Manufacturer\" : 1" + " }" + " " + "}"; + ctx = g_usb_context_new(&error); + g_usb_context_set_flags(ctx, G_USB_CONTEXT_FLAGS_DEBUG); + g_assert_no_error(error); + g_assert(ctx != NULL); + + /* watch events */ + g_usb_context_enumerate(ctx); + g_signal_connect(G_USB_CONTEXT(ctx), + "device-added", + G_CALLBACK(_context_signal_count_cb), + &added_cnt); + g_signal_connect(G_USB_CONTEXT(ctx), + "device-removed", + G_CALLBACK(_context_signal_count_cb), + &removed_cnt); + g_signal_connect(G_USB_CONTEXT(ctx), + "device-changed", + G_CALLBACK(_context_signal_count_cb), + &changed_cnt); + + /* parse */ + ret = _g_usb_context_load_json(ctx, json, &error); + g_assert_no_error(error); + g_assert(ret); + g_assert_cmpint(added_cnt, ==, 1); + g_assert_cmpint(removed_cnt, ==, 0); + g_assert_cmpint(changed_cnt, ==, 0); + + /* get vendor data */ + device = g_usb_context_find_by_vid_pid(ctx, 0x273f, 0x1004, &error); + g_assert_no_error(error); + g_assert(device != NULL); + g_assert_true(g_usb_device_has_tag(device, "emulation")); + idx = g_usb_device_get_custom_index(device, + G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, + 'F', + 'W', + &error); + g_assert_no_error(error); + g_assert_cmpint(idx, ==, 3); + + /* in-order, repeat */ + idx = g_usb_device_get_custom_index(device, + G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, + 'F', + 'W', + &error); + g_assert_no_error(error); + g_assert_cmpint(idx, ==, 3); + + /* out-of-order */ + idx = g_usb_device_get_custom_index(device, + G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, + 'F', + 'W', + &error); + g_assert_no_error(error); + g_assert_cmpint(idx, ==, 3); - ctx = g_usb_context_new (&error); - g_assert_no_error (error); - g_assert (ctx != NULL); + /* get the firmware version */ + tmp = g_usb_device_get_string_descriptor(device, idx, &error); + g_assert_no_error(error); + g_assert_cmpstr(tmp, ==, "2.0.7"); + + /* load the same data */ + ret = _g_usb_context_load_json(ctx, json, &error); + g_assert_no_error(error); + g_assert(ret); + g_assert_cmpint(added_cnt, ==, 1); + g_assert_cmpint(removed_cnt, ==, 0); + g_assert_cmpint(changed_cnt, ==, 1); + device2 = g_usb_context_find_by_vid_pid(ctx, 0x273f, 0x1004, &error); + g_assert_no_error(error); + g_assert(device2 != NULL); + g_assert_true(g_usb_device_has_tag(device2, "emulation")); + + /* load a different device */ + ret = _g_usb_context_load_json(ctx, json_new, &error); + g_assert_no_error(error); + g_assert(ret); + g_assert_cmpint(added_cnt, ==, 2); + g_assert_cmpint(changed_cnt, ==, 1); + g_assert_cmpint(removed_cnt, ==, 1); + device3 = g_usb_context_find_by_vid_pid(ctx, 0x273f, 0x1005, &error); + g_assert_no_error(error); + g_assert(device3 != NULL); + g_assert_true(g_usb_device_has_tag(device3, "emulation")); +} - g_usb_context_set_debug (ctx, G_LOG_LEVEL_ERROR); +static void +gusb_device_ch2_func(void) +{ + gboolean ret; + guint8 idx; + g_autofree gchar *data = NULL; + g_autofree gchar *tmp = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GUsbContext) ctx = NULL; + g_autoptr(GUsbDevice) device = NULL; + g_autoptr(JsonBuilder) json_builder = json_builder_new(); + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; + + ctx = g_usb_context_new(&error); + g_usb_context_set_flags(ctx, G_USB_CONTEXT_FLAGS_SAVE_EVENTS); + g_assert_no_error(error); + g_assert(ctx != NULL); + + g_usb_context_set_debug(ctx, G_LOG_LEVEL_ERROR); /* coldplug, and get the ColorHug */ - device = g_usb_context_find_by_vid_pid (ctx, - 0x273f, - 0x1004, - &error); - if (device == NULL && - error->domain == G_USB_DEVICE_ERROR && + device = g_usb_context_find_by_vid_pid(ctx, 0x273f, 0x1004, &error); + if (device == NULL && error->domain == G_USB_DEVICE_ERROR && error->code == G_USB_DEVICE_ERROR_NO_DEVICE) { - g_print ("No device detected!\n"); - g_error_free (error); - goto out; + g_print("No device detected!\n"); + return; } - g_assert_no_error (error); - g_assert (device != NULL); + g_assert_no_error(error); + g_assert(device != NULL); /* open */ - ret = g_usb_device_open (device, &error); - g_assert_no_error (error); - g_assert (ret); + ret = g_usb_device_open(device, &error); + g_assert_no_error(error); + g_assert(ret); /* get vendor data */ - idx = g_usb_device_get_custom_index (device, - G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, - 'F', 'W', &error); - g_assert_no_error (error); - g_assert_cmpint (idx, ==, 3); + idx = g_usb_device_get_custom_index(device, + G_USB_DEVICE_CLASS_VENDOR_SPECIFIC, + 'F', + 'W', + &error); + g_assert_no_error(error); + g_assert_cmpint(idx, ==, 3); /* get the firmware version */ - tmp = g_usb_device_get_string_descriptor (device, idx, &error); - g_assert_no_error (error); - g_assert_cmpstr (tmp, ==, "2.0.3"); - g_free (tmp); + tmp = g_usb_device_get_string_descriptor(device, idx, &error); + g_assert_no_error(error); + g_assert_cmpstr(tmp, ==, "2.0.7"); /* close */ - ret = g_usb_device_close (device, &error); - g_assert_no_error (error); - g_assert (ret); - - g_object_unref (device); -out: - g_object_unref (ctx); + ret = g_usb_device_close(device, &error); + g_assert_no_error(error); + g_assert(ret); + + /* save context */ + ret = g_usb_context_save(ctx, json_builder, &error); + g_assert_no_error(error); + g_assert(ret); + + /* export as a string */ + json_root = json_builder_get_root(json_builder); + json_generator = json_generator_new(); + json_generator_set_pretty(json_generator, TRUE); + json_generator_set_root(json_generator, json_root); + data = json_generator_to_data(json_generator, NULL); + g_assert_nonnull(data); + g_print("%s\n", data); } int -main (int argc, - char **argv) +main(int argc, char **argv) { - g_test_init (&argc, &argv, NULL); + g_test_init(&argc, &argv, NULL); /* only critical and error are fatal */ - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); /* tests go here */ - g_test_add_func ("/gusb/context", gusb_context_func); - g_test_add_func ("/gusb/context{lookup}", gusb_context_lookup_func); - g_test_add_func ("/gusb/device", gusb_device_func); - g_test_add_func ("/gusb/devicehuey", gusb_device_huey_func); - g_test_add_func ("/gusb/devicemunki", gusb_device_munki_func); - g_test_add_func ("/gusb/devicecolorhug2", gusb_device_ch2_func); - - return g_test_run (); + g_test_add_func("/gusb/context", gusb_context_func); + g_test_add_func("/gusb/context{lookup}", gusb_context_lookup_func); + g_test_add_func("/gusb/device", gusb_device_func); + g_test_add_func("/gusb/devicehuey", gusb_device_huey_func); + g_test_add_func("/gusb/devicemunki", gusb_device_munki_func); + g_test_add_func("/gusb/devicecolorhug2", gusb_device_ch2_func); + g_test_add_func("/gusb/devicejson", gusb_device_json_func); + + return g_test_run(); } -
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-source.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-source.c
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2010-2014 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * * SPDX-License-Identifier: LGPL-2.1+ @@ -26,17 +26,17 @@ * Since: 0.1.0 **/ GQuark -g_usb_source_error_quark (void) +g_usb_source_error_quark(void) { static GQuark quark = 0; if (!quark) - quark = g_quark_from_static_string ("g_usb_source_error"); + quark = g_quark_from_static_string("g_usb_source_error"); return quark; } /** * g_usb_source_set_callback: - * @source: a #GUsbSource + * @self: a #GUsbSource * @func: a function to call * @data: data to pass to @func * @notify: a #GDestroyNotify @@ -46,10 +46,7 @@ * Since: 0.1.0 **/ void -g_usb_source_set_callback (GUsbSource *source, - GSourceFunc func, - gpointer data, - GDestroyNotify notify) +g_usb_source_set_callback(GUsbSource *self, GSourceFunc func, gpointer data, GDestroyNotify notify) { - g_source_set_callback ((GSource *)source, func, data, notify); + g_source_set_callback((GSource *)self, func, data, notify); }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-source.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-source.h
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2010-2014 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * * SPDX-License-Identifier: LGPL-2.1+ @@ -12,7 +12,7 @@ G_BEGIN_DECLS -#define G_USB_SOURCE_ERROR (g_usb_source_error_quark ()) +#define G_USB_SOURCE_ERROR (g_usb_source_error_quark()) typedef struct _GUsbSource GUsbSource; @@ -21,17 +21,14 @@ * * The error code. **/ -typedef enum { - G_USB_SOURCE_ERROR_INTERNAL -} GUsbSourceError; +typedef enum { G_USB_SOURCE_ERROR_INTERNAL } GUsbSourceError; G_DEPRECATED_FOR(g_usb_context_error_quark) -GQuark g_usb_source_error_quark (void); +GQuark +g_usb_source_error_quark(void); G_DEPRECATED -void g_usb_source_set_callback (GUsbSource *source, - GSourceFunc func, - gpointer data, - GDestroyNotify notify); +void +g_usb_source_set_callback(GUsbSource *self, GSourceFunc func, gpointer data, GDestroyNotify notify); G_END_DECLS
View file
_service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-umockdev-test.c
Added
@@ -0,0 +1,210 @@ +/* + * libusb umockdev based tests + * + * Copyright (C) 2022 Benjamin Berg <bberg@redhat.com> + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include <glib.h> +#include <string.h> +#include <unistd.h> + +#include "gusb.h" +#include "umockdev.h" + +#define UNUSED_DATA __attribute__((unused)) gconstpointer unused_data + +/* avoid leak reports inside assertions; leaking stuff on assertion failures does not matter in + * tests */ +#if !defined(__clang__) +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#pragma GCC diagnostic ignored "-Wanalyzer-file-leak" +#endif + +typedef struct { + UMockdevTestbed *testbed; + GUsbContext *ctx; +} UMockdevTestbedFixture; + +static void +test_fixture_setup(UMockdevTestbedFixture *fixture, UNUSED_DATA) +{ + fixture->testbed = umockdev_testbed_new(); + g_assert(fixture->testbed != NULL); +} + +static void +test_fixture_setup_empty(UMockdevTestbedFixture *fixture, UNUSED_DATA) +{ + test_fixture_setup(fixture, NULL); + fixture->ctx = g_usb_context_new(NULL); +} + +static void +test_fixture_teardown(UMockdevTestbedFixture *fixture, UNUSED_DATA) +{ + /* break context -> device -> context cycle */ + if (fixture->ctx) + g_object_run_dispose(G_OBJECT(fixture->ctx)); + g_clear_object(&fixture->ctx); + g_clear_object(&fixture->testbed); + + /* running the mainloop is needed to ensure everything is cleaned up */ + while (g_main_context_iteration(NULL, FALSE)) { + } +} + +static void +test_fixture_add_canon(UMockdevTestbedFixture *fixture) +{ + /* NOTE: there is no device file, so cannot be opened */ + + /* NOTE: add_device would not create a file, needed for device emulation */ + /* XXX: racy, see https://github.com/martinpitt/umockdev/issues/173 */ + umockdev_testbed_add_from_string( + fixture->testbed, + "P: /devices/usb1\n" + "N: bus/usb/001/001\n" + "E: SUBSYSTEM=usb\n" + "E: DRIVER=usb\n" + "E: BUSNUM=001\n" + "E: DEVNUM=001\n" + "E: DEVNAME=/dev/bus/usb/001/001\n" + "E: DEVTYPE=usb_device\n" + "A: bConfigurationValue=1\\n\n" + "A: busnum=1\\n\n" + "A: devnum=1\\n\n" + "A: bConfigurationValue=1\\n\n" + "A: speed=480\\n\n" + /* descriptor from a Canon PowerShot SX200; VID 04a9 PID 31c0 */ + "H: descriptors=" + "1201000200000040a904c03102000102" + "030109022700010100c0010904000003" + "06010100070581020002000705020200" + "020007058303080009\n", + NULL); +} + +static void +test_ctx_enumerate(UMockdevTestbedFixture *fixture, UNUSED_DATA) +{ + g_autoptr(GPtrArray) devices = NULL; + + test_fixture_add_canon(fixture); + + g_usb_context_enumerate(fixture->ctx); + + devices = g_usb_context_get_devices(fixture->ctx); + g_assert_cmpint(devices->len, ==, 1); +} + +static void +count_hotplug_event_cb(GUsbContext *context, GUsbDevice *device, gpointer user_data) +{ + int *counter = user_data; + + *counter += 1; +} + +static void +test_ctx_hotplug(UMockdevTestbedFixture *fixture, UNUSED_DATA) +{ + g_autoptr(GPtrArray) devices = NULL; + gint events = 0; + + g_signal_connect(fixture->ctx, "device-added", G_CALLBACK(count_hotplug_event_cb), &events); + + g_usb_context_enumerate(fixture->ctx); + + devices = g_usb_context_get_devices(fixture->ctx); + g_assert_cmpint(devices->len, ==, 0); + g_assert_cmpint(events, ==, 0); + g_clear_pointer(&devices, g_ptr_array_unref); + + test_fixture_add_canon(fixture); + /* ensure the event was processed by helper thread */ + g_usleep(G_USEC_PER_SEC / 2); + + /* still not returned (and no event fired) */ + devices = g_usb_context_get_devices(fixture->ctx); + g_assert_cmpint(devices->len, ==, 0); + g_assert_cmpint(events, ==, 0); + g_clear_pointer(&devices, g_ptr_array_unref); + + /* run mainloop, which causes the event to be processed */ + while (g_main_context_iteration(NULL, FALSE)) { + } + + devices = g_usb_context_get_devices(fixture->ctx); + g_assert_cmpint(events, ==, 1); + g_assert_cmpint(devices->len, ==, 1); + g_clear_pointer(&devices, g_ptr_array_unref); +} + +static void +test_ctx_hotplug_dispose(UMockdevTestbedFixture *fixture, UNUSED_DATA) +{ + g_autoptr(GPtrArray) devices = NULL; + gint events = 0; + + g_signal_connect(fixture->ctx, "device-added", G_CALLBACK(count_hotplug_event_cb), &events); + + g_usb_context_enumerate(fixture->ctx); + devices = g_usb_context_get_devices(fixture->ctx); + g_assert_cmpint(devices->len, ==, 0); + g_assert_cmpint(events, ==, 0); + g_clear_pointer(&devices, g_ptr_array_unref); + + test_fixture_add_canon(fixture); + /* ensure the event was processed by helper thread */ + g_usleep(G_USEC_PER_SEC / 2); + + /* still not returned (and no event fired) */ + g_usb_context_enumerate(fixture->ctx); + devices = g_usb_context_get_devices(fixture->ctx); + g_assert_cmpint(devices->len, ==, 0); + g_assert_cmpint(events, ==, 0); + g_clear_pointer(&devices, g_ptr_array_unref); + + /* idle handler is pending, we dispose our context reference */ + g_object_run_dispose(G_OBJECT(fixture->ctx)); + + /* run mainloop, which causes the event to be processed */ + while (g_main_context_iteration(NULL, FALSE)) { + } + + /* but no signal is fired */ + g_assert_cmpint(events, ==, 0); + + g_clear_object(&fixture->ctx); +} + +int +main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add("/gusb/ctx/enumerate", + UMockdevTestbedFixture, + NULL, + test_fixture_setup_empty, + test_ctx_enumerate, + test_fixture_teardown); + + g_test_add("/gusb/ctx/hotplug", + UMockdevTestbedFixture, + NULL, + test_fixture_setup_empty, + test_ctx_hotplug, + test_fixture_teardown); + + g_test_add("/gusb/ctx/hotplug-dispose", + UMockdevTestbedFixture, + NULL, + test_fixture_setup_empty, + test_ctx_hotplug_dispose, + test_fixture_teardown); + + return g_test_run(); +}
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-util.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-util.c
Changed
@@ -22,7 +22,7 @@ * Since: 0.1.0 **/ const gchar * -g_usb_strerror (gint error_code) +g_usb_strerror(gint error_code) { - return libusb_strerror (error_code); + return libusb_strerror(error_code); }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-util.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-util.h
Changed
@@ -11,6 +11,7 @@ G_BEGIN_DECLS -const gchar *g_usb_strerror (gint error_code); +const gchar * +g_usb_strerror(gint error_code); G_END_DECLS
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-version.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-version.c
Changed
@@ -19,9 +19,8 @@ * Since: 0.3.1 **/ const gchar * -g_usb_version_string (void) +g_usb_version_string(void) { - return G_STRINGIFY(G_USB_MAJOR_VERSION) "." - G_STRINGIFY(G_USB_MINOR_VERSION) "." - G_STRINGIFY(G_USB_MICRO_VERSION); + return G_STRINGIFY(G_USB_MAJOR_VERSION) "." G_STRINGIFY( + G_USB_MINOR_VERSION) "." G_STRINGIFY(G_USB_MICRO_VERSION); }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb-version.h.in -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb-version.h.in
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2010-2018 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1+ */
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/gusb.h -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/gusb.h
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2010-2011 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2010 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -9,14 +9,15 @@ #define __GUSB_INSIDE__ -#include <gusb/gusb-autocleanups.h> +#include <gusb/gusb-bos-descriptor.h> #include <gusb/gusb-context.h> -#include <gusb/gusb-interface.h> +#include <gusb/gusb-device-event.h> +#include <gusb/gusb-device-list.h> +#include <gusb/gusb-device.h> #include <gusb/gusb-endpoint.h> +#include <gusb/gusb-interface.h> #include <gusb/gusb-source.h> -#include <gusb/gusb-device.h> -#include <gusb/gusb-device-list.h> -#include <gusb/gusb-version.h> #include <gusb/gusb-util.h> +#include <gusb/gusb-version.h> #undef __GUSB_INSIDE__
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/libgusb.ver -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/libgusb.ver
Changed
@@ -166,3 +166,52 @@ g_usb_context_set_hotplug_poll_interval; local: *; } LIBGUSB_0.3.8; + +LIBGUSB_0.4.0 { + global: + g_usb_bos_descriptor_get_capability; + g_usb_bos_descriptor_get_extra; + g_usb_bos_descriptor_get_type; + g_usb_context_load; + g_usb_context_save; + g_usb_device_event_get_bytes; + g_usb_device_event_get_id; + g_usb_device_event_get_status; + g_usb_device_event_get_type; + g_usb_device_event_set_bytes; + g_usb_device_get_bos_descriptor; + g_usb_device_get_bos_descriptors; + g_usb_device_get_events; + g_usb_device_invalidate; + local: *; +} LIBGUSB_0.3.10; + +LIBGUSB_0.4.1 { + global: + g_usb_context_load_with_tag; + g_usb_context_save_with_tag; + g_usb_device_add_tag; + local: *; +} LIBGUSB_0.4.0; + +LIBGUSB_0.4.3 { + global: + g_usb_device_has_tag; + local: *; +} LIBGUSB_0.4.1; + +LIBGUSB_0.4.4 { + global: + g_usb_device_clear_events; + g_usb_device_get_tags; + g_usb_device_is_emulated; + g_usb_device_remove_tag; + local: *; +} LIBGUSB_0.4.3; + +LIBGUSB_0.4.5 { + global: + g_usb_device_event_get_rc; + g_usb_device_get_created; + local: *; +} LIBGUSB_0.4.4;
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/gusb/meson.build -> _service:tar_scm:libgusb-0.4.6.tar.xz/gusb/meson.build
Changed
@@ -26,14 +26,16 @@ install_headers( gusb_version_h, - 'gusb-autocleanups.h', 'gusb-context.h', 'gusb-context-private.h', 'gusb-device.h', + 'gusb-device-event.h', 'gusb-device-private.h', 'gusb-device-list.h', 'gusb-interface.h', 'gusb-interface-private.h', + 'gusb-bos-descriptor.h', + 'gusb-bos-descriptor-private.h', 'gusb-endpoint.h', 'gusb-endpoint-private.h', 'gusb-source.h', @@ -54,12 +56,15 @@ sources : 'gusb-context.c', 'gusb-device.c', + 'gusb-device-event.c', 'gusb-device-list.c', 'gusb-interface.c', + 'gusb-bos-descriptor.c', 'gusb-endpoint.c', 'gusb-source.c', 'gusb-util.c', 'gusb-version.c', + 'gusb-json-common.c', , soversion : lt_current, version : lt_version, @@ -67,6 +72,7 @@ dependencies : libgio, libusb, + libjsonglib, , c_args : cargs, @@ -91,7 +97,7 @@ pkgg = import('pkgconfig') pkgg.generate(gusb, - requires : 'gio-2.0', 'gobject-2.0', 'libusb-1.0' , + requires : 'gio-2.0', 'gobject-2.0', 'libusb-1.0', 'json-glib-1.0' , subdirs : 'gusb-1', version : meson.project_version(), name : 'gusb', @@ -103,18 +109,23 @@ libgusb_girtarget = gnome.generate_gir(gusb, sources : gusb_version_h, - 'gusb-autocleanups.h', 'gusb-context.c', 'gusb-context.h', 'gusb-context-private.h', 'gusb-device.c', 'gusb-device.h', + 'gusb-device-event.c', + 'gusb-device-event.h', + 'gusb-device-event-private.h', 'gusb-device-list.c', 'gusb-device-list.h', 'gusb-device-private.h', 'gusb-interface.c', 'gusb-interface.h', 'gusb-interface-private.h', + 'gusb-bos-descriptor.c', + 'gusb-bos-descriptor.h', + 'gusb-bos-descriptor-private.h', 'gusb-endpoint.c', 'gusb-endpoint.h', 'gusb-endpoint-private.h', @@ -137,10 +148,12 @@ dependencies : libgio, libusb, + libjsonglib, , includes : 'Gio-2.0', 'GObject-2.0', + 'Json-1.0', , install : true ) @@ -163,7 +176,7 @@ output: 'libgusb.ver', command: py_installation, - join_paths(meson.source_root(), 'contrib', 'generate-version-script.py'), + join_paths(meson.project_source_root(), 'contrib', 'generate-version-script.py'), 'LIBGUSB', '@INPUT@', '@OUTPUT@', @@ -183,7 +196,7 @@ if get_option('vapi') gnome.generate_vapi('gusb', sources: libgusb_girtarget0, - packages: 'gio-2.0', + packages: 'gio-2.0', 'json-glib-1.0', install: true, ) endif @@ -194,12 +207,15 @@ sources : 'gusb-context.c', 'gusb-device.c', + 'gusb-device-event.c', 'gusb-device-list.c', 'gusb-interface.c', + 'gusb-bos-descriptor.c', 'gusb-endpoint.c', 'gusb-self-test.c', 'gusb-source.c', 'gusb-util.c', + 'gusb-json-common.c' , include_directories : root_incdir, @@ -208,10 +224,24 @@ dependencies : libgio, libusb, + libjsonglib, , c_args : cargs, , ) test('gusb-self-test', e) + + # Umockdev based tests + test_env = environment() + test_env.prepend('LD_PRELOAD', 'libumockdev-preload.so.0') + + test_umockdev = executable( + 'gusb-umockdev-test', + 'gusb-umockdev-test.c', + dependencies: umockdev, gusb_dep ) + + test('gusb-umockdev-test', + test_umockdev, + env: test_env) endif
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/meson.build -> _service:tar_scm:libgusb-0.4.6.tar.xz/meson.build
Changed
@@ -1,7 +1,7 @@ project('libgusb', 'c', - version : '0.3.10', + version : '0.4.6', license : 'LGPL-2.1+', - meson_version : '>=0.46.0', + meson_version : '>=0.56.0', default_options : 'c_std=c99' ) @@ -49,6 +49,7 @@ '-Wno-strict-aliasing', '-Wno-suggest-attribute=format', '-Wno-unused-parameter', + '-Wno-gnu-variable-sized-type-not-at-end', '-Wold-style-definition', '-Woverride-init', '-Wpointer-arith', @@ -93,6 +94,11 @@ language: 'c' ) +if get_option('tests') + umockdev = dependency('umockdev-1.0', version: '>= 0.17.7', disabler: true, required: get_option('umockdev')) +else + umockdev = disabler() +endif libgio = dependency('gio-2.0', version : '>= 2.44.0') libusb = dependency('libusb-1.0', version : '>= 1.0.9') if cc.has_header_symbol('libusb.h', 'LIBUSB_CAP_HAS_HOTPLUG', dependencies: libusb) @@ -110,10 +116,12 @@ if cc.has_header_symbol('libusb.h', 'libusb_get_port_number', dependencies: libusb) conf.set('HAVE_LIBUSB_GET_PORT_NUMBER', '1') endif +libjsonglib = dependency('json-glib-1.0', version: '>= 1.1.1') gusb_deps = libgio, libusb, + libjsonglib, gnome = import('gnome') @@ -122,6 +130,7 @@ prefix = get_option('prefix') bindir = join_paths(prefix, get_option('bindir')) +datadir = join_paths(prefix, get_option('datadir')) configure_file( output : 'config.h', @@ -132,4 +141,6 @@ subdir('gusb') subdir('tools') -subdir('docs') +if get_option('docs') + subdir('docs') +endif
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/meson_options.txt -> _service:tar_scm:libgusb-0.4.6.tar.xz/meson_options.txt
Changed
@@ -3,3 +3,4 @@ option('usb_ids', type : 'string', value : '/usr/share/hwdata/usb.ids', description : 'Path to usb.ids file') option('docs', type : 'boolean', value : true, description : 'Generate documentation') option('introspection', type : 'boolean', value : true, description : 'Generate gobject introspection data') +option('umockdev', type : 'feature', value : 'auto', description : 'Build and run umockdev based tests')
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/tools/gusb-main.c -> _service:tar_scm:libgusb-0.4.6.tar.xz/tools/gusb-main.c
Changed
@@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2011-2016 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -13,507 +13,544 @@ #include <string.h> static void -gusb_log_ignore_cb (const gchar *log_domain, GLogLevelFlags log_level, - const gchar *message, gpointer user_data) +gusb_log_ignore_cb(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) { } static void -gusb_log_handler_cb (const gchar *log_domain, GLogLevelFlags log_level, - const gchar *message, gpointer user_data) +gusb_log_handler_cb(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) { gchar str_time255; time_t the_time; /* header always in green */ - time (&the_time); - strftime (str_time, 254, "%H:%M:%S", localtime (&the_time)); - g_print ("%c%dmTI:%s\t", 0x1B, 32, str_time); + time(&the_time); + strftime(str_time, 254, "%H:%M:%S", localtime(&the_time)); + g_print("%c%dmTI:%s\t", 0x1B, 32, str_time); /* critical is also in red */ - if (log_level == G_LOG_LEVEL_CRITICAL || - log_level == G_LOG_LEVEL_WARNING || + if (log_level == G_LOG_LEVEL_CRITICAL || log_level == G_LOG_LEVEL_WARNING || log_level == G_LOG_LEVEL_ERROR) { - g_print ("%c%dm%s\n%c%dm", 0x1B, 31, message, 0x1B, 0); + g_print("%c%dm%s\n%c%dm", 0x1B, 31, message, 0x1B, 0); } else { /* debug in blue */ - g_print ("%c%dm%s\n%c%dm", 0x1B, 34, message, 0x1B, 0); + g_print("%c%dm%s\n%c%dm", 0x1B, 34, message, 0x1B, 0); } } typedef struct { - GOptionContext *context; - GUsbContext *usb_ctx; - GPtrArray *cmd_array; + GOptionContext *context; + GUsbContext *usb_ctx; + GPtrArray *cmd_array; } GUsbCmdPrivate; -typedef gboolean (*GUsbCmdPrivateCb) (GUsbCmdPrivate *cmd, - gchar **values, - GError **error); +typedef gboolean (*GUsbCmdPrivateCb)(GUsbCmdPrivate *cmd, gchar **values, GError **error); typedef struct { - gchar *name; - gchar *description; - GUsbCmdPrivateCb callback; + gchar *name; + gchar *description; + GUsbCmdPrivateCb callback; } GUsbCmdItem; static void -gusb_cmd_item_free (GUsbCmdItem *item) +gusb_cmd_item_free(GUsbCmdItem *item) { - g_free (item->name); - g_free (item->description); - g_slice_free (GUsbCmdItem, item); + g_free(item->name); + g_free(item->description); + g_slice_free(GUsbCmdItem, item); } /* * gusb_sort_command_name_cb: */ static gint -gusb_sort_command_name_cb (GUsbCmdItem **item1, GUsbCmdItem **item2) +gusb_sort_command_name_cb(GUsbCmdItem **item1, GUsbCmdItem **item2) { - return g_strcmp0 ((*item1)->name, (*item2)->name); + return g_strcmp0((*item1)->name, (*item2)->name); } static void -gusb_cmd_add (GPtrArray *array, const gchar *name, const gchar *description, GUsbCmdPrivateCb callback) +gusb_cmd_add(GPtrArray *array, + const gchar *name, + const gchar *description, + GUsbCmdPrivateCb callback) { - gchar **names; - guint i; - GUsbCmdItem *item; - - /* add each one */ - names = g_strsplit (name, ",", -1); - for (i=0; namesi != NULL; i++) { - item = g_slice_new0 (GUsbCmdItem); - item->name = g_strdup (namesi); + g_auto(GStrv) names = g_strsplit(name, ",", -1); + for (guint i = 0; namesi != NULL; i++) { + GUsbCmdItem *item = g_slice_new0(GUsbCmdItem); + item->name = g_strdup(namesi); if (i == 0) { - item->description = g_strdup (description); + item->description = g_strdup(description); } else { /* TRANSLATORS: this is a command alias */ - item->description = g_strdup_printf ("Alias to %s", - names0); + item->description = g_strdup_printf("Alias to %s", names0); } item->callback = callback; - g_ptr_array_add (array, item); + g_ptr_array_add(array, item); } - g_strfreev (names); } static gchar * -gusb_cmd_get_descriptions (GPtrArray *array) +gusb_cmd_get_descriptions(GPtrArray *array) { - guint i; - guint j; guint len; guint max_len = 19; - GUsbCmdItem *item; - GString *string; + g_autoptr(GString) string = NULL; /* print each command */ - string = g_string_new (""); - for (i = 0; i < array->len; i++) { - item = g_ptr_array_index (array, i); - g_string_append (string, " "); - g_string_append (string, item->name); - g_string_append (string, " "); - len = strlen (item->name); - for (j = len; j < max_len+2; j++) - g_string_append_c (string, ' '); - g_string_append (string, item->description); - g_string_append_c (string, '\n'); + string = g_string_new(""); + for (guint i = 0; i < array->len; i++) { + GUsbCmdItem *item = g_ptr_array_index(array, i); + g_string_append(string, " "); + g_string_append(string, item->name); + g_string_append(string, " "); + len = strlen(item->name); + for (guint j = len; j < max_len + 2; j++) + g_string_append_c(string, ' '); + g_string_append(string, item->description); + g_string_append_c(string, '\n'); } /* remove trailing newline */ if (string->len > 0) - g_string_set_size (string, string->len - 1); + g_string_set_size(string, string->len - 1); - return g_string_free (string, FALSE); + return g_string_free(g_steal_pointer(&string), FALSE); } static void -gusb_main_device_open (GUsbDevice *device) +gusb_main_device_open(GUsbDevice *device) { - GError *error = NULL; guint8 idx; + g_autoptr(GError) error = NULL; /* open */ - if (!g_usb_device_open (device, &error)) { - g_print ("failed to open: %s\n", error->message); - g_error_free (error); + if (!g_usb_device_open(device, &error)) { + g_print("failed to open: %s\n", error->message); return; } /* print info we can only get whilst open */ - idx = g_usb_device_get_product_index (device); + idx = g_usb_device_get_product_index(device); if (idx != 0x00) { - gchar *product = g_usb_device_get_string_descriptor (device, idx, &error); + g_autofree gchar *product = g_usb_device_get_string_descriptor(device, idx, &error); if (product == NULL) { - g_print ("failed to get string desc: %s\n", error->message); - g_error_free (error); + g_print("failed to get string desc: %s\n", error->message); return; } - g_print ("product: %s\n", product); - g_free (product); + g_print("product: %s\n", product); + } + if (!g_usb_device_close(device, &error)) { + g_print("failed to close: %s\n", error->message); + return; } } static void -gusb_device_list_added_cb (GUsbContext *context, - GUsbDevice *device, - gpointer user_data) +gusb_device_list_added_cb(GUsbContext *context, GUsbDevice *device, gpointer user_data) { - g_print ("device %s added %x:%x\n", - g_usb_device_get_platform_id (device), - g_usb_device_get_bus (device), - g_usb_device_get_address (device)); - gusb_main_device_open (device); + g_print("device %s added %x:%x\n", + g_usb_device_get_platform_id(device), + g_usb_device_get_bus(device), + g_usb_device_get_address(device)); + gusb_main_device_open(device); } static void -gusb_device_list_removed_cb (GUsbContext *context, - GUsbDevice *device, - gpointer user_data) +gusb_device_list_removed_cb(GUsbContext *context, GUsbDevice *device, gpointer user_data) { - g_print ("device %s removed %x:%x\n", - g_usb_device_get_platform_id (device), - g_usb_device_get_bus (device), - g_usb_device_get_address (device)); + g_print("device %s removed %x:%x\n", + g_usb_device_get_platform_id(device), + g_usb_device_get_bus(device), + g_usb_device_get_address(device)); } static gint -gusb_devices_sort_by_platform_id_cb (gconstpointer a, gconstpointer b) +gusb_devices_sort_by_platform_id_cb(gconstpointer a, gconstpointer b) { - GUsbDevice *device_a = *((GUsbDevice **) a); - GUsbDevice *device_b = *((GUsbDevice **) b); - return g_strcmp0 (g_usb_device_get_platform_id (device_a), - g_usb_device_get_platform_id (device_b)); + GUsbDevice *device_a = *((GUsbDevice **)a); + GUsbDevice *device_b = *((GUsbDevice **)b); + return g_strcmp0(g_usb_device_get_platform_id(device_a), + g_usb_device_get_platform_id(device_b)); } static gboolean -moo_cb (GNode *node, gpointer data) +gusb_cmd_show_cb(GNode *node, gpointer data) { - GUsbDevice *device = G_USB_DEVICE (node->data); - GNode *n; - guint i; + GUsbDevice *device = G_USB_DEVICE(node->data); const gchar *tmp; - gchar *product = NULL; - gchar *vendor = NULL; - GString *str = NULL; + g_autofree gchar *product = NULL; + g_autofree gchar *vendor = NULL; + g_autoptr(GString) str = NULL; if (device == NULL) { - g_print ("Root Device\n"); + g_print("Root Device\n"); return FALSE; } /* indent */ - str = g_string_new (""); - for (n = node; n->data != NULL; n = n->parent) - g_string_append (str, " "); + str = g_string_new(""); + for (GNode *n = node; n->data != NULL; n = n->parent) + g_string_append(str, " "); /* add bus:address */ - g_string_append_printf (str, "%02x:%02x %04x:%04x", - g_usb_device_get_bus (device), - g_usb_device_get_address (device), - g_usb_device_get_vid (device), - g_usb_device_get_pid (device)); + g_string_append_printf(str, + "%02x:%02x %04x:%04x", + g_usb_device_get_bus(device), + g_usb_device_get_address(device), + g_usb_device_get_vid(device), + g_usb_device_get_pid(device)); /* pad */ - for (i = str->len; i < 30; i++) - g_string_append (str, " "); + for (guint i = str->len; i < 30; i++) + g_string_append(str, " "); /* We don't error check these as not all devices have these (and the device_open may have failed). */ - g_usb_device_open (device, NULL); - vendor = g_usb_device_get_string_descriptor (device, - g_usb_device_get_manufacturer_index (device), - NULL); - product = g_usb_device_get_string_descriptor (device, - g_usb_device_get_product_index (device), - NULL); + g_usb_device_open(device, NULL); + vendor = g_usb_device_get_string_descriptor(device, + g_usb_device_get_manufacturer_index(device), + NULL); + product = g_usb_device_get_string_descriptor(device, + g_usb_device_get_product_index(device), + NULL); /* lookup from usb.ids */ if (vendor == NULL) { - tmp = g_usb_device_get_vid_as_str (device); + tmp = g_usb_device_get_vid_as_str(device); if (tmp != NULL) - vendor = g_strdup (tmp); + vendor = g_strdup(tmp); } if (product == NULL) { - tmp = g_usb_device_get_pid_as_str (device); + tmp = g_usb_device_get_pid_as_str(device); if (tmp != NULL) - product = g_strdup (tmp); + product = g_strdup(tmp); } /* a hub */ - if (g_usb_device_get_device_class (device) == 0x09 && product == NULL) { - product = g_strdup ("USB HUB"); + if (g_usb_device_get_device_class(device) == 0x09 && product == NULL) { + product = g_strdup("USB HUB"); } /* fall back to the VID/PID */ if (product == NULL) - product = g_strdup ("Unknown"); + product = g_strdup("Unknown"); if (vendor == NULL) - vendor = g_strdup ("Unknown"); + vendor = g_strdup("Unknown"); /* add bus:address */ - g_string_append_printf (str, "%s - %s", vendor, product); - g_free (product); - g_free (vendor); - - g_print ("%s\n", str->str); - g_string_free (str, TRUE); + g_string_append_printf(str, "%s - %s", vendor, product); + g_print("%s\n", str->str); + g_usb_device_close(device, NULL); return FALSE; } static gboolean -gusb_cmd_show (GUsbCmdPrivate *priv, gchar **values, GError **error) +gusb_cmd_show(GUsbCmdPrivate *priv, gchar **values, GError **error) { - GNode *n; - GNode *node; - guint i; - GUsbDevice *device; - GUsbDevice *parent; - GPtrArray *devices = NULL; + g_autoptr(GNode) node = NULL; + g_autoptr(GPtrArray) devices = NULL; /* sort */ - devices = g_usb_context_get_devices (priv->usb_ctx); - g_ptr_array_sort (devices, gusb_devices_sort_by_platform_id_cb); + devices = g_usb_context_get_devices(priv->usb_ctx); + g_ptr_array_sort(devices, gusb_devices_sort_by_platform_id_cb); /* make a tree of the devices */ - node = g_node_new (NULL); - for (i = 0; i < devices->len; i++) { - device = g_ptr_array_index (devices, i); - - parent = g_usb_device_get_parent (device); + node = g_node_new(NULL); + for (guint i = 0; i < devices->len; i++) { + GNode *n; + GUsbDevice *device = g_ptr_array_index(devices, i); + GUsbDevice *parent = g_usb_device_get_parent(device); if (parent == NULL) { - g_node_append_data (node, device); + g_node_append_data(node, device); continue; } - n = g_node_find (node, G_PRE_ORDER, G_TRAVERSE_ALL, parent); + n = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, parent); if (n == NULL) { - g_set_error (error, 1, 0, - "no parent node for %s", - g_usb_device_get_platform_id (device)); + g_set_error(error, + 1, + 0, + "no parent node for %s", + g_usb_device_get_platform_id(device)); return FALSE; } - g_node_append_data (n, device); - + g_node_append_data(n, device); } - g_ptr_array_unref (devices); - g_node_traverse (node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, moo_cb, priv); - + g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, gusb_cmd_show_cb, priv); return TRUE; } static gboolean -gusb_cmd_watch (GUsbCmdPrivate *priv, gchar **values, GError **error) +gusb_cmd_watch(GUsbCmdPrivate *priv, gchar **values, GError **error) { - gboolean ret = TRUE; - GPtrArray *devices; - guint i; - GUsbDevice *device; - GMainLoop *loop; - - devices = g_usb_context_get_devices (priv->usb_ctx); - for (i = 0; i < devices->len; i++) { - device = g_ptr_array_index (devices, i); - g_print ("device %s already present %x:%x\n", - g_usb_device_get_platform_id (device), - g_usb_device_get_bus (device), - g_usb_device_get_address (device)); - gusb_main_device_open (device); + g_autoptr(GMainLoop) loop = NULL; + g_autoptr(GPtrArray) devices = NULL; + + devices = g_usb_context_get_devices(priv->usb_ctx); + for (guint i = 0; i < devices->len; i++) { + GUsbDevice *device = g_ptr_array_index(devices, i); + g_print("device %s already present %x:%x\n", + g_usb_device_get_platform_id(device), + g_usb_device_get_bus(device), + g_usb_device_get_address(device)); + gusb_main_device_open(device); } - loop = g_main_loop_new (NULL, FALSE); - g_signal_connect (priv->usb_ctx, "device-added", - G_CALLBACK (gusb_device_list_added_cb), - priv); - g_signal_connect (priv->usb_ctx, "device-removed", - G_CALLBACK (gusb_device_list_removed_cb), - priv); - g_main_loop_run (loop); - - g_main_loop_unref (loop); - g_ptr_array_unref (devices); - return ret; + loop = g_main_loop_new(NULL, FALSE); + g_signal_connect(priv->usb_ctx, + "device-added", + G_CALLBACK(gusb_device_list_added_cb), + priv); + g_signal_connect(priv->usb_ctx, + "device-removed", + G_CALLBACK(gusb_device_list_removed_cb), + priv); + g_main_loop_run(loop); + return TRUE; } static gboolean -gusb_cmd_replug (GUsbCmdPrivate *priv, gchar **values, GError **error) +gusb_cmd_replug(GUsbCmdPrivate *priv, gchar **values, GError **error) { - GUsbDevice *device; - GUsbDevice *device_new; guint16 vid, pid; + g_autoptr(GUsbDevice) device = NULL; + g_autoptr(GUsbDevice) device_new = NULL; /* check args */ - if (g_strv_length (values) != 2) { - g_set_error_literal (error, 1, 0, - "no VID:PID specified"); + if (g_strv_length(values) != 2) { + g_set_error_literal(error, 1, 0, "no VID:PID specified"); return FALSE; } /* get vid:pid */ - vid = g_ascii_strtoull (values0, NULL, 16); - pid = g_ascii_strtoull (values1, NULL, 16); - device = g_usb_context_find_by_vid_pid (priv->usb_ctx, - vid, pid, error); + vid = g_ascii_strtoull(values0, NULL, 16); + pid = g_ascii_strtoull(values1, NULL, 16); + device = g_usb_context_find_by_vid_pid(priv->usb_ctx, vid, pid, error); if (device == NULL) return FALSE; /* watch for debugging */ - g_signal_connect (priv->usb_ctx, "device-added", - G_CALLBACK (gusb_device_list_added_cb), - priv); - g_signal_connect (priv->usb_ctx, "device-removed", - G_CALLBACK (gusb_device_list_removed_cb), - priv); + g_signal_connect(priv->usb_ctx, + "device-added", + G_CALLBACK(gusb_device_list_added_cb), + priv); + g_signal_connect(priv->usb_ctx, + "device-removed", + G_CALLBACK(gusb_device_list_removed_cb), + priv); /* wait for replug */ - device_new = g_usb_context_wait_for_replug (priv->usb_ctx, - device, - 5000, - error); - if (device_new == NULL) + device_new = g_usb_context_wait_for_replug(priv->usb_ctx, device, 5000, error); + return device_new != NULL; +} + +static gboolean +gusb_cmd_load(GUsbCmdPrivate *priv, gchar **values, GError **error) +{ + JsonObject *json_obj; + JsonNode *json_node; + g_autoptr(JsonParser) parser = json_parser_new(); + + /* check args */ + if (g_strv_length(values) != 1) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "no filename specified"); + return FALSE; + } + + /* parse */ + if (!json_parser_load_from_file(parser, values0, error)) + return FALSE; + + /* sanity check */ + json_node = json_parser_get_root(parser); + if (!JSON_NODE_HOLDS_OBJECT(json_node)) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "not a JSON object"); + return FALSE; + } + + /* not supplied */ + json_obj = json_node_get_object(json_node); + if (!g_usb_context_load(priv->usb_ctx, json_obj, error)) return FALSE; - g_object_unref (device); + /* success */ + return gusb_cmd_show(priv, NULL, error); +} + +static gboolean +gusb_cmd_save(GUsbCmdPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *data = NULL; + g_autoptr(JsonBuilder) json_builder = json_builder_new(); + g_autoptr(JsonGenerator) json_generator = NULL; + g_autoptr(JsonNode) json_root = NULL; + + if (!g_usb_context_save(priv->usb_ctx, json_builder, error)) + return FALSE; + + /* export as a string */ + json_root = json_builder_get_root(json_builder); + json_generator = json_generator_new(); + json_generator_set_pretty(json_generator, TRUE); + json_generator_set_root(json_generator, json_root); + data = json_generator_to_data(json_generator, NULL); + if (data == NULL) { + g_set_error_literal(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Failed to convert to JSON string"); + return FALSE; + } + + /* save to file */ + if (g_strv_length(values) == 1) + return g_file_set_contents(values0, data, -1, error); + + /* just print */ + g_print("%s\n", data); return TRUE; } static gboolean -gusb_cmd_run (GUsbCmdPrivate *priv, const gchar *command, gchar **values, GError **error) +gusb_cmd_run(GUsbCmdPrivate *priv, const gchar *command, gchar **values, GError **error) { - gboolean ret = FALSE; - guint i; - GUsbCmdItem *item; - GString *string; + g_autoptr(GString) string = g_string_new(NULL); /* find command */ - for (i = 0; i < priv->cmd_array->len; i++) { - item = g_ptr_array_index (priv->cmd_array, i); - if (g_strcmp0 (item->name, command) == 0) { - ret = item->callback (priv, values, error); - goto out; + for (guint i = 0; i < priv->cmd_array->len; i++) { + GUsbCmdItem *item = g_ptr_array_index(priv->cmd_array, i); + if (g_strcmp0(item->name, command) == 0) { + return item->callback(priv, values, error); } } - /* not found */ - string = g_string_new (""); /* TRANSLATORS: error message */ - g_string_append_printf (string, "%s\n", "Command not found, valid commands are:"); - for (i = 0; i < priv->cmd_array->len; i++) { - item = g_ptr_array_index (priv->cmd_array, i); - g_string_append_printf (string, " * %s\n", item->name); + g_string_append_printf(string, "%s\n", "Command not found, valid commands are:"); + for (guint i = 0; i < priv->cmd_array->len; i++) { + GUsbCmdItem *item = g_ptr_array_index(priv->cmd_array, i); + g_string_append_printf(string, " * %s\n", item->name); } - g_set_error_literal (error, 1, 0, string->str); - g_string_free (string, TRUE); -out: - return ret; + g_set_error_literal(error, 1, 0, string->str); + return FALSE; } -int -main (int argc, char *argv) +static void +gusb_cmd_private_free(GUsbCmdPrivate *priv) { - gboolean ret; - gboolean verbose = FALSE; - gchar *cmd_descriptions = NULL; - gchar *options_help = NULL; - GError *error = NULL; - gint retval = 0; - GUsbCmdPrivate *priv; + if (priv->cmd_array != NULL) + g_ptr_array_unref(priv->cmd_array); + if (priv->usb_ctx != NULL) + g_object_unref(priv->usb_ctx); + g_option_context_free(priv->context); + g_slice_free(GUsbCmdPrivate, priv); +} - const GOptionEntry options = { - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, - "Show extra debugging information", NULL }, - { NULL} - }; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUsbCmdPrivate, gusb_cmd_private_free) - setlocale (LC_ALL, ""); +int +main(int argc, char *argv) +{ + GUsbContextFlags context_flags = G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES; + gboolean verbose = FALSE; + gboolean save_events = FALSE; + g_autofree gchar *cmd_descriptions = NULL; + g_autofree gchar *options_help = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GUsbCmdPrivate) priv = NULL; + + const GOptionEntry options = {{"verbose", + 'v', + 0, + G_OPTION_ARG_NONE, + &verbose, + "Show extra debugging information", + NULL}, + {"events", + '\0', + 0, + G_OPTION_ARG_NONE, + &save_events, + "Save USB events", + NULL}, + {NULL}}; + + setlocale(LC_ALL, ""); /* create helper object */ - priv = g_slice_new0 (GUsbCmdPrivate); - - priv->context = g_option_context_new ("GUSB Console Program"); - g_option_context_add_main_entries (priv->context, options, NULL); - if (!g_option_context_parse (priv->context, &argc, &argv, &error)) { - g_printerr ("Failed to parse arguments: %s\n", error->message); - g_error_free (error); - retval = 2; - goto out; + priv = g_slice_new0(GUsbCmdPrivate); + priv->context = g_option_context_new("GUSB Console Program"); + g_option_context_add_main_entries(priv->context, options, NULL); + if (!g_option_context_parse(priv->context, &argc, &argv, &error)) { + g_printerr("Failed to parse arguments: %s\n", error->message); + return 2; } /* verbose? */ if (verbose) { - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); - g_log_set_handler ("GUsb", G_LOG_LEVEL_ERROR | - G_LOG_LEVEL_CRITICAL | - G_LOG_LEVEL_DEBUG | - G_LOG_LEVEL_WARNING, - gusb_log_handler_cb, NULL); + g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_log_set_handler("GUsb", + G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG | + G_LOG_LEVEL_WARNING, + gusb_log_handler_cb, + NULL); } else { /* hide all debugging */ - g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); - g_log_set_handler ("GUsb", G_LOG_LEVEL_DEBUG, - gusb_log_ignore_cb, NULL); + g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_log_set_handler("GUsb", G_LOG_LEVEL_DEBUG, gusb_log_ignore_cb, NULL); } /* GUsbContext */ - priv->usb_ctx = g_usb_context_new (NULL); - g_usb_context_set_flags (priv->usb_ctx, G_USB_CONTEXT_FLAGS_AUTO_OPEN_DEVICES); + priv->usb_ctx = g_usb_context_new(NULL); + if (save_events) + context_flags |= G_USB_CONTEXT_FLAGS_SAVE_EVENTS; + if (verbose) + context_flags |= G_USB_CONTEXT_FLAGS_DEBUG; + g_usb_context_set_flags(priv->usb_ctx, context_flags); /* add commands */ - priv->cmd_array = g_ptr_array_new_with_free_func ((GDestroyNotify) gusb_cmd_item_free); - gusb_cmd_add (priv->cmd_array, - "show", - "Show currently connected devices", - gusb_cmd_show); - gusb_cmd_add (priv->cmd_array, - "watch", - "Watch devices as they come and go", - gusb_cmd_watch); - gusb_cmd_add (priv->cmd_array, - "replug", - "Watch a device as it reconnects", - gusb_cmd_replug); + priv->cmd_array = g_ptr_array_new_with_free_func((GDestroyNotify)gusb_cmd_item_free); + gusb_cmd_add(priv->cmd_array, "show", "Show currently connected devices", gusb_cmd_show); + gusb_cmd_add(priv->cmd_array, "watch", "Watch devices as they come and go", gusb_cmd_watch); + gusb_cmd_add(priv->cmd_array, "replug", "Watch a device as it reconnects", gusb_cmd_replug); + gusb_cmd_add(priv->cmd_array, "load", "Load a set of devices from JSON", gusb_cmd_load); + gusb_cmd_add(priv->cmd_array, "save", "Save a set of devices to JSON", gusb_cmd_save); /* sort by command name */ - g_ptr_array_sort (priv->cmd_array, - (GCompareFunc) gusb_sort_command_name_cb); + g_ptr_array_sort(priv->cmd_array, (GCompareFunc)gusb_sort_command_name_cb); /* get a list of the commands */ - cmd_descriptions = gusb_cmd_get_descriptions (priv->cmd_array); - g_option_context_set_summary (priv->context, cmd_descriptions); + cmd_descriptions = gusb_cmd_get_descriptions(priv->cmd_array); + g_option_context_set_summary(priv->context, cmd_descriptions); /* nothing specified */ if (argc < 2) { - options_help = g_option_context_get_help (priv->context, TRUE, NULL); - g_print ("%s", options_help); - goto out; + options_help = g_option_context_get_help(priv->context, TRUE, NULL); + g_print("%s", options_help); + return 1; } /* run the specified command */ - ret = gusb_cmd_run (priv, argv1, (gchar**) &argv2, &error); - if (!ret) { - g_print ("%s\n", error->message); - g_error_free (error); - retval = 1; - goto out; - } -out: - if (priv != NULL) { - if (priv->cmd_array != NULL) - g_ptr_array_unref (priv->cmd_array); - if (priv->usb_ctx != NULL) - g_object_unref (priv->usb_ctx); - g_option_context_free (priv->context); - g_slice_free (GUsbCmdPrivate, priv); + if (!gusb_cmd_run(priv, argv1, (gchar **)&argv2, &error)) { + g_print("%s\n", error->message); + return 1; } - /* free state */ - g_free (options_help); - g_free (cmd_descriptions); - return retval; + /* success */ + return 0; }
View file
_service:tar_scm:libgusb-0.3.10.tar.xz/tools/meson.build -> _service:tar_scm:libgusb-0.4.6.tar.xz/tools/meson.build
Changed
@@ -12,6 +12,7 @@ dependencies : libgio, libusb, + libjsonglib, , link_with : gusb, c_args :
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2