/* 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 #include #include #include #include #include #include #include #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); }