api,manager: new InhibitDevice() method
This new method allows users of the ModemManager API to take full control of a given device. Unlike other operations in the API, the inhibition is maintained as long as the caller exists in the bus, or until the same caller uninhibits the device. https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/98
This commit is contained in:
@@ -56,6 +56,7 @@ static gboolean list_modems_flag;
|
|||||||
static gboolean monitor_modems_flag;
|
static gboolean monitor_modems_flag;
|
||||||
static gboolean scan_modems_flag;
|
static gboolean scan_modems_flag;
|
||||||
static gchar *set_logging_str;
|
static gchar *set_logging_str;
|
||||||
|
static gchar *inhibit_device_str;
|
||||||
static gchar *report_kernel_event_str;
|
static gchar *report_kernel_event_str;
|
||||||
|
|
||||||
#if defined WITH_UDEV
|
#if defined WITH_UDEV
|
||||||
@@ -83,6 +84,10 @@ static GOptionEntry entries[] = {
|
|||||||
"Request to re-scan looking for modems",
|
"Request to re-scan looking for modems",
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
{ "inhibit-device", 'I', 0, G_OPTION_ARG_STRING, &inhibit_device_str,
|
||||||
|
"Inhibit device given a unique device identifier",
|
||||||
|
"[UID]"
|
||||||
|
},
|
||||||
{ "report-kernel-event", 'K', 0, G_OPTION_ARG_STRING, &report_kernel_event_str,
|
{ "report-kernel-event", 'K', 0, G_OPTION_ARG_STRING, &report_kernel_event_str,
|
||||||
"Report kernel event",
|
"Report kernel event",
|
||||||
"[\"key=value,...\"]"
|
"[\"key=value,...\"]"
|
||||||
@@ -126,6 +131,7 @@ mmcli_manager_options_enabled (void)
|
|||||||
monitor_modems_flag +
|
monitor_modems_flag +
|
||||||
scan_modems_flag +
|
scan_modems_flag +
|
||||||
!!set_logging_str +
|
!!set_logging_str +
|
||||||
|
!!inhibit_device_str +
|
||||||
!!report_kernel_event_str);
|
!!report_kernel_event_str);
|
||||||
|
|
||||||
#if defined WITH_UDEV
|
#if defined WITH_UDEV
|
||||||
@@ -145,7 +151,8 @@ mmcli_manager_options_enabled (void)
|
|||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
mmcli_force_async_operation ();
|
mmcli_force_async_operation ();
|
||||||
}
|
} else if (inhibit_device_str)
|
||||||
|
mmcli_force_async_operation ();
|
||||||
|
|
||||||
#if defined WITH_UDEV
|
#if defined WITH_UDEV
|
||||||
if (report_kernel_event_auto_scan)
|
if (report_kernel_event_auto_scan)
|
||||||
@@ -180,6 +187,41 @@ mmcli_manager_shutdown (void)
|
|||||||
context_free (ctx);
|
context_free (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibition_cancelled (GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!mm_manager_uninhibit_device_sync (ctx->manager, inhibit_device_str, NULL, &error)) {
|
||||||
|
g_printerr ("error: couldn't uninhibit device: '%s'\n",
|
||||||
|
error ? error->message : "unknown error");
|
||||||
|
} else
|
||||||
|
g_print ("successfully uninhibited device with uid '%s'\n", inhibit_device_str);
|
||||||
|
|
||||||
|
mmcli_async_operation_done ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_device_ready (MMManager *manager,
|
||||||
|
GAsyncResult *result)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!mm_manager_inhibit_device_finish (manager, result, &error)) {
|
||||||
|
g_printerr ("error: couldn't inhibit device: '%s'\n",
|
||||||
|
error ? error->message : "unknown error");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("successfully inhibited device with uid '%s'\n", inhibit_device_str);
|
||||||
|
g_print ("type Ctrl+C to abort this program and remove the inhibition\n");
|
||||||
|
|
||||||
|
g_cancellable_connect (ctx->cancellable,
|
||||||
|
G_CALLBACK (inhibition_cancelled),
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
report_kernel_event_process_reply (gboolean result,
|
report_kernel_event_process_reply (gboolean result,
|
||||||
const GError *error)
|
const GError *error)
|
||||||
@@ -463,6 +505,16 @@ get_manager_ready (GObject *source,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Request to inhibit device? */
|
||||||
|
if (inhibit_device_str) {
|
||||||
|
mm_manager_inhibit_device (ctx->manager,
|
||||||
|
inhibit_device_str,
|
||||||
|
ctx->cancellable,
|
||||||
|
(GAsyncReadyCallback)inhibit_device_ready,
|
||||||
|
NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_warn_if_reached ();
|
g_warn_if_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,12 @@ mm_manager_get_version
|
|||||||
mm_manager_scan_devices
|
mm_manager_scan_devices
|
||||||
mm_manager_scan_devices_finish
|
mm_manager_scan_devices_finish
|
||||||
mm_manager_scan_devices_sync
|
mm_manager_scan_devices_sync
|
||||||
|
mm_manager_inhibit_device
|
||||||
|
mm_manager_inhibit_device_finish
|
||||||
|
mm_manager_inhibit_device_sync
|
||||||
|
mm_manager_uninhibit_device
|
||||||
|
mm_manager_uninhibit_device_finish
|
||||||
|
mm_manager_uninhibit_device_sync
|
||||||
mm_manager_set_logging
|
mm_manager_set_logging
|
||||||
mm_manager_set_logging_finish
|
mm_manager_set_logging_finish
|
||||||
mm_manager_set_logging_sync
|
mm_manager_set_logging_sync
|
||||||
@@ -1731,6 +1737,9 @@ mm_gdbus_org_freedesktop_modem_manager1_get_version
|
|||||||
mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices
|
mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices_finish
|
mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices_finish
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices_sync
|
mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices_sync
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_call_inhibit_device
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_call_inhibit_device_finish
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_call_inhibit_device_sync
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging
|
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging_finish
|
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging_finish
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging_sync
|
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging_sync
|
||||||
@@ -1740,6 +1749,7 @@ mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event_sync
|
|||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_set_version
|
mm_gdbus_org_freedesktop_modem_manager1_set_version
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_override_properties
|
mm_gdbus_org_freedesktop_modem_manager1_override_properties
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_complete_inhibit_device
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_complete_scan_devices
|
mm_gdbus_org_freedesktop_modem_manager1_complete_scan_devices
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_complete_set_logging
|
mm_gdbus_org_freedesktop_modem_manager1_complete_set_logging
|
||||||
mm_gdbus_org_freedesktop_modem_manager1_complete_report_kernel_event
|
mm_gdbus_org_freedesktop_modem_manager1_complete_report_kernel_event
|
||||||
|
@@ -106,6 +106,27 @@
|
|||||||
<arg name="properties" type="a{sv}" direction="in" />
|
<arg name="properties" type="a{sv}" direction="in" />
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
InhibitDevice:
|
||||||
|
@uid: the unique ID of the physical device, given in the
|
||||||
|
#org.freedesktop.ModemManager1.Modem:Device property.
|
||||||
|
@inhibit: %TRUE to inhibit the modem and %FALSE to uninhibit it.
|
||||||
|
|
||||||
|
Inhibit or uninhibit the device.
|
||||||
|
|
||||||
|
When the modem is inhibited ModemManager will close all its ports and
|
||||||
|
unexport it from the bus, so that users of the interface are no longer
|
||||||
|
able to operate with it.
|
||||||
|
|
||||||
|
This operation binds the inhibition request to the existence of the
|
||||||
|
caller in the DBus bus. If the caller disappears from the bus, the
|
||||||
|
inhibition will automatically removed.
|
||||||
|
-->
|
||||||
|
<method name="InhibitDevice">
|
||||||
|
<arg name="uid" type="s" direction="in" />
|
||||||
|
<arg name="inhibit" type="b" direction="in" />
|
||||||
|
</method>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Version:
|
Version:
|
||||||
|
|
||||||
|
@@ -638,6 +638,242 @@ mm_manager_report_kernel_event_sync (MMManager *manager,
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
common_inhibit_device_finish (MMManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_ready (MmGdbusOrgFreedesktopModemManager1 *manager_iface_proxy,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!mm_gdbus_org_freedesktop_modem_manager1_call_inhibit_device_finish (manager_iface_proxy, res, &error))
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
else
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_inhibit_device (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
gboolean inhibit,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task;
|
||||||
|
GError *inner_error = NULL;
|
||||||
|
|
||||||
|
task = g_task_new (manager, cancellable, callback, user_data);
|
||||||
|
|
||||||
|
if (!ensure_modem_manager1_proxy (manager, &inner_error)) {
|
||||||
|
g_task_return_error (task, inner_error);
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_call_inhibit_device (
|
||||||
|
manager->priv->manager_iface_proxy,
|
||||||
|
uid,
|
||||||
|
inhibit,
|
||||||
|
cancellable,
|
||||||
|
(GAsyncReadyCallback)inhibit_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
common_inhibit_device_sync (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
gboolean inhibit,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
if (!ensure_modem_manager1_proxy (manager, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return (mm_gdbus_org_freedesktop_modem_manager1_call_inhibit_device_sync (
|
||||||
|
manager->priv->manager_iface_proxy,
|
||||||
|
uid,
|
||||||
|
inhibit,
|
||||||
|
cancellable,
|
||||||
|
error));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mm_manager_inhibit_device_finish:
|
||||||
|
* @manager: A #MMManager.
|
||||||
|
* @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_manager_inhibit_device().
|
||||||
|
* @error: Return location for error or %NULL.
|
||||||
|
*
|
||||||
|
* Finishes an operation started with mm_manager_inhibit_device().
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the call succeeded, %FALSE if @error is set.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
mm_manager_inhibit_device_finish (MMManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (MM_IS_MANAGER (manager), FALSE);
|
||||||
|
return common_inhibit_device_finish (manager, res, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mm_manager_inhibit_device:
|
||||||
|
* @manager: A #MMManager.
|
||||||
|
* @uid: the unique ID of the physical device.
|
||||||
|
* @cancellable: (allow-none): A #GCancellable or %NULL.
|
||||||
|
* @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
|
||||||
|
* @user_data: User data to pass to @callback.
|
||||||
|
*
|
||||||
|
* Asynchronously requests to add an inhibition on the device identified by @uid.
|
||||||
|
*
|
||||||
|
* The @uid must be the unique ID retrieved from an existing #MMModem using
|
||||||
|
* mm_modem_get_device(). The caller should keep track of this @uid and use it
|
||||||
|
* in the mm_manager_uninhibit_device() call when the inhibition is no longer required.
|
||||||
|
*
|
||||||
|
* The inhibition added with this method may also be automatically removed when
|
||||||
|
* the caller program disappears from the bus (e.g. if the program ends before
|
||||||
|
* having called mm_manager_uninhibit_device() explicitly).
|
||||||
|
*
|
||||||
|
* When the operation is finished, @callback will be invoked in the
|
||||||
|
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
|
||||||
|
* of the thread you are calling this method from. You can then call
|
||||||
|
* mm_manager_inhibit_device_finish() to get the result of the operation.
|
||||||
|
*
|
||||||
|
* See mm_manager_inhibit_device_sync() for the synchronous, blocking version of this method.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mm_manager_inhibit_device (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_return_if_fail (MM_IS_MANAGER (manager));
|
||||||
|
common_inhibit_device (manager, uid, TRUE, cancellable, callback, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mm_manager_inhibit_device_sync:
|
||||||
|
* @manager: A #MMManager.
|
||||||
|
* @uid: the unique ID of the physical device.
|
||||||
|
* @cancellable: (allow-none): A #GCancellable or %NULL.
|
||||||
|
* @error: Return location for error or %NULL.
|
||||||
|
*
|
||||||
|
* Synchronously requests to add an inhibition on the device identified by @uid.
|
||||||
|
*
|
||||||
|
* The @uid must be the unique ID retrieved from an existing #MMModem using
|
||||||
|
* mm_modem_get_device(). The caller should keep track of this @uid and use it
|
||||||
|
* in the mm_manager_uninhibit_device_sync() call when the inhibition is no longer required.
|
||||||
|
*
|
||||||
|
* The inhibition added with this method may also be automatically removed when
|
||||||
|
* the caller program disappears from the bus (e.g. if the program ends before
|
||||||
|
* having called mm_manager_uninhibit_device_sync() explicitly).
|
||||||
|
*
|
||||||
|
* See mm_manager_inhibit_device() for the asynchronous version of this method.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the call succeeded, %FALSE if @error is set.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
mm_manager_inhibit_device_sync (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (MM_IS_MANAGER (manager), FALSE);
|
||||||
|
return common_inhibit_device_sync (manager, uid, TRUE, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mm_manager_uninhibit_device_finish:
|
||||||
|
* @manager: A #MMManager.
|
||||||
|
* @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_manager_uninhibit_device().
|
||||||
|
* @error: Return location for error or %NULL.
|
||||||
|
*
|
||||||
|
* Finishes an operation started with mm_manager_uninhibit_device().
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the call succeeded, %FALSE if @error is set.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
mm_manager_uninhibit_device_finish (MMManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (MM_IS_MANAGER (manager), FALSE);
|
||||||
|
return common_inhibit_device_finish (manager, res, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mm_manager_uninhibit_device:
|
||||||
|
* @manager: A #MMManager.
|
||||||
|
* @uid: the unique ID of the physical device.
|
||||||
|
* @cancellable: (allow-none): A #GCancellable or %NULL.
|
||||||
|
* @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
|
||||||
|
* @user_data: User data to pass to @callback.
|
||||||
|
*
|
||||||
|
* Asynchronously requests to remove an inhibition on the device identified by @uid.
|
||||||
|
*
|
||||||
|
* The @uid must be the same unique ID that was sent in the inhibition request.
|
||||||
|
*
|
||||||
|
* Only the same program that placed an inhibition on a given device is able to remove
|
||||||
|
* the inhibition.
|
||||||
|
*
|
||||||
|
* When the operation is finished, @callback will be invoked in the
|
||||||
|
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
|
||||||
|
* of the thread you are calling this method from. You can then call
|
||||||
|
* mm_manager_uninhibit_device_finish() to get the result of the operation.
|
||||||
|
*
|
||||||
|
* See mm_manager_uninhibit_device_sync() for the synchronous, blocking version of this method.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mm_manager_uninhibit_device (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_return_if_fail (MM_IS_MANAGER (manager));
|
||||||
|
common_inhibit_device (manager, uid, FALSE, cancellable, callback, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mm_manager_uninhibit_device_sync:
|
||||||
|
* @manager: A #MMManager.
|
||||||
|
* @uid: the unique ID of the physical device.
|
||||||
|
* @cancellable: (allow-none): A #GCancellable or %NULL.
|
||||||
|
* @error: Return location for error or %NULL.
|
||||||
|
*
|
||||||
|
* Synchronously requests to remove an inhibition on the device identified by @uid.
|
||||||
|
*
|
||||||
|
* The @uid must be the same unique ID that was sent in the inhibition request.
|
||||||
|
*
|
||||||
|
* Only the same program that placed an inhibition on a given device is able to remove
|
||||||
|
* the inhibition.
|
||||||
|
*
|
||||||
|
* See mm_manager_uninhibit_device() for the asynchronous version of this method.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the call succeeded, %FALSE if @error is set.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
mm_manager_uninhibit_device_sync (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (MM_IS_MANAGER (manager), FALSE);
|
||||||
|
return common_inhibit_device_sync (manager, uid, FALSE, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
register_dbus_errors (void)
|
register_dbus_errors (void)
|
||||||
{
|
{
|
||||||
|
@@ -128,6 +128,32 @@ gboolean mm_manager_report_kernel_event_sync (MMManager *manage
|
|||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
void mm_manager_inhibit_device (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_manager_inhibit_device_finish (MMManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
gboolean mm_manager_inhibit_device_sync (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void mm_manager_uninhibit_device (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_manager_uninhibit_device_finish (MMManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
gboolean mm_manager_uninhibit_device_sync (MMManager *manager,
|
||||||
|
const gchar *uid,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* _MM_MANAGER_H_ */
|
#endif /* _MM_MANAGER_H_ */
|
||||||
|
@@ -87,6 +87,8 @@ struct _MMBaseManagerPrivate {
|
|||||||
GHashTable *devices;
|
GHashTable *devices;
|
||||||
/* The Object Manager server */
|
/* The Object Manager server */
|
||||||
GDBusObjectManagerServer *object_manager;
|
GDBusObjectManagerServer *object_manager;
|
||||||
|
/* The map of inhibited devices */
|
||||||
|
GHashTable *inhibited_devices;
|
||||||
|
|
||||||
/* The Test interface support */
|
/* The Test interface support */
|
||||||
MmGdbusTest *test_skeleton;
|
MmGdbusTest *test_skeleton;
|
||||||
@@ -205,6 +207,15 @@ device_support_check_ready (MMPluginManager *plugin_manager,
|
|||||||
find_device_support_context_free (ctx);
|
find_device_support_context_free (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean is_device_inhibited (MMBaseManager *self,
|
||||||
|
const gchar *physdev_uid);
|
||||||
|
static void device_inhibited_track_port (MMBaseManager *self,
|
||||||
|
const gchar *physdev_uid,
|
||||||
|
MMKernelDevice *port,
|
||||||
|
gboolean manual_scan);
|
||||||
|
static void device_inhibited_untrack_port (MMBaseManager *self,
|
||||||
|
MMKernelDevice *port);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
device_removed (MMBaseManager *self,
|
device_removed (MMBaseManager *self,
|
||||||
MMKernelDevice *kernel_device)
|
MMKernelDevice *kernel_device)
|
||||||
@@ -246,8 +257,14 @@ device_removed (MMBaseManager *self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_object_unref (device);
|
g_object_unref (device);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the device was inhibited and the port is gone, untrack it.
|
||||||
|
* This is only needed for ports that were tracked out of device objects.
|
||||||
|
* In this case we don't rely on the physdev uid, as API-reported
|
||||||
|
* remove kernel events may not include uid. */
|
||||||
|
device_inhibited_untrack_port (self, kernel_device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,6 +335,20 @@ device_added (MMBaseManager *manager,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the port's physical device's uid. All ports of the same physical
|
||||||
|
* device will share the same uid. */
|
||||||
|
physdev_uid = mm_kernel_device_get_physdev_uid (port);
|
||||||
|
g_assert (physdev_uid);
|
||||||
|
|
||||||
|
/* If the device is inhibited, do nothing else */
|
||||||
|
if (is_device_inhibited (manager, physdev_uid)) {
|
||||||
|
/* Note: we will not report as hotplugged an inhibited device port
|
||||||
|
* because we don't know what was done with the port out of our
|
||||||
|
* context. */
|
||||||
|
device_inhibited_track_port (manager, physdev_uid, port, manual_scan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Run port filter */
|
/* Run port filter */
|
||||||
if (!mm_filter_port (manager->priv->filter, port, manual_scan))
|
if (!mm_filter_port (manager->priv->filter, port, manual_scan))
|
||||||
return;
|
return;
|
||||||
@@ -328,11 +359,6 @@ device_added (MMBaseManager *manager,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the port's physical device's uid. All ports of the same physical
|
|
||||||
* device will share the same uid. */
|
|
||||||
physdev_uid = mm_kernel_device_get_physdev_uid (port);
|
|
||||||
g_assert (physdev_uid);
|
|
||||||
|
|
||||||
/* See if we already created an object to handle ports in this device */
|
/* See if we already created an object to handle ports in this device */
|
||||||
device = find_device_by_physdev_uid (manager, physdev_uid);
|
device = find_device_by_physdev_uid (manager, physdev_uid);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
@@ -898,6 +924,333 @@ handle_report_kernel_event (MmGdbusOrgFreedesktopModemManager1 *manager,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Inhibit or uninhibit device */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMKernelDevice *kernel_port;
|
||||||
|
gboolean manual_scan;
|
||||||
|
} InhibitedDevicePortInfo;
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibited_device_port_info_free (InhibitedDevicePortInfo *port_info)
|
||||||
|
{
|
||||||
|
g_object_unref (port_info->kernel_port);
|
||||||
|
g_slice_free (InhibitedDevicePortInfo, port_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gchar *sender;
|
||||||
|
guint name_lost_id;
|
||||||
|
GList *port_infos;
|
||||||
|
} InhibitedDeviceInfo;
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibited_device_info_free (InhibitedDeviceInfo *info)
|
||||||
|
{
|
||||||
|
g_list_free_full (info->port_infos, (GDestroyNotify)inhibited_device_port_info_free);
|
||||||
|
g_bus_unwatch_name (info->name_lost_id);
|
||||||
|
g_free (info->sender);
|
||||||
|
g_slice_free (InhibitedDeviceInfo, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static InhibitedDeviceInfo *
|
||||||
|
find_inhibited_device_info_by_physdev_uid (MMBaseManager *self,
|
||||||
|
const gchar *physdev_uid)
|
||||||
|
{
|
||||||
|
return (physdev_uid ? g_hash_table_lookup (self->priv->inhibited_devices, physdev_uid) : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_device_inhibited (MMBaseManager *self,
|
||||||
|
const gchar *physdev_uid)
|
||||||
|
{
|
||||||
|
return !!find_inhibited_device_info_by_physdev_uid (self, physdev_uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
device_inhibited_untrack_port (MMBaseManager *self,
|
||||||
|
MMKernelDevice *kernel_port)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
gchar *uid;
|
||||||
|
InhibitedDeviceInfo *info;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, self->priv->inhibited_devices);
|
||||||
|
while (g_hash_table_iter_next (&iter, (gpointer)&uid, (gpointer)&info)) {
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
for (l = info->port_infos; l; l = g_list_next (l)) {
|
||||||
|
InhibitedDevicePortInfo *port_info;
|
||||||
|
|
||||||
|
port_info = (InhibitedDevicePortInfo *)(l->data);
|
||||||
|
if (mm_kernel_device_cmp (port_info->kernel_port, kernel_port)) {
|
||||||
|
mm_dbg ("(%s/%s): released while inhibited",
|
||||||
|
mm_kernel_device_get_subsystem (kernel_port),
|
||||||
|
mm_kernel_device_get_name (kernel_port));
|
||||||
|
inhibited_device_port_info_free (port_info);
|
||||||
|
info->port_infos = g_list_delete_link (info->port_infos, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
device_inhibited_track_port (MMBaseManager *self,
|
||||||
|
const gchar *physdev_uid,
|
||||||
|
MMKernelDevice *kernel_port,
|
||||||
|
gboolean manual_scan)
|
||||||
|
{
|
||||||
|
InhibitedDevicePortInfo *port_info;
|
||||||
|
InhibitedDeviceInfo *info;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
info = find_inhibited_device_info_by_physdev_uid (self, physdev_uid);
|
||||||
|
g_assert (info);
|
||||||
|
|
||||||
|
for (l = info->port_infos; l; l = g_list_next (l)) {
|
||||||
|
/* If device is already tracked, just overwrite the manual scan info */
|
||||||
|
port_info = (InhibitedDevicePortInfo *)(l->data);
|
||||||
|
if (mm_kernel_device_cmp (port_info->kernel_port, kernel_port)) {
|
||||||
|
port_info->manual_scan = manual_scan;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_dbg ("(%s/%s): added while inhibited",
|
||||||
|
mm_kernel_device_get_subsystem (kernel_port),
|
||||||
|
mm_kernel_device_get_name (kernel_port));
|
||||||
|
|
||||||
|
port_info = g_slice_new0 (InhibitedDevicePortInfo);
|
||||||
|
port_info->kernel_port = g_object_ref (kernel_port);
|
||||||
|
port_info->manual_scan = manual_scan;
|
||||||
|
info->port_infos = g_list_append (info->port_infos, port_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBaseManager *self;
|
||||||
|
gchar *uid;
|
||||||
|
} InhibitSenderLostContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_sender_lost_context_free (InhibitSenderLostContext *lost_ctx)
|
||||||
|
{
|
||||||
|
g_free (lost_ctx->uid);
|
||||||
|
g_slice_free (InhibitSenderLostContext, lost_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_device_inhibition (MMBaseManager *self,
|
||||||
|
const gchar *uid)
|
||||||
|
{
|
||||||
|
InhibitedDeviceInfo *info;
|
||||||
|
MMDevice *device;
|
||||||
|
GList *port_infos;
|
||||||
|
|
||||||
|
info = find_inhibited_device_info_by_physdev_uid (self, uid);
|
||||||
|
g_assert (info);
|
||||||
|
|
||||||
|
device = find_device_by_physdev_uid (self, uid);
|
||||||
|
port_infos = info->port_infos;
|
||||||
|
info->port_infos = NULL;
|
||||||
|
g_hash_table_remove (self->priv->inhibited_devices, uid);
|
||||||
|
|
||||||
|
if (port_infos) {
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
/* Note that a device can only be inhibited if it had an existing
|
||||||
|
* modem exposed in the bus. And so, inhibition can only be placed
|
||||||
|
* AFTER all port probes have finished for a given device. This means
|
||||||
|
* that we either have a device tracked, or we have a list of port
|
||||||
|
* infos. Both at the same time should never happen. */
|
||||||
|
g_assert (!device);
|
||||||
|
|
||||||
|
/* Report as added all port infos that we had tracked while the
|
||||||
|
* device was inhibited. We can only report the added port after
|
||||||
|
* having removed the entry from the inhibited devices tracking
|
||||||
|
* table. */
|
||||||
|
for (l = port_infos; l; l = g_list_next (l)) {
|
||||||
|
InhibitedDevicePortInfo *port_info;
|
||||||
|
|
||||||
|
port_info = (InhibitedDevicePortInfo *)(l->data);
|
||||||
|
device_added (self, port_info->kernel_port, FALSE, port_info->manual_scan);
|
||||||
|
}
|
||||||
|
g_list_free_full (port_infos, (GDestroyNotify)inhibited_device_port_info_free);
|
||||||
|
}
|
||||||
|
/* The device may be totally gone from the system while we were
|
||||||
|
* keeping the inhibition, so do not error out if not found. */
|
||||||
|
else if (device) {
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
/* Uninhibit device, which will create and expose the modem object */
|
||||||
|
if (!mm_device_uninhibit (device, self->priv->object_manager, &error)) {
|
||||||
|
mm_warn ("Couldn't uninhibit device: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_sender_lost (GDBusConnection *connection,
|
||||||
|
const gchar *sender_name,
|
||||||
|
InhibitSenderLostContext *lost_ctx)
|
||||||
|
{
|
||||||
|
mm_info ("Device inhibition teardown for uid '%s' (owner disappeared from bus)", lost_ctx->uid);
|
||||||
|
remove_device_inhibition (lost_ctx->self, lost_ctx->uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBaseManager *self;
|
||||||
|
GDBusMethodInvocation *invocation;
|
||||||
|
gchar *uid;
|
||||||
|
gboolean inhibit;
|
||||||
|
} InhibitDeviceContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_device_context_free (InhibitDeviceContext *ctx)
|
||||||
|
{
|
||||||
|
g_object_unref (ctx->invocation);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_free (ctx->uid);
|
||||||
|
g_slice_free (InhibitDeviceContext, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
device_inhibit_ready (MMDevice *device,
|
||||||
|
GAsyncResult *res,
|
||||||
|
InhibitDeviceContext *ctx)
|
||||||
|
{
|
||||||
|
InhibitSenderLostContext *lost_ctx;
|
||||||
|
InhibitedDeviceInfo *info;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!mm_device_inhibit_finish (device, res, &error)) {
|
||||||
|
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = g_slice_new0 (InhibitedDeviceInfo);
|
||||||
|
info->sender = g_strdup (g_dbus_method_invocation_get_sender (ctx->invocation));
|
||||||
|
|
||||||
|
/* This context will exist as long as the sender name watcher exists,
|
||||||
|
* i.e. as long as the associated InhibitDeviceInfo exists. We don't need
|
||||||
|
* an extra reference of self here because these contexts are stored within
|
||||||
|
* self, and therefore bound to its lifetime. */
|
||||||
|
lost_ctx = g_slice_new0 (InhibitSenderLostContext);
|
||||||
|
lost_ctx->self = ctx->self;
|
||||||
|
lost_ctx->uid = g_strdup (ctx->uid);
|
||||||
|
info->name_lost_id = g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (ctx->invocation),
|
||||||
|
info->sender,
|
||||||
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||||
|
NULL,
|
||||||
|
(GBusNameVanishedCallback)inhibit_sender_lost,
|
||||||
|
lost_ctx,
|
||||||
|
(GDestroyNotify)inhibit_sender_lost_context_free);
|
||||||
|
|
||||||
|
g_hash_table_insert (ctx->self->priv->inhibited_devices, g_strdup (ctx->uid), info);
|
||||||
|
|
||||||
|
mm_info ("Device inhibition setup for uid '%s'", ctx->uid);
|
||||||
|
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_complete_inhibit_device (
|
||||||
|
MM_GDBUS_ORG_FREEDESKTOP_MODEM_MANAGER1 (ctx->self),
|
||||||
|
ctx->invocation);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
base_manager_inhibit_device (InhibitDeviceContext *ctx)
|
||||||
|
{
|
||||||
|
MMDevice *device;
|
||||||
|
|
||||||
|
device = find_device_by_physdev_uid (ctx->self, ctx->uid);
|
||||||
|
if (!device) {
|
||||||
|
g_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
|
||||||
|
"No device found with uid '%s'", ctx->uid);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mm_device_get_inhibited (device)) {
|
||||||
|
g_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS,
|
||||||
|
"Device '%s' is already inhibited", ctx->uid);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_device_inhibit (device,
|
||||||
|
(GAsyncReadyCallback) device_inhibit_ready,
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
base_manager_uninhibit_device (InhibitDeviceContext *ctx)
|
||||||
|
{
|
||||||
|
InhibitedDeviceInfo *info;
|
||||||
|
const gchar *sender;
|
||||||
|
|
||||||
|
/* Validate uninhibit request */
|
||||||
|
sender = g_dbus_method_invocation_get_sender (ctx->invocation);
|
||||||
|
info = find_inhibited_device_info_by_physdev_uid (ctx->self, ctx->uid);
|
||||||
|
if (!info || (g_strcmp0 (info->sender, sender) != 0)) {
|
||||||
|
g_dbus_method_invocation_return_error (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
|
||||||
|
"No inhibition found for uid '%s'", ctx->uid);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_info ("Device inhibition teardown for uid '%s'", ctx->uid);
|
||||||
|
remove_device_inhibition (ctx->self, ctx->uid);
|
||||||
|
|
||||||
|
mm_gdbus_org_freedesktop_modem_manager1_complete_inhibit_device (
|
||||||
|
MM_GDBUS_ORG_FREEDESKTOP_MODEM_MANAGER1 (ctx->self),
|
||||||
|
ctx->invocation);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_device_auth_ready (MMAuthProvider *authp,
|
||||||
|
GAsyncResult *res,
|
||||||
|
InhibitDeviceContext *ctx)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!mm_auth_provider_authorize_finish (authp, res, &error)) {
|
||||||
|
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||||
|
inhibit_device_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->inhibit)
|
||||||
|
base_manager_inhibit_device (ctx);
|
||||||
|
else
|
||||||
|
base_manager_uninhibit_device (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
handle_inhibit_device (MmGdbusOrgFreedesktopModemManager1 *manager,
|
||||||
|
GDBusMethodInvocation *invocation,
|
||||||
|
const gchar *uid,
|
||||||
|
gboolean inhibit)
|
||||||
|
{
|
||||||
|
InhibitDeviceContext *ctx;
|
||||||
|
|
||||||
|
ctx = g_new0 (InhibitDeviceContext, 1);
|
||||||
|
ctx->self = g_object_ref (manager);
|
||||||
|
ctx->invocation = g_object_ref (invocation);
|
||||||
|
ctx->uid = g_strdup (uid);
|
||||||
|
ctx->inhibit = inhibit;
|
||||||
|
|
||||||
|
mm_auth_provider_authorize (ctx->self->priv->authp,
|
||||||
|
invocation,
|
||||||
|
MM_AUTHORIZATION_MANAGER_CONTROL,
|
||||||
|
ctx->self->priv->authp_cancellable,
|
||||||
|
(GAsyncReadyCallback)inhibit_device_auth_ready,
|
||||||
|
ctx);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Test profile setup */
|
/* Test profile setup */
|
||||||
|
|
||||||
@@ -1092,6 +1445,9 @@ mm_base_manager_init (MMBaseManager *manager)
|
|||||||
/* Setup internal lists of device objects */
|
/* Setup internal lists of device objects */
|
||||||
priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||||
|
|
||||||
|
/* Setup internal list of inhibited devices */
|
||||||
|
priv->inhibited_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)inhibited_device_info_free);
|
||||||
|
|
||||||
#if defined WITH_UDEV
|
#if defined WITH_UDEV
|
||||||
{
|
{
|
||||||
const gchar *subsys[5] = { "tty", "net", "usb", "usbmisc", NULL };
|
const gchar *subsys[5] = { "tty", "net", "usb", "usbmisc", NULL };
|
||||||
@@ -1111,17 +1467,11 @@ mm_base_manager_init (MMBaseManager *manager)
|
|||||||
priv->object_manager = g_dbus_object_manager_server_new (MM_DBUS_PATH);
|
priv->object_manager = g_dbus_object_manager_server_new (MM_DBUS_PATH);
|
||||||
|
|
||||||
/* Enable processing of input DBus messages */
|
/* Enable processing of input DBus messages */
|
||||||
g_signal_connect (manager,
|
g_object_connect (manager,
|
||||||
"handle-set-logging",
|
"signal::handle-set-logging", G_CALLBACK (handle_set_logging), NULL,
|
||||||
G_CALLBACK (handle_set_logging),
|
"signal::handle-scan-devices", G_CALLBACK (handle_scan_devices), NULL,
|
||||||
NULL);
|
"signal::handle-report-kernel-event", G_CALLBACK (handle_report_kernel_event), NULL,
|
||||||
g_signal_connect (manager,
|
"signal::handle-inhibit-device", G_CALLBACK (handle_inhibit_device), NULL,
|
||||||
"handle-scan-devices",
|
|
||||||
G_CALLBACK (handle_scan_devices),
|
|
||||||
NULL);
|
|
||||||
g_signal_connect (manager,
|
|
||||||
"handle-report-kernel-event",
|
|
||||||
G_CALLBACK (handle_report_kernel_event),
|
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1185,6 +1535,7 @@ finalize (GObject *object)
|
|||||||
g_free (priv->initial_kernel_events);
|
g_free (priv->initial_kernel_events);
|
||||||
g_free (priv->plugin_dir);
|
g_free (priv->plugin_dir);
|
||||||
|
|
||||||
|
g_hash_table_destroy (priv->inhibited_devices);
|
||||||
g_hash_table_destroy (priv->devices);
|
g_hash_table_destroy (priv->devices);
|
||||||
|
|
||||||
#if defined WITH_UDEV
|
#if defined WITH_UDEV
|
||||||
|
103
src/mm-device.c
103
src/mm-device.c
@@ -36,6 +36,7 @@ enum {
|
|||||||
PROP_MODEM,
|
PROP_MODEM,
|
||||||
PROP_HOTPLUGGED,
|
PROP_HOTPLUGGED,
|
||||||
PROP_VIRTUAL,
|
PROP_VIRTUAL,
|
||||||
|
PROP_INHIBITED,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,6 +80,9 @@ struct _MMDevicePrivate {
|
|||||||
/* Whether the device was hot-plugged. */
|
/* Whether the device was hot-plugged. */
|
||||||
gboolean hotplugged;
|
gboolean hotplugged;
|
||||||
|
|
||||||
|
/* Whether the device is inhibited. */
|
||||||
|
gboolean inhibited;
|
||||||
|
|
||||||
/* Virtual ports */
|
/* Virtual ports */
|
||||||
gchar **virtual_ports;
|
gchar **virtual_ports;
|
||||||
};
|
};
|
||||||
@@ -370,6 +374,12 @@ mm_device_create_modem (MMDevice *self,
|
|||||||
g_assert (self->priv->modem == NULL);
|
g_assert (self->priv->modem == NULL);
|
||||||
g_assert (self->priv->object_manager == NULL);
|
g_assert (self->priv->object_manager == NULL);
|
||||||
|
|
||||||
|
if (self->priv->inhibited) {
|
||||||
|
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Device is inhibited");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!self->priv->virtual) {
|
if (!self->priv->virtual) {
|
||||||
if (!self->priv->port_probes) {
|
if (!self->priv->port_probes) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@@ -520,6 +530,85 @@ mm_device_get_hotplugged (MMDevice *self)
|
|||||||
return self->priv->hotplugged;
|
return self->priv->hotplugged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_device_get_inhibited (MMDevice *self)
|
||||||
|
{
|
||||||
|
return self->priv->inhibited;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_device_inhibit_finish (MMDevice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inhibit_disable_ready (MMBaseModem *modem,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
MMDevice *self;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
self = g_task_get_source_object (task);
|
||||||
|
|
||||||
|
if (!mm_base_modem_disable_finish (modem, res, &error))
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
else {
|
||||||
|
g_cancellable_cancel (mm_base_modem_peek_cancellable (modem));
|
||||||
|
mm_device_remove_modem (self);
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
}
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mm_device_inhibit (MMDevice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
/* We want to allow inhibiting only devices that are currently
|
||||||
|
* exported in the bus, because otherwise we may be inhibiting
|
||||||
|
* in the middle of port probing and that may lead to some ports
|
||||||
|
* tracked inside the device object during inhibition and some
|
||||||
|
* other ports tracked in the base manager. So, if the device
|
||||||
|
* does not have a valid modem created and exposed, do not allow
|
||||||
|
* the inhibition. */
|
||||||
|
if (!self->priv->modem || !g_dbus_object_get_object_path (G_DBUS_OBJECT (self->priv->modem))) {
|
||||||
|
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE,
|
||||||
|
"Modem not exported in the bus");
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flag as inhibited right away */
|
||||||
|
g_assert (!self->priv->inhibited);
|
||||||
|
self->priv->inhibited = TRUE;
|
||||||
|
|
||||||
|
/* Make sure modem is disabled while inhibited */
|
||||||
|
mm_base_modem_disable (self->priv->modem,
|
||||||
|
(GAsyncReadyCallback)inhibit_disable_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_device_uninhibit (MMDevice *self,
|
||||||
|
GDBusObjectManagerServer *object_manager,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_assert (self->priv->inhibited);
|
||||||
|
self->priv->inhibited = FALSE;
|
||||||
|
return mm_device_create_modem (self, object_manager, error);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -602,6 +691,9 @@ set_property (GObject *object,
|
|||||||
case PROP_VIRTUAL:
|
case PROP_VIRTUAL:
|
||||||
self->priv->virtual = g_value_get_boolean (value);
|
self->priv->virtual = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_INHIBITED:
|
||||||
|
self->priv->inhibited = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -632,6 +724,9 @@ get_property (GObject *object,
|
|||||||
case PROP_VIRTUAL:
|
case PROP_VIRTUAL:
|
||||||
g_value_set_boolean (value, self->priv->virtual);
|
g_value_set_boolean (value, self->priv->virtual);
|
||||||
break;
|
break;
|
||||||
|
case PROP_INHIBITED:
|
||||||
|
g_value_set_boolean (value, self->priv->inhibited);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -719,6 +814,14 @@ mm_device_class_init (MMDeviceClass *klass)
|
|||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
g_object_class_install_property (object_class, PROP_VIRTUAL, properties[PROP_VIRTUAL]);
|
g_object_class_install_property (object_class, PROP_VIRTUAL, properties[PROP_VIRTUAL]);
|
||||||
|
|
||||||
|
properties[PROP_INHIBITED] =
|
||||||
|
g_param_spec_boolean (MM_DEVICE_INHIBITED,
|
||||||
|
"Inhibited",
|
||||||
|
"Whether the modem is inhibited",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_property (object_class, PROP_INHIBITED, properties[PROP_INHIBITED]);
|
||||||
|
|
||||||
signals[SIGNAL_PORT_GRABBED] =
|
signals[SIGNAL_PORT_GRABBED] =
|
||||||
g_signal_new (MM_DEVICE_PORT_GRABBED,
|
g_signal_new (MM_DEVICE_PORT_GRABBED,
|
||||||
G_OBJECT_CLASS_TYPE (object_class),
|
G_OBJECT_CLASS_TYPE (object_class),
|
||||||
|
@@ -38,6 +38,7 @@ typedef struct _MMDevicePrivate MMDevicePrivate;
|
|||||||
#define MM_DEVICE_MODEM "modem"
|
#define MM_DEVICE_MODEM "modem"
|
||||||
#define MM_DEVICE_HOTPLUGGED "hotplugged"
|
#define MM_DEVICE_HOTPLUGGED "hotplugged"
|
||||||
#define MM_DEVICE_VIRTUAL "virtual"
|
#define MM_DEVICE_VIRTUAL "virtual"
|
||||||
|
#define MM_DEVICE_INHIBITED "inhibited"
|
||||||
|
|
||||||
#define MM_DEVICE_PORT_GRABBED "port-grabbed"
|
#define MM_DEVICE_PORT_GRABBED "port-grabbed"
|
||||||
#define MM_DEVICE_PORT_RELEASED "port-released"
|
#define MM_DEVICE_PORT_RELEASED "port-released"
|
||||||
@@ -77,6 +78,17 @@ gboolean mm_device_create_modem (MMDevice *self,
|
|||||||
GError **error);
|
GError **error);
|
||||||
void mm_device_remove_modem (MMDevice *self);
|
void mm_device_remove_modem (MMDevice *self);
|
||||||
|
|
||||||
|
void mm_device_inhibit (MMDevice *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean mm_device_inhibit_finish (MMDevice *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
gboolean mm_device_uninhibit (MMDevice *self,
|
||||||
|
GDBusObjectManagerServer *object_manager,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
|
||||||
const gchar *mm_device_get_uid (MMDevice *self);
|
const gchar *mm_device_get_uid (MMDevice *self);
|
||||||
const gchar **mm_device_get_drivers (MMDevice *self);
|
const gchar **mm_device_get_drivers (MMDevice *self);
|
||||||
guint16 mm_device_get_vendor (MMDevice *self);
|
guint16 mm_device_get_vendor (MMDevice *self);
|
||||||
@@ -94,6 +106,7 @@ GObject *mm_device_get_port_probe (MMDevice *self,
|
|||||||
GList *mm_device_peek_port_probe_list (MMDevice *self);
|
GList *mm_device_peek_port_probe_list (MMDevice *self);
|
||||||
GList *mm_device_get_port_probe_list (MMDevice *self);
|
GList *mm_device_get_port_probe_list (MMDevice *self);
|
||||||
gboolean mm_device_get_hotplugged (MMDevice *self);
|
gboolean mm_device_get_hotplugged (MMDevice *self);
|
||||||
|
gboolean mm_device_get_inhibited (MMDevice *self);
|
||||||
|
|
||||||
/* For testing purposes */
|
/* For testing purposes */
|
||||||
void mm_device_virtual_grab_ports (MMDevice *self,
|
void mm_device_virtual_grab_ports (MMDevice *self,
|
||||||
|
Reference in New Issue
Block a user