On Wed, Feb 22, 2017 at 6:55 AM, Christophe Milard < christophe.mil...@linaro.org> wrote:
> 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) > 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 > >