Changeset a1b7e80 in mainline for uspace/lib/drv/generic/driver.c


Ignore:
Timestamp:
2011-09-02T16:54:18Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f480d7e
Parents:
7a72ce1a (diff), 224c0e7 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge basic infrastructure for anticipated device removal from
lp:~jsvoboda/helenos/devrem

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/generic/driver.c

    r7a72ce1a ra1b7e80  
    6363
    6464/** Devices */
     65LIST_INITIALIZE(devices);
     66FIBRIL_MUTEX_INITIALIZE(devices_mutex);
     67
     68/** Functions */
    6569LIST_INITIALIZE(functions);
    6670FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     
    8286static ddf_dev_t *create_device(void);
    8387static void delete_device(ddf_dev_t *);
     88static void dev_add_ref(ddf_dev_t *);
     89static void dev_del_ref(ddf_dev_t *);
     90static void fun_add_ref(ddf_fun_t *);
     91static void fun_del_ref(ddf_fun_t *);
    8492static remote_handler_t *function_get_default_handler(ddf_fun_t *);
    8593static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
     
    227235}
    228236
    229 static ddf_fun_t *driver_get_function(list_t *functions, devman_handle_t handle)
     237static ddf_dev_t *driver_get_device(devman_handle_t handle)
     238{
     239        ddf_dev_t *dev = NULL;
     240       
     241        assert(fibril_mutex_is_locked(&devices_mutex));
     242       
     243        list_foreach(devices, link) {
     244                dev = list_get_instance(link, ddf_dev_t, link);
     245                if (dev->handle == handle)
     246                        return dev;
     247        }
     248       
     249        return NULL;
     250}
     251
     252static ddf_fun_t *driver_get_function(devman_handle_t handle)
    230253{
    231254        ddf_fun_t *fun = NULL;
    232255       
    233         fibril_mutex_lock(&functions_mutex);
    234        
    235         list_foreach(*functions, link) {
     256        assert(fibril_mutex_is_locked(&functions_mutex));
     257       
     258        list_foreach(functions, link) {
    236259                fun = list_get_instance(link, ddf_fun_t, link);
    237                 if (fun->handle == handle) {
    238                         fibril_mutex_unlock(&functions_mutex);
     260                if (fun->handle == handle)
    239261                        return fun;
    240                 }
    241         }
    242        
    243         fibril_mutex_unlock(&functions_mutex);
     262        }
    244263       
    245264        return NULL;
    246265}
    247266
    248 static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
     267static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    249268{
    250269        char *dev_name = NULL;
     
    255274       
    256275        ddf_dev_t *dev = create_device();
     276
     277        /* Add one reference that will be dropped by driver_dev_remove() */
     278        dev_add_ref(dev);
    257279        dev->handle = dev_handle;
    258280
     
    267289       
    268290        res = driver->driver_ops->add_device(dev);
    269         if (res != EOK)
    270                 delete_device(dev);
     291       
     292        if (res != EOK) {
     293                dev_del_ref(dev);
     294                async_answer_0(iid, res);
     295                return;
     296        }
     297       
     298        fibril_mutex_lock(&devices_mutex);
     299        list_append(&dev->link, &devices);
     300        fibril_mutex_unlock(&devices_mutex);
    271301       
    272302        async_answer_0(iid, res);
     303}
     304
     305static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
     306{
     307        devman_handle_t devh;
     308        ddf_dev_t *dev;
     309        int rc;
     310       
     311        devh = IPC_GET_ARG1(*icall);
     312       
     313        fibril_mutex_lock(&devices_mutex);
     314        dev = driver_get_device(devh);
     315        dev_add_ref(dev);
     316        fibril_mutex_unlock(&devices_mutex);
     317       
     318        if (dev == NULL) {
     319                async_answer_0(iid, ENOENT);
     320                return;
     321        }
     322       
     323        if (driver->driver_ops->dev_remove != NULL)
     324                rc = driver->driver_ops->dev_remove(dev);
     325        else
     326                rc = ENOTSUP;
     327       
     328        if (rc == EOK)
     329                dev_del_ref(dev);
     330       
     331        async_answer_0(iid, (sysarg_t) rc);
     332}
     333
     334static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     335{
     336        devman_handle_t funh;
     337        ddf_fun_t *fun;
     338        int rc;
     339       
     340        funh = IPC_GET_ARG1(*icall);
     341       
     342        /*
     343         * Look the function up. Bump reference count so that
     344         * the function continues to exist until we return
     345         * from the driver.
     346         */
     347        fibril_mutex_lock(&functions_mutex);
     348       
     349        fun = driver_get_function(funh);
     350        if (fun != NULL)
     351                fun_add_ref(fun);
     352       
     353        fibril_mutex_unlock(&functions_mutex);
     354       
     355        if (fun == NULL) {
     356                async_answer_0(iid, ENOENT);
     357                return;
     358        }
     359       
     360        /* Call driver entry point */
     361        if (driver->driver_ops->fun_online != NULL)
     362                rc = driver->driver_ops->fun_online(fun);
     363        else
     364                rc = ENOTSUP;
     365       
     366        fun_del_ref(fun);
     367       
     368        async_answer_0(iid, (sysarg_t) rc);
     369}
     370
     371static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     372{
     373        devman_handle_t funh;
     374        ddf_fun_t *fun;
     375        int rc;
     376       
     377        funh = IPC_GET_ARG1(*icall);
     378       
     379        /*
     380         * Look the function up. Bump reference count so that
     381         * the function continues to exist until we return
     382         * from the driver.
     383         */
     384        fibril_mutex_lock(&functions_mutex);
     385       
     386        fun = driver_get_function(funh);
     387        if (fun != NULL)
     388                fun_add_ref(fun);
     389       
     390        fibril_mutex_unlock(&functions_mutex);
     391       
     392        if (fun == NULL) {
     393                async_answer_0(iid, ENOENT);
     394                return;
     395        }
     396       
     397        /* Call driver entry point */
     398        if (driver->driver_ops->fun_offline != NULL)
     399                rc = driver->driver_ops->fun_offline(fun);
     400        else
     401                rc = ENOTSUP;
     402       
     403        async_answer_0(iid, (sysarg_t) rc);
    273404}
    274405
     
    286417               
    287418                switch (IPC_GET_IMETHOD(call)) {
    288                 case DRIVER_ADD_DEVICE:
    289                         driver_add_device(callid, &call);
     419                case DRIVER_DEV_ADD:
     420                        driver_dev_add(callid, &call);
     421                        break;
     422                case DRIVER_DEV_REMOVE:
     423                        driver_dev_remove(callid, &call);
     424                        break;
     425                case DRIVER_FUN_ONLINE:
     426                        driver_fun_online(callid, &call);
     427                        break;
     428                case DRIVER_FUN_OFFLINE:
     429                        driver_fun_offline(callid, &call);
    290430                        break;
    291431                default:
    292                         async_answer_0(callid, ENOENT);
     432                        async_answer_0(callid, ENOTSUP);
    293433                }
    294434        }
     
    308448         */
    309449        devman_handle_t handle = IPC_GET_ARG2(*icall);
    310         ddf_fun_t *fun = driver_get_function(&functions, handle);
     450
     451        fibril_mutex_lock(&functions_mutex);
     452        ddf_fun_t *fun = driver_get_function(handle);
     453        fibril_mutex_unlock(&functions_mutex);
     454        /* XXX Need a lock on fun */
    311455       
    312456        if (fun == NULL) {
     
    466610        ddf_dev_t *dev;
    467611
    468         dev = malloc(sizeof(ddf_dev_t));
     612        dev = calloc(1, sizeof(ddf_dev_t));
    469613        if (dev == NULL)
    470614                return NULL;
    471615
    472         memset(dev, 0, sizeof(ddf_dev_t));
    473616        return dev;
    474617}
     
    498641static void delete_device(ddf_dev_t *dev)
    499642{
     643        if (dev->driver_data != NULL)
     644                free(dev->driver_data);
    500645        free(dev);
    501646}
    502647
    503 /** Delete device structure.
     648/** Delete function structure.
    504649 *
    505650 * @param dev           The device structure.
     
    508653{
    509654        clean_match_ids(&fun->match_ids);
     655        if (fun->driver_data != NULL)
     656                free(fun->driver_data);
    510657        if (fun->name != NULL)
    511658                free(fun->name);
     
    513660}
    514661
     662/** Increase device reference count. */
     663static void dev_add_ref(ddf_dev_t *dev)
     664{
     665        atomic_inc(&dev->refcnt);
     666}
     667
     668/** Decrease device reference count.
     669 *
     670 * Free the device structure if the reference count drops to zero.
     671 */
     672static void dev_del_ref(ddf_dev_t *dev)
     673{
     674        if (atomic_predec(&dev->refcnt) == 0)
     675                delete_device(dev);
     676}
     677
     678/** Increase function reference count.
     679 *
     680 * This also increases reference count on the device. The device structure
     681 * will thus not be deallocated while there are some associated function
     682 * structures.
     683 */
     684static void fun_add_ref(ddf_fun_t *fun)
     685{
     686        dev_add_ref(fun->dev);
     687        atomic_inc(&fun->refcnt);
     688}
     689
     690/** Decrease function reference count.
     691 *
     692 * Free the function structure if the reference count drops to zero.
     693 */
     694static void fun_del_ref(ddf_fun_t *fun)
     695{
     696        ddf_dev_t *dev = fun->dev;
     697
     698        if (atomic_predec(&fun->refcnt) == 0)
     699                delete_function(fun);
     700
     701        dev_del_ref(dev);
     702}
     703
     704/** Allocate driver-specific device data. */
     705extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     706{
     707        void *data;
     708
     709        assert(dev->driver_data == NULL);
     710
     711        data = calloc(1, size);
     712        if (data == NULL)
     713                return NULL;
     714
     715        dev->driver_data = data;
     716        return data;
     717}
     718
    515719/** Create a DDF function node.
    516720 *
     
    544748                return NULL;
    545749
     750        /* Add one reference that will be dropped by ddf_fun_destroy() */
     751        fun->dev = dev;
     752        fun_add_ref(fun);
     753
    546754        fun->bound = false;
    547         fun->dev = dev;
    548755        fun->ftype = ftype;
    549756
     
    557764}
    558765
     766/** Allocate driver-specific function data. */
     767extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     768{
     769        void *data;
     770
     771        assert(fun->bound == false);
     772        assert(fun->driver_data == NULL);
     773
     774        data = calloc(1, size);
     775        if (data == NULL)
     776                return NULL;
     777
     778        fun->driver_data = data;
     779        return data;
     780}
     781
    559782/** Destroy DDF function node.
    560783 *
     
    567790{
    568791        assert(fun->bound == false);
    569         delete_function(fun);
     792
     793        /*
     794         * Drop the reference added by ddf_fun_create(). This will deallocate
     795         * the function as soon as all other references are dropped (i.e.
     796         * as soon control leaves all driver entry points called in context
     797         * of this function.
     798         */
     799        fun_del_ref(fun);
    570800}
    571801
     
    614844 * the function invisible to the system.
    615845 *
    616  * @param fun           Function to bind
     846 * @param fun           Function to unbind
    617847 * @return              EOK on success or negative error code
    618848 */
     
    623853        assert(fun->bound == true);
    624854       
    625         add_to_functions_list(fun);
    626855        res = devman_remove_function(fun->handle);
    627856        if (res != EOK)
     
    631860       
    632861        fun->bound = false;
     862        return EOK;
     863}
     864
     865/** Online function.
     866 *
     867 * @param fun           Function to online
     868 * @return              EOK on success or negative error code
     869 */
     870int ddf_fun_online(ddf_fun_t *fun)
     871{
     872        int res;
     873       
     874        assert(fun->bound == true);
     875       
     876        res = devman_drv_fun_online(fun->handle);
     877        if (res != EOK)
     878                return res;
     879       
     880        return EOK;
     881}
     882
     883/** Offline function.
     884 *
     885 * @param fun           Function to offline
     886 * @return              EOK on success or negative error code
     887 */
     888int ddf_fun_offline(ddf_fun_t *fun)
     889{
     890        int res;
     891       
     892        assert(fun->bound == true);
     893       
     894        res = devman_drv_fun_offline(fun->handle);
     895        if (res != EOK)
     896                return res;
     897       
    633898        return EOK;
    634899}
Note: See TracChangeset for help on using the changeset viewer.