/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2020 Emmanuel Pacaud * * SPDX-License-Identifier: LGPL-2.1+ */ /** * SECTION:gusb-endpoint * @short_description: GLib wrapper around a USB endpoint. * * This object is a thin glib wrapper around a libusb_endpoint_descriptor. * * All the data is copied when the object is created and the original * descriptor can be destroyed any at point. */ #include "config.h" #include #include "gusb-endpoint-private.h" #include "gusb-json-common.h" struct _GUsbEndpoint { GObject parent_instance; struct libusb_endpoint_descriptor endpoint_descriptor; GBytes *extra; }; G_DEFINE_TYPE(GUsbEndpoint, g_usb_endpoint, G_TYPE_OBJECT) static void g_usb_endpoint_finalize(GObject *object) { GUsbEndpoint *self = G_USB_ENDPOINT(object); g_bytes_unref(self->extra); G_OBJECT_CLASS(g_usb_endpoint_parent_class)->finalize(object); } static void g_usb_endpoint_class_init(GUsbEndpointClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = g_usb_endpoint_finalize; } static void 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; } /** * _g_usb_endpoint_new: * * Return value: a new #GUsbEndpoint object. * * Since: 0.3.3 **/ GUsbEndpoint * _g_usb_endpoint_new(const struct libusb_endpoint_descriptor *endpoint_descriptor) { GUsbEndpoint *self; self = g_object_new(G_USB_TYPE_ENDPOINT, NULL); /* copy the data */ 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(self); } /** * g_usb_endpoint_get_kind: * @self: a #GUsbEndpoint * * Gets the type of endpoint. * * Return value: The 8-bit type * * Since: 0.3.3 **/ guint8 g_usb_endpoint_get_kind(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return self->endpoint_descriptor.bDescriptorType; } /** * g_usb_endpoint_get_maximum_packet_size: * @self: a #GUsbEndpoint * * Gets the maximum packet size this endpoint is capable of sending/receiving. * * Return value: The maximum packet size * * Since: 0.3.3 **/ guint16 g_usb_endpoint_get_maximum_packet_size(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return self->endpoint_descriptor.wMaxPacketSize; } /** * g_usb_endpoint_get_polling_interval: * @self: a #GUsbEndpoint * * Gets the endpoint polling interval. * * Return value: The endpoint polling interval * * Since: 0.3.3 **/ guint8 g_usb_endpoint_get_polling_interval(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return self->endpoint_descriptor.bInterval; } /** * g_usb_endpoint_get_refresh: * @self: a #GUsbEndpoint * * Gets the rate at which synchronization feedback is provided, for audio device only. * * Return value: The endpoint refresh * * Since: 0.3.3 **/ guint8 g_usb_endpoint_get_refresh(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return self->endpoint_descriptor.bRefresh; } /** * g_usb_endpoint_get_synch_address: * @self: a #GUsbEndpoint * * Gets the address if the synch endpoint, for audio device only. * * Return value: The synch endpoint address * * Since: 0.3.3 **/ guint8 g_usb_endpoint_get_synch_address(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return self->endpoint_descriptor.bSynchAddress; } /** * g_usb_endpoint_get_address: * @self: a #GUsbEndpoint * * Gets the address of the endpoint. * * Return value: The 4-bit endpoint address * * Since: 0.3.3 **/ guint8 g_usb_endpoint_get_address(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return self->endpoint_descriptor.bEndpointAddress; } /** * g_usb_endpoint_get_number: * @self: a #GUsbEndpoint * * Gets the number part of endpoint address. * * Return value: The lower 4-bit of endpoint address * * Since: 0.3.3 **/ guint8 g_usb_endpoint_get_number(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), 0); return (self->endpoint_descriptor.bEndpointAddress) & 0xf; } /** * g_usb_endpoint_get_direction: * @self: a #GUsbEndpoint * * Gets the direction of the endpoint. * * Return value: The endpoint direction * * Since: 0.3.3 **/ GUsbDeviceDirection g_usb_endpoint_get_direction(GUsbEndpoint *self) { 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: * @self: a #GUsbEndpoint * * Gets any extra data from the endpoint. * * Return value: (transfer none): a #GBytes, or %NULL for failure * * Since: 0.3.3 **/ GBytes * g_usb_endpoint_get_extra(GUsbEndpoint *self) { g_return_val_if_fail(G_USB_IS_ENDPOINT(self), NULL); return self->extra; }