i2c: Support private/shared clients 30/259230/5 accepted/tizen_6.5_unified accepted/tizen_unified tizen tizen_6.5 accepted/tizen/6.5/unified/20211028.115421 accepted/tizen/unified/20210607.124317 submit/tizen/20210607.045229 submit/tizen_6.5/20211028.162501 tizen_6.5.m2_release
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 2 Jun 2021 16:38:50 +0000 (18:38 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Fri, 4 Jun 2021 10:01:46 +0000 (12:01 +0200)
Change-Id: I1d0672d682cd4dc5b69eaa80546c04a87c61285e

include/gdbus/peripheral_gdbus_i2c.h
include/handle/peripheral_handle.h
include/handle/peripheral_handle_i2c.h
packaging/peripheral-bus.spec
src/gdbus/peripheral_gdbus_i2c.c
src/gdbus/peripheral_io.xml
src/handle/peripheral_handle_i2c.c
src/peripheral_bus.c

index 6fb3813452fc14339f0ad8facf244e32d1c9a144..4c4878ce0c8080aa973f40f1a02c3e924f5ed106 100644 (file)
@@ -27,6 +27,15 @@ gboolean peripheral_gdbus_i2c_open(
                gint address,
                gpointer user_data);
 
+gboolean peripheral_gdbus_i2c_open_flags(
+               PeripheralIoGdbusI2c *i2c,
+               GDBusMethodInvocation *invocation,
+               GUnixFDList *fd_list,
+               gint bus,
+               gint address,
+               gint flags,
+               gpointer user_data);
+
 gboolean peripheral_gdbus_i2c_close(
                PeripheralIoGdbusI2c *i2c,
                GDBusMethodInvocation *invocation,
index 66e12696a808e3e9b1ff5cd103481440f5b33589..879c148c2b88f5b4bb951c34c01defa60f32c274 100644 (file)
@@ -75,8 +75,12 @@ typedef struct {
 } peripheral_handle_spi_s;
 
 typedef struct {
-       uint watch_id;
        uint32_t handle_id;
+       uint watch_id;
+
+       peripheral_open_flags_e open_flags; // used by i2c only for now
+       GList *watch_list;                  // ditto
+
        GList **list;
        union {
                peripheral_handle_gpio_s gpio;
index 55079e0a2d651591b708188a1ab770b16cfd844c..ae89911f44c7fcfece294a7b588c755ca27f8962 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef __PERIPHERAL_HANDLE_I2C_H__
 #define __PERIPHERAL_HANDLE_I2C_H__
 
-int peripheral_handle_i2c_create(int bus, int address, peripheral_h *handle, gpointer user_data);
+int peripheral_handle_i2c_create(int bus, int address, int flags, peripheral_h *handle, gpointer user_data);
 int peripheral_handle_i2c_destroy(peripheral_h handle);
 
 #endif /* __PERIPHERAL_HANDLE_I2C_H__ */
index 37dfc3077acef2b8ff70292b2bf4a2ca6638e273..41afbe31269821aa7cb6963ff410907455bc7f83 100644 (file)
@@ -1,6 +1,6 @@
 Name:       peripheral-bus
 Summary:    Tizen Peripheral Input & Output Service Daemon
-Version:    0.1.4
+Version:    0.2.0
 Release:    0
 Group:      System & System Tools
 License:    Apache-2.0
index 7003f373c3da1f1d8232053cd22af6236b1b2d7c..5fbe6df1ed1b6918585c51cc4a398f50777a4c8a 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <assert.h>
 #include <peripheral_io.h>
 #include <gio/gunixfdlist.h>
 
 #include "peripheral_interface_i2c.h"
 #include "peripheral_gdbus_i2c.h"
 
+struct watch_data {
+       guint watch_id;
+       peripheral_h handle;
+       char *name;
+};
+
+static void __watch_remove_one(struct watch_data *watch_ptr)
+{
+     assert(watch_ptr);
+     peripheral_h i2c_handle = watch_ptr->handle;
+     assert(i2c_handle);
+
+     g_bus_unwatch_name(watch_ptr->watch_id);
+     i2c_handle->watch_list = g_list_remove(i2c_handle->watch_list, watch_ptr);
+
+     free(watch_ptr->name);
+     free(watch_ptr);
+}
+
+static int __watch_remove(struct watch_data *watch_ptr)
+{
+       assert(watch_ptr);
+       peripheral_h i2c_handle = watch_ptr->handle;
+       assert(i2c_handle);
+
+       int ret = PERIPHERAL_ERROR_NONE;
+
+       __watch_remove_one(watch_ptr);
+
+       if (!i2c_handle->watch_list) {
+               _D("Removed last referenced i2c client, dropping handle");
+
+               ret = peripheral_handle_i2c_destroy(i2c_handle);
+               if (ret != PERIPHERAL_ERROR_NONE)
+                       _E("Failed to destroy i2c handle");
+       } else
+               _D("Remaining %u client(s) for i2c handle remaining, keeping it for now", g_list_length(i2c_handle->watch_list));
+
+       return ret;
+}
+
 static void __i2c_on_name_vanished(GDBusConnection *connection,
                const gchar *name,
                gpointer user_data)
 {
-       int ret = PERIPHERAL_ERROR_NONE;
-
-       peripheral_h i2c_handle = (peripheral_h)user_data;
        _D("appid [%s] vanished ", name);
+       (void)__watch_remove((struct watch_data *)user_data);
+}
+
+static bool __do_watch(GDBusMethodInvocation *invocation, peripheral_h i2c_handle)
+{
+       assert(invocation);
+       assert(i2c_handle);
+
+       char *name = strdup(g_dbus_method_invocation_get_sender(invocation));
+       if (!name)
+               return false;
 
-       g_bus_unwatch_name(i2c_handle->watch_id);
+       struct watch_data *watch_ptr = malloc(sizeof(struct watch_data));
+       if (!watch_ptr) {
+               free(name);
+               return false;
+       }
+
+       watch_ptr->name = name;
+       watch_ptr->handle = i2c_handle;
+       watch_ptr->watch_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
+                       name,
+                       G_BUS_NAME_WATCHER_FLAGS_NONE,
+                       NULL,
+                       __i2c_on_name_vanished,
+                       watch_ptr,
+                       NULL);
+       i2c_handle->watch_list = g_list_append(i2c_handle->watch_list, watch_ptr);
 
-       ret = peripheral_handle_i2c_destroy(i2c_handle);
-       if (ret != PERIPHERAL_ERROR_NONE)
-               _E("Failed to destroy i2c handle");
+       return true;
 }
 
 gboolean peripheral_gdbus_i2c_open(
@@ -68,20 +131,57 @@ gboolean peripheral_gdbus_i2c_open(
                goto out;
        }
 
-       ret = peripheral_handle_i2c_create(bus, address, &i2c_handle, user_data);
+       ret = peripheral_handle_i2c_create(bus, address, PERIPHERAL_OPEN_FLAGS_PRIVATE, &i2c_handle, user_data);
        if (ret != PERIPHERAL_ERROR_NONE) {
                _E("Failed to create i2c handle");
                goto out;
        }
 
-       i2c_handle->watch_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
-                       g_dbus_method_invocation_get_sender(invocation),
-                       G_BUS_NAME_WATCHER_FLAGS_NONE,
-                       NULL,
-                       __i2c_on_name_vanished,
-                       i2c_handle,
-                       NULL);
+       if (!__do_watch(invocation, i2c_handle))
+               goto out;
+out:
+       peripheral_io_gdbus_i2c_complete_open(i2c, invocation, i2c_fd_list, PERIPHERAL_H_TO_ID(i2c_handle), ret);
+       peripheral_interface_i2c_fd_list_destroy(i2c_fd_list);
+
+       return true;
+}
+
+gboolean peripheral_gdbus_i2c_open_flags(
+               PeripheralIoGdbusI2c *i2c,
+               GDBusMethodInvocation *invocation,
+               GUnixFDList *fd_list,
+               gint bus,
+               gint address,
+               gint flags,
+               gpointer user_data)
+{
+       int ret = PERIPHERAL_ERROR_NONE;
+
+       peripheral_info_s *info = (peripheral_info_s*)user_data;
+       peripheral_h i2c_handle = NULL;
+       GUnixFDList *i2c_fd_list = NULL;
+
+       ret = peripheral_privilege_check(invocation, info->connection);
+       if (ret != 0) {
+               _E("Permission denied.");
+               ret = PERIPHERAL_ERROR_PERMISSION_DENIED;
+               goto out;
+       }
+
+       ret = peripheral_interface_i2c_fd_list_create(bus, address, &i2c_fd_list);
+       if (ret != PERIPHERAL_ERROR_NONE) {
+               _E("Failed to create i2c fd list");
+               goto out;
+       }
 
+       ret = peripheral_handle_i2c_create(bus, address, flags, &i2c_handle, user_data);
+       if (ret != PERIPHERAL_ERROR_NONE) {
+               _E("Failed to create i2c handle");
+               goto out;
+       }
+
+       if (!__do_watch(invocation, i2c_handle))
+               goto out;
 out:
        peripheral_io_gdbus_i2c_complete_open(i2c, invocation, i2c_fd_list, PERIPHERAL_H_TO_ID(i2c_handle), ret);
        peripheral_interface_i2c_fd_list_destroy(i2c_fd_list);
@@ -105,12 +205,21 @@ gboolean peripheral_gdbus_i2c_close(
                goto out;
        }
 
-       g_bus_unwatch_name(i2c_handle->watch_id);
-
-       ret = peripheral_handle_i2c_destroy(i2c_handle);
-       if (ret != PERIPHERAL_ERROR_NONE)
-               _E("Failed to destroy i2c handle");
-
+       const char *name = g_dbus_method_invocation_get_sender(invocation);
+       struct watch_data *found = NULL;
+       for (GList *list = i2c_handle->watch_list; list; list = g_list_next(list)) {
+               struct watch_data *ptr = (struct watch_data *)list->data;
+               if (!strcmp(name, ptr->name)) {
+                       found = ptr;
+                       break;
+               }
+       }
+       if (found)
+               ret = __watch_remove(found);
+       else {
+               ret = PERIPHERAL_ERROR_INVALID_PARAMETER;
+               _E("i2c close called but referenced client not found");
+       }
 out:
        peripheral_io_gdbus_i2c_complete_close(i2c, invocation, ret);
 
index db72361e9134ea6ed74611c98dee39c8d2405390..c868cdf5b9674be3052b5fbee6315e8cc5f2bd0c 100644 (file)
                        <arg type="u" name="handle" direction="out"/>
                        <arg type="i" name="result" direction="out"/>
                </method>
+               <method name="OpenFlags">
+                       <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
+                       <arg type="i" name="bus" direction="in"/>
+                       <arg type="i" name="address" direction="in"/>
+                       <arg type="i" name="flags" direction="in"/>
+                       <arg type="u" name="handle" direction="out"/>
+                       <arg type="i" name="result" direction="out"/>
+               </method>
                <method name="Close">
                        <arg type="u" name="handle" direction="in"/>
                        <arg type="i" name="result" direction="out"/>
index 8bce082a0be5c52557a67d95821054fc747c146f..9c2a8ea35ed5f3396f9c848e3b178b0360fa54b9 100644 (file)
@@ -15,8 +15,9 @@
  */
 
 #include "peripheral_handle.h"
+#include "peripheral_io.h"
 
-static bool __peripheral_handle_i2c_is_creatable(int bus, int address, peripheral_info_s *info)
+static bool __peripheral_handle_i2c_is_creatable(int bus, int address, peripheral_info_s *info, int flags, peripheral_h *out_handle)
 {
        pb_board_dev_s *i2c = NULL;
        peripheral_h handle;
@@ -35,8 +36,13 @@ static bool __peripheral_handle_i2c_is_creatable(int bus, int address, periphera
        while (link) {
                handle = (peripheral_h)link->data;
                if (handle->type.i2c.bus == bus && handle->type.i2c.address == address) {
-                       _E("Resource is in use, bus : %d, address : %d", bus, address);
-                       return false;
+                       if (handle->open_flags != PERIPHERAL_OPEN_FLAGS_SHARED || flags != PERIPHERAL_OPEN_FLAGS_SHARED) {
+                               _E("Resource is in use, bus : %d, address : %d", bus, address);
+                               return false;
+                       } else {
+                               *out_handle = handle;
+                               return true;
+                       }
                }
                link = g_list_next(link);
        }
@@ -57,7 +63,7 @@ int peripheral_handle_i2c_destroy(peripheral_h handle)
        return ret;
 }
 
-int peripheral_handle_i2c_create(int bus, int address, peripheral_h *handle, gpointer user_data)
+int peripheral_handle_i2c_create(int bus, int address, int flags, peripheral_h *handle, gpointer user_data)
 {
        RETVM_IF(bus < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid i2c bus");
        RETVM_IF(address < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid i2c address");
@@ -65,25 +71,33 @@ int peripheral_handle_i2c_create(int bus, int address, peripheral_h *handle, gpo
 
        peripheral_info_s *info = (peripheral_info_s*)user_data;
 
+       if (flags != PERIPHERAL_OPEN_FLAGS_PRIVATE && flags != PERIPHERAL_OPEN_FLAGS_SHARED) {
+               _E("Invalid open flags passed");
+               return false;
+       }
+
        peripheral_h i2c_handle = NULL;
        bool is_handle_creatable = false;
 
-       is_handle_creatable = __peripheral_handle_i2c_is_creatable(bus, address, info);
+       is_handle_creatable = __peripheral_handle_i2c_is_creatable(bus, address, info, flags, &i2c_handle);
        if (is_handle_creatable == false) {
                _E("bus : %d, address : 0x%x is not available", bus, address);
                return PERIPHERAL_ERROR_RESOURCE_BUSY;
        }
 
-       i2c_handle = peripheral_handle_new(&info->i2c_list);
        if (i2c_handle == NULL) {
-               _E("peripheral_handle_new error");
-               return PERIPHERAL_ERROR_OUT_OF_MEMORY;
+               i2c_handle = peripheral_handle_new(&info->i2c_list);
+               if (i2c_handle == NULL) {
+                       _E("peripheral_handle_new error");
+                       return PERIPHERAL_ERROR_OUT_OF_MEMORY;
+               }
+               i2c_handle->list = &info->i2c_list;
+               i2c_handle->type.i2c.bus = bus;
+               i2c_handle->type.i2c.address = address;
+               i2c_handle->open_flags = flags;
+               i2c_handle->watch_list = NULL;
        }
 
-       i2c_handle->list = &info->i2c_list;
-       i2c_handle->type.i2c.bus = bus;
-       i2c_handle->type.i2c.address = address;
-
        *handle = i2c_handle;
 
        return PERIPHERAL_ERROR_NONE;
index 53a637932b5390aca847620c25310500d7f30629..8392421a37bb450390e6fa099990e369ecfdc111 100644 (file)
@@ -89,6 +89,10 @@ static gboolean __i2c_init(peripheral_info_s *info)
                        "handle-open",
                        G_CALLBACK(peripheral_gdbus_i2c_open),
                        info);
+       g_signal_connect(info->i2c_skeleton,
+                       "handle-open-flags",
+                       G_CALLBACK(peripheral_gdbus_i2c_open_flags),
+                       info);
        g_signal_connect(info->i2c_skeleton,
                        "handle-close",
                        G_CALLBACK(peripheral_gdbus_i2c_close),