diff mbox series

[API-NEXT,08/21] linux-gen: drv: device creation and deletion

Message ID 1487768164-43184-9-git-send-email-christophe.milard@linaro.org
State Superseded
Headers show
Series driver items registration and probing | expand

Commit Message

Christophe Milard Feb. 22, 2017, 12:55 p.m. UTC
Functions to create and remove devices are populated to do
more proper things.

Signed-off-by: Christophe Milard <christophe.milard@linaro.org>

---
 platform/linux-generic/drv_driver.c | 172 ++++++++++++++++++++++++++++++++++--
 1 file changed, 164 insertions(+), 8 deletions(-)

-- 
2.7.4

Comments

Bill Fischofer Feb. 22, 2017, 10:28 p.m. UTC | #1
On Wed, Feb 22, 2017 at 6:55 AM, Christophe Milard <
christophe.milard@linaro.org> wrote:

> Functions to create and remove devices are populated to do

> more proper things.

>

> Signed-off-by: Christophe Milard <christophe.milard@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)

>


Same comment as for earlier locking routines regarding the necessity of
these guards.


> +               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;

>


Same question as for other lists. Where is the head field initialized? This
should be done in the init routine along with lock initialization.


> +       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

>

>
Christophe Milard Feb. 27, 2017, 12:58 p.m. UTC | #2
On 22 February 2017 at 23:28, Bill Fischofer <bill.fischofer@linaro.org> wrote:
>

>

> On Wed, Feb 22, 2017 at 6:55 AM, Christophe Milard

> <christophe.milard@linaro.org> wrote:

>>

>> Functions to create and remove devices are populated to do

>> more proper things.

>>

>> Signed-off-by: Christophe Milard <christophe.milard@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)

>

>

> Same comment as for earlier locking routines regarding the necessity of

> these guards.


Hope my previous answer made that clear :-)

>

>>

>> +               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;

>

>

> Same question as for other lists. Where is the head field initialized? This

> should be done in the init routine along with lock initialization.


hope my previous answer made that clear

Christophe

>

>>

>> +       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

>>

>
diff mbox series

Patch

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();