Ignore:
File:
1 edited

Legend:

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

    r79a141a rf278930  
    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);
     
    139147find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
    140148{
     149        interrupt_context_t *ctx;
     150       
    141151        fibril_mutex_lock(&list->mutex);
    142152       
    143         link_t *link = list->contexts.next;
    144         interrupt_context_t *ctx;
    145        
    146         while (link != &list->contexts) {
     153        list_foreach(list->contexts, link) {
    147154                ctx = list_get_instance(link, interrupt_context_t, link);
    148155                if (ctx->id == id) {
     
    150157                        return ctx;
    151158                }
    152                 link = link->next;
    153159        }
    154160       
     
    160166find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
    161167{
     168        interrupt_context_t *ctx;
     169       
    162170        fibril_mutex_lock(&list->mutex);
    163171       
    164         link_t *link = list->contexts.next;
    165         interrupt_context_t *ctx;
    166        
    167         while (link != &list->contexts) {
     172        list_foreach(list->contexts, link) {
    168173                ctx = list_get_instance(link, interrupt_context_t, link);
    169174                if (ctx->irq == irq && ctx->dev == dev) {
     
    171176                        return ctx;
    172177                }
    173                 link = link->next;
    174178        }
    175179       
     
    231235}
    232236
    233 static ddf_fun_t *driver_get_function(link_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)
    234253{
    235254        ddf_fun_t *fun = NULL;
    236255       
    237         fibril_mutex_lock(&functions_mutex);
    238         link_t *link = functions->next;
    239        
    240         while (link != functions) {
     256        assert(fibril_mutex_is_locked(&functions_mutex));
     257       
     258        list_foreach(functions, link) {
    241259                fun = list_get_instance(link, ddf_fun_t, link);
    242                 if (fun->handle == handle) {
    243                         fibril_mutex_unlock(&functions_mutex);
     260                if (fun->handle == handle)
    244261                        return fun;
    245                 }
    246                
    247                 link = link->next;
    248         }
    249        
    250         fibril_mutex_unlock(&functions_mutex);
     262        }
    251263       
    252264        return NULL;
    253265}
    254266
    255 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)
    256268{
    257269        char *dev_name = NULL;
     
    262274       
    263275        ddf_dev_t *dev = create_device();
     276
     277        /* Add one reference that will be dropped by driver_dev_remove() */
     278        dev_add_ref(dev);
    264279        dev->handle = dev_handle;
    265280
     
    274289       
    275290        res = driver->driver_ops->add_device(dev);
    276         if (res != EOK)
    277                 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);
    278301       
    279302        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        if (dev != NULL)
     316                dev_add_ref(dev);
     317        fibril_mutex_unlock(&devices_mutex);
     318       
     319        if (dev == NULL) {
     320                async_answer_0(iid, ENOENT);
     321                return;
     322        }
     323       
     324        if (driver->driver_ops->dev_remove != NULL)
     325                rc = driver->driver_ops->dev_remove(dev);
     326        else
     327                rc = ENOTSUP;
     328       
     329        if (rc == EOK)
     330                dev_del_ref(dev);
     331       
     332        async_answer_0(iid, (sysarg_t) rc);
     333}
     334
     335static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     336{
     337        devman_handle_t funh;
     338        ddf_fun_t *fun;
     339        int rc;
     340       
     341        funh = IPC_GET_ARG1(*icall);
     342       
     343        /*
     344         * Look the function up. Bump reference count so that
     345         * the function continues to exist until we return
     346         * from the driver.
     347         */
     348        fibril_mutex_lock(&functions_mutex);
     349       
     350        fun = driver_get_function(funh);
     351        if (fun != NULL)
     352                fun_add_ref(fun);
     353       
     354        fibril_mutex_unlock(&functions_mutex);
     355       
     356        if (fun == NULL) {
     357                async_answer_0(iid, ENOENT);
     358                return;
     359        }
     360       
     361        /* Call driver entry point */
     362        if (driver->driver_ops->fun_online != NULL)
     363                rc = driver->driver_ops->fun_online(fun);
     364        else
     365                rc = ENOTSUP;
     366       
     367        fun_del_ref(fun);
     368       
     369        async_answer_0(iid, (sysarg_t) rc);
     370}
     371
     372static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     373{
     374        devman_handle_t funh;
     375        ddf_fun_t *fun;
     376        int rc;
     377       
     378        funh = IPC_GET_ARG1(*icall);
     379       
     380        /*
     381         * Look the function up. Bump reference count so that
     382         * the function continues to exist until we return
     383         * from the driver.
     384         */
     385        fibril_mutex_lock(&functions_mutex);
     386       
     387        fun = driver_get_function(funh);
     388        if (fun != NULL)
     389                fun_add_ref(fun);
     390       
     391        fibril_mutex_unlock(&functions_mutex);
     392       
     393        if (fun == NULL) {
     394                async_answer_0(iid, ENOENT);
     395                return;
     396        }
     397       
     398        /* Call driver entry point */
     399        if (driver->driver_ops->fun_offline != NULL)
     400                rc = driver->driver_ops->fun_offline(fun);
     401        else
     402                rc = ENOTSUP;
     403       
     404        async_answer_0(iid, (sysarg_t) rc);
    280405}
    281406
     
    293418               
    294419                switch (IPC_GET_IMETHOD(call)) {
    295                 case DRIVER_ADD_DEVICE:
    296                         driver_add_device(callid, &call);
     420                case DRIVER_DEV_ADD:
     421                        driver_dev_add(callid, &call);
     422                        break;
     423                case DRIVER_DEV_REMOVE:
     424                        driver_dev_remove(callid, &call);
     425                        break;
     426                case DRIVER_FUN_ONLINE:
     427                        driver_fun_online(callid, &call);
     428                        break;
     429                case DRIVER_FUN_OFFLINE:
     430                        driver_fun_offline(callid, &call);
    297431                        break;
    298432                default:
    299                         async_answer_0(callid, ENOENT);
     433                        async_answer_0(callid, ENOTSUP);
    300434                }
    301435        }
     
    315449         */
    316450        devman_handle_t handle = IPC_GET_ARG2(*icall);
    317         ddf_fun_t *fun = driver_get_function(&functions, handle);
     451
     452        fibril_mutex_lock(&functions_mutex);
     453        ddf_fun_t *fun = driver_get_function(handle);
     454        fibril_mutex_unlock(&functions_mutex);
     455        /* XXX Need a lock on fun */
    318456       
    319457        if (fun == NULL) {
     
    321459                    " %" PRIun " was found.\n", driver->name, handle);
    322460                async_answer_0(iid, ENOENT);
     461                return;
     462        }
     463       
     464        if (fun->conn_handler != NULL) {
     465                /* Driver has a custom connection handler. */
     466                (*fun->conn_handler)(iid, icall, (void *)fun);
    323467                return;
    324468        }
     
    427571
    428572/** Function for handling connections to device driver. */
    429 static void driver_connection(ipc_callid_t iid, ipc_call_t *icall)
    430 {
     573static void driver_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     574{
     575        sysarg_t conn_type;
     576
     577        if (iid == 0) {
     578                /* Callback connection from devman */
     579                /* XXX Use separate handler for this type of connection */
     580                conn_type = DRIVER_DEVMAN;
     581        } else {
     582                conn_type = IPC_GET_ARG1(*icall);
     583        }
     584
    431585        /* Select interface */
    432         switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
     586        switch (conn_type) {
    433587        case DRIVER_DEVMAN:
    434588                /* Handle request from device manager */
     
    457611        ddf_dev_t *dev;
    458612
    459         dev = malloc(sizeof(ddf_dev_t));
     613        dev = calloc(1, sizeof(ddf_dev_t));
    460614        if (dev == NULL)
    461615                return NULL;
    462616
    463         memset(dev, 0, sizeof(ddf_dev_t));
    464617        return dev;
    465618}
     
    489642static void delete_device(ddf_dev_t *dev)
    490643{
     644        if (dev->driver_data != NULL)
     645                free(dev->driver_data);
    491646        free(dev);
    492647}
    493648
    494 /** Delete device structure.
     649/** Delete function structure.
    495650 *
    496651 * @param dev           The device structure.
     
    499654{
    500655        clean_match_ids(&fun->match_ids);
     656        if (fun->driver_data != NULL)
     657                free(fun->driver_data);
    501658        if (fun->name != NULL)
    502659                free(fun->name);
     
    504661}
    505662
     663/** Increase device reference count. */
     664static void dev_add_ref(ddf_dev_t *dev)
     665{
     666        atomic_inc(&dev->refcnt);
     667}
     668
     669/** Decrease device reference count.
     670 *
     671 * Free the device structure if the reference count drops to zero.
     672 */
     673static void dev_del_ref(ddf_dev_t *dev)
     674{
     675        if (atomic_predec(&dev->refcnt) == 0)
     676                delete_device(dev);
     677}
     678
     679/** Increase function reference count.
     680 *
     681 * This also increases reference count on the device. The device structure
     682 * will thus not be deallocated while there are some associated function
     683 * structures.
     684 */
     685static void fun_add_ref(ddf_fun_t *fun)
     686{
     687        dev_add_ref(fun->dev);
     688        atomic_inc(&fun->refcnt);
     689}
     690
     691/** Decrease function reference count.
     692 *
     693 * Free the function structure if the reference count drops to zero.
     694 */
     695static void fun_del_ref(ddf_fun_t *fun)
     696{
     697        ddf_dev_t *dev = fun->dev;
     698
     699        if (atomic_predec(&fun->refcnt) == 0)
     700                delete_function(fun);
     701
     702        dev_del_ref(dev);
     703}
     704
     705/** Allocate driver-specific device data. */
     706extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     707{
     708        void *data;
     709
     710        assert(dev->driver_data == NULL);
     711
     712        data = calloc(1, size);
     713        if (data == NULL)
     714                return NULL;
     715
     716        dev->driver_data = data;
     717        return data;
     718}
     719
    506720/** Create a DDF function node.
    507721 *
     
    535749                return NULL;
    536750
     751        /* Add one reference that will be dropped by ddf_fun_destroy() */
     752        fun->dev = dev;
     753        fun_add_ref(fun);
     754
    537755        fun->bound = false;
    538         fun->dev = dev;
    539756        fun->ftype = ftype;
    540757
     
    548765}
    549766
     767/** Allocate driver-specific function data. */
     768extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     769{
     770        void *data;
     771
     772        assert(fun->bound == false);
     773        assert(fun->driver_data == NULL);
     774
     775        data = calloc(1, size);
     776        if (data == NULL)
     777                return NULL;
     778
     779        fun->driver_data = data;
     780        return data;
     781}
     782
    550783/** Destroy DDF function node.
    551784 *
     
    558791{
    559792        assert(fun->bound == false);
    560         delete_function(fun);
     793
     794        /*
     795         * Drop the reference added by ddf_fun_create(). This will deallocate
     796         * the function as soon as all other references are dropped (i.e.
     797         * as soon control leaves all driver entry points called in context
     798         * of this function.
     799         */
     800        fun_del_ref(fun);
    561801}
    562802
     
    583823int ddf_fun_bind(ddf_fun_t *fun)
    584824{
     825        assert(fun->bound == false);
    585826        assert(fun->name != NULL);
    586827       
     
    599840}
    600841
     842/** Unbind a function node.
     843 *
     844 * Unbind the specified function from the system. This effectively makes
     845 * the function invisible to the system.
     846 *
     847 * @param fun           Function to unbind
     848 * @return              EOK on success or negative error code
     849 */
     850int ddf_fun_unbind(ddf_fun_t *fun)
     851{
     852        int res;
     853       
     854        assert(fun->bound == true);
     855       
     856        res = devman_remove_function(fun->handle);
     857        if (res != EOK)
     858                return res;
     859
     860        remove_from_functions_list(fun);
     861       
     862        fun->bound = false;
     863        return EOK;
     864}
     865
     866/** Online function.
     867 *
     868 * @param fun           Function to online
     869 * @return              EOK on success or negative error code
     870 */
     871int ddf_fun_online(ddf_fun_t *fun)
     872{
     873        int res;
     874       
     875        assert(fun->bound == true);
     876       
     877        res = devman_drv_fun_online(fun->handle);
     878        if (res != EOK)
     879                return res;
     880       
     881        return EOK;
     882}
     883
     884/** Offline function.
     885 *
     886 * @param fun           Function to offline
     887 * @return              EOK on success or negative error code
     888 */
     889int ddf_fun_offline(ddf_fun_t *fun)
     890{
     891        int res;
     892       
     893        assert(fun->bound == true);
     894       
     895        res = devman_drv_fun_offline(fun->handle);
     896        if (res != EOK)
     897                return res;
     898       
     899        return EOK;
     900}
     901
    601902/** Add single match ID to inner function.
    602903 *
     
    621922                return ENOMEM;
    622923       
    623         match_id->id = match_id_str;
     924        match_id->id = str_dup(match_id_str);
    624925        match_id->score = 90;
    625926       
     
    636937}
    637938
    638 /** Add exposed function to class.
     939/** Add exposed function to category.
    639940 *
    640941 * Must only be called when the function is bound.
    641942 */
    642 int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
     943int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
    643944{
    644945        assert(fun->bound == true);
    645946        assert(fun->ftype == fun_exposed);
    646947       
    647         return devman_add_device_to_class(fun->handle, class_name);
     948        return devman_add_device_to_category(fun->handle, cat_name);
    648949}
    649950
Note: See TracChangeset for help on using the changeset viewer.