Ignore:
File:
1 edited

Legend:

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

    rf278930 r79a141a  
    6363
    6464/** Devices */
    65 LIST_INITIALIZE(devices);
    66 FIBRIL_MUTEX_INITIALIZE(devices_mutex);
    67 
    68 /** Functions */
    6965LIST_INITIALIZE(functions);
    7066FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     
    8682static ddf_dev_t *create_device(void);
    8783static void delete_device(ddf_dev_t *);
    88 static void dev_add_ref(ddf_dev_t *);
    89 static void dev_del_ref(ddf_dev_t *);
    90 static void fun_add_ref(ddf_fun_t *);
    91 static void fun_del_ref(ddf_fun_t *);
    9284static remote_handler_t *function_get_default_handler(ddf_fun_t *);
    9385static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
     
    147139find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
    148140{
     141        fibril_mutex_lock(&list->mutex);
     142       
     143        link_t *link = list->contexts.next;
    149144        interrupt_context_t *ctx;
    150145       
    151         fibril_mutex_lock(&list->mutex);
    152        
    153         list_foreach(list->contexts, link) {
     146        while (link != &list->contexts) {
    154147                ctx = list_get_instance(link, interrupt_context_t, link);
    155148                if (ctx->id == id) {
     
    157150                        return ctx;
    158151                }
     152                link = link->next;
    159153        }
    160154       
     
    166160find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
    167161{
     162        fibril_mutex_lock(&list->mutex);
     163       
     164        link_t *link = list->contexts.next;
    168165        interrupt_context_t *ctx;
    169166       
    170         fibril_mutex_lock(&list->mutex);
    171        
    172         list_foreach(list->contexts, link) {
     167        while (link != &list->contexts) {
    173168                ctx = list_get_instance(link, interrupt_context_t, link);
    174169                if (ctx->irq == irq && ctx->dev == dev) {
     
    176171                        return ctx;
    177172                }
     173                link = link->next;
    178174        }
    179175       
     
    235231}
    236232
    237 static 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         }
     233static ddf_fun_t *driver_get_function(link_t *functions, devman_handle_t handle)
     234{
     235        ddf_fun_t *fun = NULL;
     236       
     237        fibril_mutex_lock(&functions_mutex);
     238        link_t *link = functions->next;
     239       
     240        while (link != functions) {
     241                fun = list_get_instance(link, ddf_fun_t, link);
     242                if (fun->handle == handle) {
     243                        fibril_mutex_unlock(&functions_mutex);
     244                        return fun;
     245                }
     246               
     247                link = link->next;
     248        }
     249       
     250        fibril_mutex_unlock(&functions_mutex);
    248251       
    249252        return NULL;
    250253}
    251254
    252 static ddf_fun_t *driver_get_function(devman_handle_t handle)
    253 {
    254         ddf_fun_t *fun = NULL;
    255        
    256         assert(fibril_mutex_is_locked(&functions_mutex));
    257        
    258         list_foreach(functions, link) {
    259                 fun = list_get_instance(link, ddf_fun_t, link);
    260                 if (fun->handle == handle)
    261                         return fun;
    262         }
    263        
    264         return NULL;
    265 }
    266 
    267 static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
     255static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
    268256{
    269257        char *dev_name = NULL;
     
    274262       
    275263        ddf_dev_t *dev = create_device();
    276 
    277         /* Add one reference that will be dropped by driver_dev_remove() */
    278         dev_add_ref(dev);
    279264        dev->handle = dev_handle;
    280265
     
    289274       
    290275        res = driver->driver_ops->add_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);
     276        if (res != EOK)
     277                delete_device(dev);
    301278       
    302279        async_answer_0(iid, res);
    303 }
    304 
    305 static 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 
    335 static 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 
    372 static 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);
    405280}
    406281
     
    418293               
    419294                switch (IPC_GET_IMETHOD(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);
     295                case DRIVER_ADD_DEVICE:
     296                        driver_add_device(callid, &call);
    431297                        break;
    432298                default:
    433                         async_answer_0(callid, ENOTSUP);
     299                        async_answer_0(callid, ENOENT);
    434300                }
    435301        }
     
    449315         */
    450316        devman_handle_t handle = IPC_GET_ARG2(*icall);
    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 */
     317        ddf_fun_t *fun = driver_get_function(&functions, handle);
    456318       
    457319        if (fun == NULL) {
     
    459321                    " %" PRIun " was found.\n", driver->name, handle);
    460322                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);
    467323                return;
    468324        }
     
    571427
    572428/** Function for handling connections to device driver. */
    573 static 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 
     429static void driver_connection(ipc_callid_t iid, ipc_call_t *icall)
     430{
    585431        /* Select interface */
    586         switch (conn_type) {
     432        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    587433        case DRIVER_DEVMAN:
    588434                /* Handle request from device manager */
     
    611457        ddf_dev_t *dev;
    612458
    613         dev = calloc(1, sizeof(ddf_dev_t));
     459        dev = malloc(sizeof(ddf_dev_t));
    614460        if (dev == NULL)
    615461                return NULL;
    616462
     463        memset(dev, 0, sizeof(ddf_dev_t));
    617464        return dev;
    618465}
     
    642489static void delete_device(ddf_dev_t *dev)
    643490{
    644         if (dev->driver_data != NULL)
    645                 free(dev->driver_data);
    646491        free(dev);
    647492}
    648493
    649 /** Delete function structure.
     494/** Delete device structure.
    650495 *
    651496 * @param dev           The device structure.
     
    654499{
    655500        clean_match_ids(&fun->match_ids);
    656         if (fun->driver_data != NULL)
    657                 free(fun->driver_data);
    658501        if (fun->name != NULL)
    659502                free(fun->name);
     
    661504}
    662505
    663 /** Increase device reference count. */
    664 static 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  */
    673 static 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  */
    685 static 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  */
    695 static 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. */
    706 extern 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 
    720506/** Create a DDF function node.
    721507 *
     
    749535                return NULL;
    750536
    751         /* Add one reference that will be dropped by ddf_fun_destroy() */
     537        fun->bound = false;
    752538        fun->dev = dev;
    753         fun_add_ref(fun);
    754 
    755         fun->bound = false;
    756539        fun->ftype = ftype;
    757540
     
    765548}
    766549
    767 /** Allocate driver-specific function data. */
    768 extern 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 
    783550/** Destroy DDF function node.
    784551 *
     
    791558{
    792559        assert(fun->bound == false);
    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);
     560        delete_function(fun);
    801561}
    802562
     
    823583int ddf_fun_bind(ddf_fun_t *fun)
    824584{
    825         assert(fun->bound == false);
    826585        assert(fun->name != NULL);
    827586       
     
    840599}
    841600
    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  */
    850 int 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  */
    871 int 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  */
    889 int 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 
    902601/** Add single match ID to inner function.
    903602 *
     
    922621                return ENOMEM;
    923622       
    924         match_id->id = str_dup(match_id_str);
     623        match_id->id = match_id_str;
    925624        match_id->score = 90;
    926625       
     
    937636}
    938637
    939 /** Add exposed function to category.
     638/** Add exposed function to class.
    940639 *
    941640 * Must only be called when the function is bound.
    942641 */
    943 int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
     642int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
    944643{
    945644        assert(fun->bound == true);
    946645        assert(fun->ftype == fun_exposed);
    947646       
    948         return devman_add_device_to_category(fun->handle, cat_name);
     647        return devman_add_device_to_class(fun->handle, class_name);
    949648}
    950649
Note: See TracChangeset for help on using the changeset viewer.