summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlok Barsode <alok.barsode@linux.intel.com>2011-08-24 16:44:09 +0300
committerSamuel Ortiz <sameo@linux.intel.com>2011-08-25 11:14:21 +0200
commit7abedeb03775038f334e2edf03f73675425579fd (patch)
tree43cc2d087abfc933c5190f95044fe381593fc326
parent6c1c909876d619b39f80c198ccbe3db354890ca2 (diff)
downloadconnman-7abedeb03775038f334e2edf03f73675425579fd.tar.gz
connman-7abedeb03775038f334e2edf03f73675425579fd.tar.bz2
connman-7abedeb03775038f334e2edf03f73675425579fd.zip
device: Redo pending power request logic
Use 3 values(None/Enable/Disable) for the power_pending. It helps keep track of the ongoing pending request. Add a pending timeout. If the daemon handling the device fails to send a response then we need to reset the power_pending flag.
-rw-r--r--src/device.c149
1 files changed, 92 insertions, 57 deletions
diff --git a/src/device.c b/src/device.c
index 155018a8..669c6a8c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -32,13 +32,20 @@ static GSList *device_list = NULL;
static gchar **device_filter = NULL;
static gchar **nodevice_filter = NULL;
+enum connman_pending_type {
+ PENDING_NONE = 0,
+ PENDING_ENABLE = 1,
+ PENDING_DISABLE = 2,
+};
+
struct connman_device {
gint refcount;
enum connman_device_type type;
+ enum connman_pending_type powered_pending; /* Indicates a pending
+ enable/disable request */
connman_bool_t offlinemode;
connman_bool_t blocked;
connman_bool_t powered;
- connman_bool_t powered_pending;
connman_bool_t powered_persistent;
connman_bool_t scanning;
connman_bool_t disconnected;
@@ -56,6 +63,7 @@ struct connman_device {
int index;
unsigned int connections;
guint scan_timeout;
+ guint pending_timeout;
struct connman_device_driver *driver;
void *driver_data;
@@ -209,62 +217,93 @@ enum connman_service_type __connman_device_get_service_type(struct connman_devic
return CONNMAN_SERVICE_TYPE_UNKNOWN;
}
+static gboolean device_pending_reset(gpointer user_data)
+{
+ struct connman_device *device = user_data;
+
+ DBG("device %p", device);
+
+ /* Power request timedout, reset power pending state. */
+ if (device->pending_timeout > 0) {
+ g_source_remove(device->pending_timeout);
+ device->pending_timeout = 0;
+ device->powered_pending = PENDING_NONE;
+ }
+
+ return FALSE;
+}
+
int __connman_device_enable(struct connman_device *device)
{
int err;
- enum connman_service_type type;
DBG("device %p %d", device, device->blocked);
if (!device->driver || !device->driver->enable)
return -EOPNOTSUPP;
- if (device->powered_pending == TRUE)
- return -EALREADY;
-
if (device->blocked == TRUE)
return -ENOLINK;
- connman_device_set_disconnected(device, FALSE);
- device->scanning = FALSE;
+ /* There is an ongoing power disable request. */
+ if (device->powered_pending == PENDING_DISABLE)
+ return -EBUSY;
- err = device->driver->enable(device);
- if (err < 0 && err != -EALREADY) {
- if (err == -EINPROGRESS) {
- device->powered_pending = TRUE;
- device->offlinemode = FALSE;
- if (__connman_profile_get_offlinemode() == TRUE)
- __connman_profile_set_offlinemode(FALSE, FALSE);
- }
- return err;
- }
+ if (device->powered_pending == PENDING_ENABLE)
+ return -EALREADY;
- device->powered_pending = TRUE;
- device->powered = TRUE;
- device->offlinemode = FALSE;
- if (__connman_profile_get_offlinemode() == TRUE)
- __connman_profile_set_offlinemode(FALSE, FALSE);
+ if (device->powered_pending == PENDING_NONE && device->powered == TRUE)
+ return -EALREADY;
- type = __connman_device_get_service_type(device);
- __connman_technology_enabled(type);
+ device->powered_pending = PENDING_ENABLE;
- return 0;
+ err = device->driver->enable(device);
+ /*
+ * device gets enabled right away.
+ * Invoke the callback
+ */
+ if (err == 0) {
+ connman_device_set_powered(device, TRUE);
+ goto done;
+ }
+
+ if (err == -EALREADY) {
+ /* If device is already powered, but connman is not updated */
+ connman_device_set_powered(device, TRUE);
+ goto done;
+ }
+ /*
+ * if err == -EINPROGRESS, then the DBus call to the respective daemon
+ * was successful. We set a 4 sec timeout so if the daemon never
+ * returns a reply, we would reset the pending request.
+ */
+ if (err == -EINPROGRESS)
+ device->pending_timeout = g_timeout_add_seconds(4,
+ device_pending_reset, device);
+done:
+ return err;
}
int __connman_device_disable(struct connman_device *device)
{
int err;
- enum connman_service_type type;
DBG("device %p", device);
if (!device->driver || !device->driver->disable)
return -EOPNOTSUPP;
- if (device->powered == FALSE)
+ if (device->blocked == TRUE)
return -ENOLINK;
- if (device->powered_pending == FALSE)
+ /* Ongoing power enable request */
+ if (device->powered_pending == PENDING_ENABLE)
+ return -EBUSY;
+
+ if (device->powered_pending == PENDING_DISABLE)
+ return -EALREADY;
+
+ if (device->powered_pending == PENDING_NONE && device->powered == FALSE)
return -EALREADY;
device->reconnect = FALSE;
@@ -272,23 +311,21 @@ int __connman_device_disable(struct connman_device *device)
clear_scan_trigger(device);
err = device->driver->disable(device);
- if (err < 0 && err != -EALREADY) {
- if (err == -EINPROGRESS)
- device->powered_pending = FALSE;
- return err;
+ if (err == 0) {
+ connman_device_set_powered(device, FALSE);
+ goto done;
}
- g_hash_table_remove_all(device->networks);
-
- device->connections = 0;
-
- device->powered_pending = FALSE;
- device->powered = FALSE;
-
- type = __connman_device_get_service_type(device);
- __connman_technology_disabled(type);
+ if (err == -EALREADY) {
+ connman_device_set_powered(device, FALSE);
+ goto done;
+ }
- return 0;
+ if (err == -EINPROGRESS)
+ device->pending_timeout = g_timeout_add_seconds(4,
+ device_pending_reset, device);
+done:
+ return err;
}
static int set_powered(struct connman_device *device, connman_bool_t powered)
@@ -656,26 +693,22 @@ const char *connman_device_get_ident(struct connman_device *device)
int connman_device_set_powered(struct connman_device *device,
connman_bool_t powered)
{
- int err;
enum connman_service_type type;
DBG("driver %p powered %d", device, powered);
- if (device->powered == powered) {
- device->powered_pending = powered;
+ if (device->powered == powered)
return -EALREADY;
- }
- if (powered == TRUE)
- err = __connman_device_enable(device);
- else
- err = __connman_device_disable(device);
+ /* Reset pending request */
+ g_source_remove(device->pending_timeout);
+ device->pending_timeout = 0;
+ device->powered_pending = PENDING_NONE;
- if (err < 0 && err != -EINPROGRESS && err != -EALREADY)
- return err;
+ if (device->offlinemode == TRUE && powered == TRUE)
+ return __connman_device_disable(device);
device->powered = powered;
- device->powered_pending = powered;
type = __connman_device_get_service_type(device);
@@ -684,11 +717,13 @@ int connman_device_set_powered(struct connman_device *device,
else
__connman_technology_disabled(type);
- if (device->offlinemode == TRUE && powered == TRUE)
- return connman_device_set_powered(device, FALSE);
-
- if (powered == FALSE)
+ if (powered == FALSE) {
+ device->connections = 0;
return 0;
+ }
+
+ connman_device_set_disconnected(device, FALSE);
+ device->scanning = FALSE;
reset_scan_trigger(device);