freebsd-ports/graphics/entangle/files/patch-src_backend_entangle-device-manager.c
2013-09-16 03:54:03 +00:00

172 lines
4.8 KiB
C

--- src/backend/entangle-device-manager.c.orig 2013-03-13 05:23:35.000000000 +0800
+++ src/backend/entangle-device-manager.c 2013-07-04 20:02:19.000000000 +0800
@@ -20,13 +20,19 @@
#include <config.h>
-#include <string.h>
-#include <stdio.h>
-
+#if defined(__FreeBSD__)
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <glib.h>
+#include <unistd.h>
+#else
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#ifdef G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#endif
+#endif
+#include <string.h>
+#include <stdio.h>
#include "entangle-debug.h"
#include "entangle-device-manager.h"
@@ -35,7 +41,11 @@
(G_TYPE_INSTANCE_GET_PRIVATE((obj), ENTANGLE_TYPE_DEVICE_MANAGER, EntangleDeviceManagerPrivate))
struct _EntangleDeviceManagerPrivate {
+#if defined(__linux__)
GUdevClient *ctx;
+#elif defined(__FreeBSD__)
+ int efd;
+#endif
};
G_DEFINE_TYPE(EntangleDeviceManager, entangle_device_manager, G_TYPE_OBJECT);
@@ -47,8 +57,13 @@ static void entangle_device_manager_fina
EntangleDeviceManagerPrivate *priv = manager->priv;
ENTANGLE_DEBUG("Finalize manager");
+#if defined(__linux__)
if (priv->ctx)
g_object_unref(priv->ctx);
+#elif defined(__FreeBSD__)
+ if (priv->efd)
+ close(priv->efd);
+#endif
G_OBJECT_CLASS (entangle_device_manager_parent_class)->finalize (object);
}
@@ -85,6 +100,7 @@ static void entangle_device_manager_clas
}
+#if defined(__linux__)
static void do_udev_event(GUdevClient *client G_GNUC_UNUSED,
const char *action,
GUdevDevice *dev,
@@ -126,6 +142,91 @@ static void do_udev_event(GUdevClient *c
}
g_free(port);
}
+#elif defined(__FreeBSD__)
+static void devd_init(EntangleDeviceManager *manager);
+
+static gboolean do_devd_event(GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ EntangleDeviceManager *manager = user_data;
+ char *event, *cutoff;
+ gsize end;
+ GIOStatus status;
+
+ status = g_io_channel_read_line(source, &event, NULL, &end, NULL);
+
+ switch (status) {
+ case G_IO_STATUS_NORMAL:
+ event[end] = '\0';
+ if (strncmp(event + 1, "ugen", 4))
+ break;
+ if (!(cutoff = strchr(event + 5, ' ')))
+ break;
+ *cutoff = '\0';
+ if (*event == '+') {
+ g_signal_emit_by_name(manager, "device-added", event + 1);
+ } else if (*event == '-') {
+ g_signal_emit_by_name(manager, "device-removed", event + 1);
+ }
+ g_free(event);
+ break;
+ case G_IO_STATUS_EOF:
+ case G_IO_STATUS_AGAIN:
+ /*
+ * Apparently, devd(8) was reinited (restarted?). Allocate
+ * new channel and teardown previous connection.
+ */
+ devd_init(manager);
+ if (manager->priv->efd > 0) {
+ int old_efd = g_io_channel_unix_get_fd(source);
+ g_io_channel_shutdown(source, FALSE, NULL);
+ close(old_efd);
+ return FALSE;
+ }
+ break;
+ case G_IO_STATUS_ERROR:
+ default:
+ /* XXX: what shall we do? */
+ break;
+ }
+ return TRUE;
+}
+
+
+static void devd_init(EntangleDeviceManager *manager)
+{
+ EntangleDeviceManagerPrivate *priv = manager->priv;
+ struct sockaddr_un addr;
+
+ priv->efd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (priv->efd == -1) {
+ perror("socket");
+ return;
+ }
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, "/var/run/devd.pipe", sizeof(addr.sun_path));
+
+ if (connect(priv->efd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+ GIOChannel *channel = g_io_channel_unix_new(priv->efd);
+ g_io_add_watch(channel, G_IO_IN, do_devd_event, manager);
+ /*
+ * We can reduce the refcount here so that when the watch is
+ * removed, the channel will be destroyed.
+ */
+ g_io_channel_unref(channel);
+ } else {
+ /*
+ * XXX: we should probably spin for a while until connect()
+ * succeeds to get rid of the useless socket()/close() storm
+ * for a short period when devd(8) is not ready yet.
+ */
+ close(priv->efd);
+ priv->efd = -1;
+ }
+}
+#endif
EntangleDeviceManager *entangle_device_manager_new(void)
@@ -136,6 +237,7 @@ EntangleDeviceManager *entangle_device_m
static void entangle_device_manager_init_devices(EntangleDeviceManager *manager)
{
+#if defined(__linux__)
EntangleDeviceManagerPrivate *priv = manager->priv;
GList *devs, *tmp;
const gchar *const subsys[] = {
@@ -161,6 +263,12 @@ static void entangle_device_manager_init
}
g_list_free(devs);
+#elif defined(__FreeBSD__)
+
+ ENTANGLE_DEBUG("Init devd");
+
+ devd_init(manager);
+#endif
}