Functions to create and remove devices are populated to do
more proper things.

Signed-off-by: Christophe Milard <christophe.mil...@linaro.org>
---
 platform/linux-generic/drv_driver.c | 172 ++++++++++++++++++++++++++++++++++--
 1 file changed, 164 insertions(+), 8 deletions(-)

diff --git a/platform/linux-generic/drv_driver.c 
b/platform/linux-generic/drv_driver.c
index f8844f5..48a90a2 100644
--- a/platform/linux-generic/drv_driver.c
+++ b/platform/linux-generic/drv_driver.c
@@ -19,12 +19,15 @@
 
 static enum {UNDONE, IN_PROGRESS, DONE} init_global_status;
 
+static void device_destroy_terminate(odpdrv_device_t device);
+
 /* pool from which different list elements are alocated: */
 #define ELT_POOL_SIZE (1 << 20)  /* 1Mb */
 static _odp_ishm_pool_t *list_elt_pool;
 
 typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t;
 typedef struct _odpdrv_enumr_s _odpdrv_enumr_t;
+typedef struct _odpdrv_device_s _odpdrv_device_t;
 
 /* an enumerator class (list element) */
 struct _odpdrv_enumr_class_s {
@@ -55,6 +58,20 @@ typedef struct _odpdrv_enumr_lst_t {
 } _odpdrv_enumr_lst_t;
 static struct _odpdrv_enumr_lst_t enumr_lst;
 
+/* a device (list element) */
+struct _odpdrv_device_s {
+       odpdrv_device_param_t param;
+       void (*enumr_destroy_callback)(void *enum_dev);/*dev destroy callback */
+       struct _odpdrv_device_s *next;
+} _odpdrv_device_s;
+
+/* the device list (all devices, from all enumerators): */
+typedef struct _odpdrv_device_lst_t {
+       odp_rwlock_recursive_t lock;
+       _odpdrv_device_t *head;
+} _odpdrv_device_lst_t;
+static struct _odpdrv_device_lst_t device_lst;
+
 /* some driver elements (such as enumeraor classes, drivers, devio) may
  * register before init_global and init_local complete. Mutex will fail
  * in this cases but should be used later on.
@@ -108,6 +125,30 @@ static void enumr_list_write_unlock(void)
                odp_rwlock_recursive_write_unlock(&enumr_lst.lock);
 }
 
+static void dev_list_read_lock(void)
+{
+       if (init_global_status == DONE)
+               odp_rwlock_recursive_read_lock(&device_lst.lock);
+}
+
+static void dev_list_read_unlock(void)
+{
+       if (init_global_status == DONE)
+               odp_rwlock_recursive_read_unlock(&device_lst.lock);
+}
+
+static void dev_list_write_lock(void)
+{
+       if (init_global_status == DONE)
+               odp_rwlock_recursive_write_lock(&device_lst.lock);
+}
+
+static void dev_list_write_unlock(void)
+{
+       if (init_global_status == DONE)
+               odp_rwlock_recursive_write_unlock(&device_lst.lock);
+}
+
 odpdrv_enumr_class_t odpdrv_enumr_class_register(odpdrv_enumr_class_param_t
                                                 *param)
 {
@@ -222,24 +263,119 @@ odpdrv_enumr_t 
odpdrv_enumr_register(odpdrv_enumr_param_t *param)
 
 odpdrv_device_t odpdrv_device_create(odpdrv_device_param_t *param)
 {
-       ODP_ERR("odpdrv_device_create not Supported yet! devaddress: %s\n.",
-               param->address);
-       return ODPDRV_DEVICE_INVALID;
+       _odpdrv_device_t *dev;
+
+       /* If init_global has not been done yet, we have a big issue. */
+       if (init_global_status == UNDONE)
+               return ODPDRV_DEVICE_INVALID;
+
+       /* make sure that the provided device address does not already exist: */
+       dev_list_read_lock();
+       dev = device_lst.head;
+       while (dev) {
+               if (strcmp(param->address, dev->param.address) == 0) {
+                       ODP_ERR("device already exists!\n");
+                       dev_list_read_unlock();
+                       return ODPDRV_DEVICE_INVALID;
+               }
+               dev = dev->next;
+       }
+       dev_list_read_unlock();
+
+       dev = _odp_ishm_pool_alloc(list_elt_pool,
+                                  sizeof(_odpdrv_device_t));
+       if (!dev) {
+               ODP_ERR("_odp_ishm_pool_alloc failed!\n");
+               return ODPDRV_DEVICE_INVALID;
+       }
+
+       /* save and set dev init parameters and insert new device in list */
+       dev->param = *param;
+       dev->enumr_destroy_callback = NULL;
+       dev_list_write_lock();
+       dev->next = device_lst.head;
+       device_lst.head = dev;
+       dev_list_write_unlock();
+
+       /* todo: probe for drivers */
+
+       return (odpdrv_device_t)dev;
 }
 
 int odpdrv_device_destroy(odpdrv_device_t dev,
                          void (*callback)(void *enum_dev), uint32_t flags)
 {
-       if (dev == ODPDRV_DEVICE_INVALID)
+       _odpdrv_device_t *device = (_odpdrv_device_t *)(void *)dev;
+       _odpdrv_device_t *_dev;
+       _odpdrv_device_t *target = NULL;
+
+       if (dev == ODPDRV_DEVICE_INVALID) {
                ODP_ERR("Invalid device\n");
-       if (callback != NULL)
-               ODP_ERR("Callback not supported yet\n");
-       if (flags != 0)
-               ODP_ERR("flags not supported yet\n");
+               return -1;
+       }
+
+       if (flags & ODPDRV_DEV_DESTROY_IMMEDIATE)
+               ODP_ERR("ODPDRV_DEV_DESTROY_IMMEDIATE not supported yet\n");
+
+       /* remove the device from the device list (but keep the device): */
+       dev_list_write_lock();
+       if (device == device_lst.head) {
+               target = device;
+               device_lst.head = device_lst.head->next;
+       } else {
+               _dev = device_lst.head;
+               while (_dev) {
+                       if (_dev->next == device) {
+                               target = device;
+                               _dev->next = _dev->next->next;
+                               break;
+                       }
+                       _dev = _dev->next;
+               }
+       }
+       dev_list_write_unlock();
+
+       if (!target) {
+               ODP_ERR("Unknown device (cannot be removed)!\n");
+               return -1;
+       }
+
+       /* save the enumerator callback function which should be called
+        * when the driver is unbound (for gracious removal):
+        */
+       target->enumr_destroy_callback = callback;
+
+       /* TODO: if a driver is bound to the device, unbind it!
+        * passing the flag andf device_destroy_terminate() as a callback */
+
+       /* no driver is handling this device, or no callback was
+        * provided: continue removing the device: */
+       device_destroy_terminate(dev);
 
        return 0;
 }
 
