Ignore:
File:
1 edited

Legend:

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

    r80a96d2 rb72efe8  
    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);
     
    235227}
    236228
    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         }
     229static ddf_fun_t *driver_get_function(list_t *functions, devman_handle_t handle)
     230{
     231        ddf_fun_t *fun = NULL;
     232       
     233        fibril_mutex_lock(&functions_mutex);
     234       
     235        list_foreach(*functions, link) {
     236                fun = list_get_instance(link, ddf_fun_t, link);
     237                if (fun->handle == handle) {
     238                        fibril_mutex_unlock(&functions_mutex);
     239                        return fun;
     240                }
     241        }
     242       
     243        fibril_mutex_unlock(&functions_mutex);
    248244       
    249245        return NULL;
    250246}
    251247
    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)
     248static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
    268249{
    269250        char *dev_name = NULL;
     
    274255       
    275256        ddf_dev_t *dev = create_device();
    276 
    277         /* Add one reference that will be dropped by driver_dev_remove() */
    278         dev_add_ref(dev);
    279257        dev->handle = dev_handle;
    280258
     
    289267       
    290268        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);
     269        if (res != EOK)
     270                delete_device(dev);
    301271       
    302272        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_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
    336 {
    337         devman_handle_t devh;
    338         ddf_dev_t *dev;
    339         int rc;
    340        
    341         devh = IPC_GET_ARG1(*icall);
    342        
    343         fibril_mutex_lock(&devices_mutex);
    344         dev = driver_get_device(devh);
    345         if (dev != NULL)
    346                 dev_add_ref(dev);
    347         fibril_mutex_unlock(&devices_mutex);
    348        
    349         if (dev == NULL) {
    350                 async_answer_0(iid, ENOENT);
    351                 return;
    352         }
    353        
    354         if (driver->driver_ops->dev_gone != NULL)
    355                 rc = driver->driver_ops->dev_gone(dev);
    356         else
    357                 rc = ENOTSUP;
    358        
    359         if (rc == EOK)
    360                 dev_del_ref(dev);
    361        
    362         async_answer_0(iid, (sysarg_t) rc);
    363 }
    364 
    365 static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    366 {
    367         devman_handle_t funh;
    368         ddf_fun_t *fun;
    369         int rc;
    370        
    371         funh = IPC_GET_ARG1(*icall);
    372        
    373         /*
    374          * Look the function up. Bump reference count so that
    375          * the function continues to exist until we return
    376          * from the driver.
    377          */
    378         fibril_mutex_lock(&functions_mutex);
    379        
    380         fun = driver_get_function(funh);
    381         if (fun != NULL)
    382                 fun_add_ref(fun);
    383        
    384         fibril_mutex_unlock(&functions_mutex);
    385        
    386         if (fun == NULL) {
    387                 async_answer_0(iid, ENOENT);
    388                 return;
    389         }
    390        
    391         /* Call driver entry point */
    392         if (driver->driver_ops->fun_online != NULL)
    393                 rc = driver->driver_ops->fun_online(fun);
    394         else
    395                 rc = ENOTSUP;
    396        
    397         fun_del_ref(fun);
    398        
    399         async_answer_0(iid, (sysarg_t) rc);
    400 }
    401 
    402 static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    403 {
    404         devman_handle_t funh;
    405         ddf_fun_t *fun;
    406         int rc;
    407        
    408         funh = IPC_GET_ARG1(*icall);
    409        
    410         /*
    411          * Look the function up. Bump reference count so that
    412          * the function continues to exist until we return
    413          * from the driver.
    414          */
    415         fibril_mutex_lock(&functions_mutex);
    416        
    417         fun = driver_get_function(funh);
    418         if (fun != NULL)
    419                 fun_add_ref(fun);
    420        
    421         fibril_mutex_unlock(&functions_mutex);
    422        
    423         if (fun == NULL) {
    424                 async_answer_0(iid, ENOENT);
    425                 return;
    426         }
    427        
    428         /* Call driver entry point */
    429         if (driver->driver_ops->fun_offline != NULL)
    430                 rc = driver->driver_ops->fun_offline(fun);
    431         else
    432                 rc = ENOTSUP;
    433        
    434         async_answer_0(iid, (sysarg_t) rc);
    435273}
    436274
     
    448286               
    449287                switch (IPC_GET_IMETHOD(call)) {
    450                 case DRIVER_DEV_ADD:
    451                         driver_dev_add(callid, &call);
    452                         break;
    453                 case DRIVER_DEV_REMOVE:
    454                         driver_dev_remove(callid, &call);
    455                         break;
    456                 case DRIVER_DEV_GONE:
    457                         driver_dev_gone(callid, &call);
    458                         break;
    459                 case DRIVER_FUN_ONLINE:
    460                         driver_fun_online(callid, &call);
    461                         break;
    462                 case DRIVER_FUN_OFFLINE:
    463                         driver_fun_offline(callid, &call);
     288                case DRIVER_ADD_DEVICE:
     289                        driver_add_device(callid, &call);
    464290                        break;
    465291                default:
    466                         async_answer_0(callid, ENOTSUP);
     292                        async_answer_0(callid, ENOENT);
    467293                }
    468294        }
     
    482308         */
    483309        devman_handle_t handle = IPC_GET_ARG2(*icall);
    484 
    485         fibril_mutex_lock(&functions_mutex);
    486         ddf_fun_t *fun = driver_get_function(handle);
    487         fibril_mutex_unlock(&functions_mutex);
    488         /* XXX Need a lock on fun */
     310        ddf_fun_t *fun = driver_get_function(&functions, handle);
    489311       
    490312        if (fun == NULL) {
     
    492314                    " %" PRIun " was found.\n", driver->name, handle);
    493315                async_answer_0(iid, ENOENT);
    494                 return;
    495         }
    496        
    497         if (fun->conn_handler != NULL) {
    498                 /* Driver has a custom connection handler. */
    499                 (*fun->conn_handler)(iid, icall, (void *)fun);
    500316                return;
    501317        }
     
    606422static void driver_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    607423{
    608         sysarg_t conn_type;
    609 
    610         if (iid == 0) {
    611                 /* Callback connection from devman */
    612                 /* XXX Use separate handler for this type of connection */
    613                 conn_type = DRIVER_DEVMAN;
    614         } else {
    615                 conn_type = IPC_GET_ARG1(*icall);
    616         }
    617 
    618424        /* Select interface */
    619         switch (conn_type) {
     425        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    620426        case DRIVER_DEVMAN:
    621427                /* Handle request from device manager */
     
    644450        ddf_dev_t *dev;
    645451
    646         dev = calloc(1, sizeof(ddf_dev_t));
     452        dev = malloc(sizeof(ddf_dev_t));
    647453        if (dev == NULL)
    648454                return NULL;
    649455
     456        memset(dev, 0, sizeof(ddf_dev_t));
    650457        return dev;
    651458}
     
    675482static void delete_device(ddf_dev_t *dev)
    676483{
    677         if (dev->driver_data != NULL)
    678                 free(dev->driver_data);
    679484        free(dev);
    680485}
    681486
    682 /** Delete function structure.
     487/** Delete device structure.
    683488 *
    684489 * @param dev           The device structure.
     
    687492{
    688493        clean_match_ids(&fun->match_ids);
    689         if (fun->driver_data != NULL)
    690                 free(fun->driver_data);
    691494        if (fun->name != NULL)
    692495                free(fun->name);
     
    694497}
    695498
    696 /** Increase device reference count. */
    697 static void dev_add_ref(ddf_dev_t *dev)
    698 {
    699         atomic_inc(&dev->refcnt);
    700 }
    701 
    702 /** Decrease device reference count.
    703  *
    704  * Free the device structure if the reference count drops to zero.
    705  */
    706 static void dev_del_ref(ddf_dev_t *dev)
    707 {
    708         if (atomic_predec(&dev->refcnt) == 0)
    709                 delete_device(dev);
    710 }
    711 
    712 /** Increase function reference count.
    713  *
    714  * This also increases reference count on the device. The device structure
    715  * will thus not be deallocated while there are some associated function
    716  * structures.
    717  */
    718 static void fun_add_ref(ddf_fun_t *fun)
    719 {
    720         dev_add_ref(fun->dev);
    721         atomic_inc(&fun->refcnt);
    722 }
    723 
    724 /** Decrease function reference count.
    725  *
    726  * Free the function structure if the reference count drops to zero.
    727  */
    728 static void fun_del_ref(ddf_fun_t *fun)
    729 {
    730         ddf_dev_t *dev = fun->dev;
    731 
    732         if (atomic_predec(&fun->refcnt) == 0)
    733                 delete_function(fun);
    734 
    735         dev_del_ref(dev);
    736 }
    737 
    738 /** Allocate driver-specific device data. */
    739 extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
    740 {
    741         void *data;
    742 
    743         assert(dev->driver_data == NULL);
    744 
    745         data = calloc(1, size);
    746         if (data == NULL)
    747                 return NULL;
    748 
    749         dev->driver_data = data;
    750         return data;
    751 }
    752 
    753499/** Create a DDF function node.
    754500 *
     
    782528                return NULL;
    783529
    784         /* Add one reference that will be dropped by ddf_fun_destroy() */
     530        fun->bound = false;
    785531        fun->dev = dev;
    786         fun_add_ref(fun);
    787 
    788         fun->bound = false;
    789532        fun->ftype = ftype;
    790533
     
    798541}
    799542
    800 /** Allocate driver-specific function data. */
    801 extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
    802 {
    803         void *data;
    804 
    805         assert(fun->bound == false);
    806         assert(fun->driver_data == NULL);
    807 
    808         data = calloc(1, size);
    809         if (data == NULL)
    810                 return NULL;
    811 
    812         fun->driver_data = data;
    813         return data;
    814 }
    815 
    816543/** Destroy DDF function node.
    817544 *
     
    824551{
    825552        assert(fun->bound == false);
    826 
    827         /*
    828          * Drop the reference added by ddf_fun_create(). This will deallocate
    829          * the function as soon as all other references are dropped (i.e.
    830          * as soon control leaves all driver entry points called in context
    831          * of this function.
    832          */
    833         fun_del_ref(fun);
     553        delete_function(fun);
    834554}
    835555
     
    856576int ddf_fun_bind(ddf_fun_t *fun)
    857577{
    858         assert(fun->bound == false);
    859578        assert(fun->name != NULL);
    860579       
     
    873592}
    874593
    875 /** Unbind a function node.
    876  *
    877  * Unbind the specified function from the system. This effectively makes
    878  * the function invisible to the system.
    879  *
    880  * @param fun           Function to unbind
    881  * @return              EOK on success or negative error code
    882  */
    883 int ddf_fun_unbind(ddf_fun_t *fun)
    884 {
    885         int res;
    886        
    887         assert(fun->bound == true);
    888        
    889         res = devman_remove_function(fun->handle);
    890         if (res != EOK)
    891                 return res;
    892 
    893         remove_from_functions_list(fun);
    894        
    895         fun->bound = false;
    896         return EOK;
    897 }
    898 
    899 /** Online function.
    900  *
    901  * @param fun           Function to online
    902  * @return              EOK on success or negative error code
    903  */
    904 int ddf_fun_online(ddf_fun_t *fun)
    905 {
    906         int res;
    907        
    908         assert(fun->bound == true);
    909        
    910         res = devman_drv_fun_online(fun->handle);
    911         if (res != EOK)
    912                 return res;
    913        
    914         return EOK;
    915 }
    916 
    917 /** Offline function.
    918  *
    919  * @param fun           Function to offline
    920  * @return              EOK on success or negative error code
    921  */
    922 int ddf_fun_offline(ddf_fun_t *fun)
    923 {
    924         int res;
    925        
    926         assert(fun->bound == true);
    927        
    928         res = devman_drv_fun_offline(fun->handle);
    929         if (res != EOK)
    930                 return res;
    931        
    932         return EOK;
    933 }
    934 
    935594/** Add single match ID to inner function.
    936595 *
     
    955614                return ENOMEM;
    956615       
    957         match_id->id = str_dup(match_id_str);
     616        match_id->id = match_id_str;
    958617        match_id->score = 90;
    959618       
     
    970629}
    971630
    972 /** Add exposed function to category.
     631/** Add exposed function to class.
    973632 *
    974633 * Must only be called when the function is bound.
    975634 */
    976 int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
     635int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
    977636{
    978637        assert(fun->bound == true);
    979638        assert(fun->ftype == fun_exposed);
    980639       
    981         return devman_add_device_to_category(fun->handle, cat_name);
     640        return devman_add_device_to_class(fun->handle, class_name);
    982641}
    983642
Note: See TracChangeset for help on using the changeset viewer.