blob: 5975f1c6eb1a11ac4501299ac140fe30920fae8c [file] [log] [blame]
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <dbus/dbus.h>
#include <errno.h>
#include <poll.h>
#include <stdint.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/select.h>
#include <unistd.h>
#include "cras_system_state.h"
#include "cras_tm.h"
static void dbus_watch_callback(void *arg, int revents)
{
DBusWatch *watch = (DBusWatch *)arg;
int r, flags;
struct pollfd pollfd;
pollfd.fd = dbus_watch_get_unix_fd(watch);
pollfd.events = POLLIN | POLLOUT;
r = poll(&pollfd, 1, 0);
if (r <= 0)
return;
flags = 0;
if (pollfd.revents & POLLIN)
flags |= DBUS_WATCH_READABLE;
if (pollfd.revents & POLLOUT)
flags |= DBUS_WATCH_WRITABLE;
if (!dbus_watch_handle(watch, flags))
syslog(LOG_WARNING, "Failed to handle D-Bus watch.");
}
static dbus_bool_t dbus_watch_add(DBusWatch *watch, void *data)
{
int r;
unsigned int flags = dbus_watch_get_flags(watch);
/* Only select the read watch.
* TODO(hychao): select on write watch when we have a use case.
*/
if ((flags & DBUS_WATCH_READABLE) && dbus_watch_get_enabled(watch)) {
r = cras_system_add_select_fd(dbus_watch_get_unix_fd(watch),
dbus_watch_callback, watch,
POLLIN);
if (r != 0)
return FALSE;
}
return TRUE;
}
static void dbus_watch_remove(DBusWatch *watch, void *data)
{
unsigned int flags = dbus_watch_get_flags(watch);
/* Only select the read watch. */
if (flags & DBUS_WATCH_READABLE)
cras_system_rm_select_fd(dbus_watch_get_unix_fd(watch));
}
static void dbus_watch_toggled(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch)) {
dbus_watch_add(watch, NULL);
} else {
dbus_watch_remove(watch, NULL);
}
}
static void dbus_timeout_callback(struct cras_timer *t, void *data)
{
struct cras_tm *tm = cras_system_state_get_tm();
struct DBusTimeout *timeout = data;
/* Timer is automatically removed after it fires. Add a new one so this
* fires until it is removed by dbus. */
t = cras_tm_create_timer(tm, dbus_timeout_get_interval(timeout),
dbus_timeout_callback, timeout);
dbus_timeout_set_data(timeout, t, NULL);
if (!dbus_timeout_handle(timeout))
syslog(LOG_WARNING, "Failed to handle D-Bus timeout.");
}
static dbus_bool_t dbus_timeout_add(DBusTimeout *timeout, void *arg)
{
struct cras_tm *tm = cras_system_state_get_tm();
struct cras_timer *t = dbus_timeout_get_data(timeout);
if (t) {
dbus_timeout_set_data(timeout, NULL, NULL);
cras_tm_cancel_timer(tm, t);
}
if (dbus_timeout_get_enabled(timeout)) {
t = cras_tm_create_timer(tm, dbus_timeout_get_interval(timeout),
dbus_timeout_callback, timeout);
dbus_timeout_set_data(timeout, t, NULL);
if (t == NULL)
return FALSE;
}
return TRUE;
}
static void dbus_timeout_remove(DBusTimeout *timeout, void *arg)
{
struct cras_tm *tm = cras_system_state_get_tm();
struct cras_timer *t = dbus_timeout_get_data(timeout);
if (t) {
dbus_timeout_set_data(timeout, NULL, NULL);
cras_tm_cancel_timer(tm, t);
}
}
static void dbus_timeout_toggled(DBusTimeout *timeout, void *arg)
{
if (dbus_timeout_get_enabled(timeout))
dbus_timeout_add(timeout, NULL);
else
dbus_timeout_remove(timeout, NULL);
}
DBusConnection *cras_dbus_connect_system_bus()
{
DBusError dbus_error;
DBusConnection *conn;
int rc;
dbus_error_init(&dbus_error);
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
if (!conn) {
syslog(LOG_WARNING, "Failed to connect to D-Bus: %s",
dbus_error.message);
dbus_error_free(&dbus_error);
return NULL;
}
/* Request a name on the bus. */
rc = dbus_bus_request_name(conn, "org.chromium.cras", 0, &dbus_error);
if (dbus_error_is_set(&dbus_error)) {
syslog(LOG_ERR, "Requesting dbus name %s", dbus_error.message);
dbus_error_free(&dbus_error);
}
if (rc != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
syslog(LOG_ERR, "Not primary owner of dbus name.");
if (!dbus_connection_set_watch_functions(
conn, dbus_watch_add, dbus_watch_remove, dbus_watch_toggled,
NULL, NULL))
goto error;
if (!dbus_connection_set_timeout_functions(
conn, dbus_timeout_add, dbus_timeout_remove,
dbus_timeout_toggled, NULL, NULL))
goto error;
return conn;
error:
syslog(LOG_WARNING, "Failed to setup D-Bus connection.");
dbus_connection_unref(conn);
return NULL;
}
void cras_dbus_dispatch(DBusConnection *conn)
{
while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS)
;
}
void cras_dbus_disconnect_system_bus(DBusConnection *conn)
{
dbus_connection_unref(conn);
}