+/* This function is called as a callback from the driver, when unbindind
+ * a device, or directely from odpdrv_device_destroy() if no driver
+ * was bound to the device.
+ * just call the enumerator callback to cleanup the enumerator part
+ * and free device memory */
+static void device_destroy_terminate(odpdrv_device_t drv_device)
+{
+       _odpdrv_device_t *device = (_odpdrv_device_t *)(void *)drv_device;
+       void (*callback)(void *enum_dev);
+
+       /* get the enumerator callback function */
+       callback = device->enumr_destroy_callback;
+
+       /* let the enumerator cleanup his part: */
+       if (callback != NULL)
+               callback(device->param.enum_dev);
+
+       /* free device memory: */
+       _odp_ishm_pool_free(list_elt_pool, device);
+}
+
 odpdrv_devio_t odpdrv_devio_register(odpdrv_devio_param_t *param)
 {
        ODP_ERR("NOT Supported yet! Driver %s Registration!\n.",
@@ -295,6 +431,7 @@ int odpdrv_print_all(void)
 {
        _odpdrv_enumr_class_t *enumr_c;
        _odpdrv_enumr_t *enumr;
+       _odpdrv_device_t *dev;
 
        /* we cannot use ODP_DBG before ODP init... */
        if (init_global_status == UNDONE)
@@ -327,6 +464,24 @@ int odpdrv_print_all(void)
        }
        enumr_list_read_unlock();
 
+       /* print the list of registered devices: */
+       dev_list_read_lock();
+       dev = device_lst.head;
+       ODP_DBG("The following devices have been registered:\n");
+       while (dev) {
+               enumr = (_odpdrv_enumr_t *)(void *)dev->param.enumerator;
+               enumr_c = (_odpdrv_enumr_class_t *)
+                                             (void *)enumr->param.enumr_class;
+               ODP_DBG(" device: address: %s, from enumerator class: %s "
+                       "  API: %s, Version: %d\n",
+                       dev->param.address,
+                       enumr_c->param.name,
+                       enumr->param.api_name,
+                       enumr->param.api_version);
+               dev = dev->next;
+       }
+       dev_list_read_unlock();
+
        return 0;
 }
 
@@ -343,6 +498,7 @@ int _odpdrv_driver_init_global(void)
        /* from now, we want to ensure mutex on the list: init lock: */
        odp_rwlock_recursive_init(&enumr_class_lst.lock);
        odp_rwlock_recursive_init(&enumr_lst.lock);
+       odp_rwlock_recursive_init(&device_lst.lock);
 
        /* probe things... */
        _odpdrv_driver_probe_drv_items();
-- 
2.7.4

Reply via email to