Ignore:
File:
1 edited

Legend:

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

    r45059d6b ra996ae31  
    6363
    6464/** Devices */
     65LIST_INITIALIZE(devices);
     66FIBRIL_MUTEX_INITIALIZE(devices_mutex);
     67
     68/** Functions */
    6569LIST_INITIALIZE(functions);
    6670FIBRIL_MUTEX_INITIALIZE(functions_mutex);
     
    7680
    7781static irq_code_t default_pseudocode = {
     82        0,
     83        NULL,
    7884        sizeof(default_cmds) / sizeof(irq_cmd_t),
    7985        default_cmds
     
    8288static ddf_dev_t *create_device(void);
    8389static void delete_device(ddf_dev_t *);
     90static void dev_add_ref(ddf_dev_t *);
     91static void dev_del_ref(ddf_dev_t *);
     92static void fun_add_ref(ddf_fun_t *);
     93static void fun_del_ref(ddf_fun_t *);
    8494static remote_handler_t *function_get_default_handler(ddf_fun_t *);
    8595static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
     
    190200                pseudocode = &default_pseudocode;
    191201       
    192         int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
     202        int res = irq_register(irq, dev->handle, ctx->id, pseudocode);
    193203        if (res != EOK) {
    194204                remove_interrupt_context(&interrupt_contexts, ctx);
     
    203213        interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
    204214            dev, irq);
    205         int res = unregister_irq(irq, dev->handle);
     215        int res = irq_unregister(irq, dev->handle);
    206216       
    207217        if (ctx != NULL) {
     
    227237}
    228238
    229 static ddf_fun_t *driver_get_function(list_t *functions, devman_handle_t handle)
     239static ddf_dev_t *driver_get_device(devman_handle_t handle)
     240{
     241        ddf_dev_t *dev = NULL;
     242       
     243        assert(fibril_mutex_is_locked(&devices_mutex));
     244       
     245        list_foreach(devices, link) {
     246                dev = list_get_instance(link, ddf_dev_t, link);
     247                if (dev->handle == handle)
     248                        return dev;
     249        }
     250       
     251        return NULL;
     252}
     253
     254static ddf_fun_t *driver_get_function(devman_handle_t handle)
    230255{
    231256        ddf_fun_t *fun = NULL;
    232257       
    233         fibril_mutex_lock(&functions_mutex);
    234        
    235         list_foreach(*functions, link) {
     258        assert(fibril_mutex_is_locked(&functions_mutex));
     259       
     260        list_foreach(functions, link) {
    236261                fun = list_get_instance(link, ddf_fun_t, link);
    237                 if (fun->handle == handle) {
    238                         fibril_mutex_unlock(&functions_mutex);
     262                if (fun->handle == handle)
    239263                        return fun;
    240                 }
    241         }
    242        
    243         fibril_mutex_unlock(&functions_mutex);
     264        }
    244265       
    245266        return NULL;
    246267}
    247268
    248 static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
     269static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    249270{
    250271        char *dev_name = NULL;
     
    252273       
    253274        devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
    254         devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
     275        devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
    255276       
    256277        ddf_dev_t *dev = create_device();
     278
     279        /* Add one reference that will be dropped by driver_dev_remove() */
     280        dev_add_ref(dev);
    257281        dev->handle = dev_handle;
    258282
     
    266290        (void) parent_fun_handle;
    267291       
    268         res = driver->driver_ops->add_device(dev);
    269         if (res != EOK)
    270                 delete_device(dev);
     292        res = driver->driver_ops->dev_add(dev);
     293       
     294        if (res != EOK) {
     295                dev_del_ref(dev);
     296                async_answer_0(iid, res);
     297                return;
     298        }
     299       
     300        fibril_mutex_lock(&devices_mutex);
     301        list_append(&dev->link, &devices);
     302        fibril_mutex_unlock(&devices_mutex);
    271303       
    272304        async_answer_0(iid, res);
     305}
     306
     307static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
     308{
     309        fibril_mutex_lock(&devices_mutex);
     310        ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));
     311        fibril_mutex_unlock(&devices_mutex);
     312       
     313        if (dev != NULL && driver->driver_ops->device_added != NULL)
     314                driver->driver_ops->device_added(dev);
     315}
     316
     317static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
     318{
     319        devman_handle_t devh;
     320        ddf_dev_t *dev;
     321        int rc;
     322       
     323        devh = IPC_GET_ARG1(*icall);
     324       
     325        fibril_mutex_lock(&devices_mutex);
     326        dev = driver_get_device(devh);
     327        if (dev != NULL)
     328                dev_add_ref(dev);
     329        fibril_mutex_unlock(&devices_mutex);
     330       
     331        if (dev == NULL) {
     332                async_answer_0(iid, ENOENT);
     333                return;
     334        }
     335       
     336        if (driver->driver_ops->dev_remove != NULL)
     337                rc = driver->driver_ops->dev_remove(dev);
     338        else
     339                rc = ENOTSUP;
     340       
     341        if (rc == EOK)
     342                dev_del_ref(dev);
     343       
     344        async_answer_0(iid, (sysarg_t) rc);
     345}
     346
     347static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
     348{
     349        devman_handle_t devh;
     350        ddf_dev_t *dev;
     351        int rc;
     352       
     353        devh = IPC_GET_ARG1(*icall);
     354       
     355        fibril_mutex_lock(&devices_mutex);
     356        dev = driver_get_device(devh);
     357        if (dev != NULL)
     358                dev_add_ref(dev);
     359        fibril_mutex_unlock(&devices_mutex);
     360       
     361        if (dev == NULL) {
     362                async_answer_0(iid, ENOENT);
     363                return;
     364        }
     365       
     366        if (driver->driver_ops->dev_gone != NULL)
     367                rc = driver->driver_ops->dev_gone(dev);
     368        else
     369                rc = ENOTSUP;
     370       
     371        if (rc == EOK)
     372                dev_del_ref(dev);
     373       
     374        async_answer_0(iid, (sysarg_t) rc);
     375}
     376
     377static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     378{
     379        devman_handle_t funh;
     380        ddf_fun_t *fun;
     381        int rc;
     382       
     383        funh = IPC_GET_ARG1(*icall);
     384       
     385        /*
     386         * Look the function up. Bump reference count so that
     387         * the function continues to exist until we return
     388         * from the driver.
     389         */
     390        fibril_mutex_lock(&functions_mutex);
     391       
     392        fun = driver_get_function(funh);
     393        if (fun != NULL)
     394                fun_add_ref(fun);
     395       
     396        fibril_mutex_unlock(&functions_mutex);
     397       
     398        if (fun == NULL) {
     399                async_answer_0(iid, ENOENT);
     400                return;
     401        }
     402       
     403        /* Call driver entry point */
     404        if (driver->driver_ops->fun_online != NULL)
     405                rc = driver->driver_ops->fun_online(fun);
     406        else
     407                rc = ENOTSUP;
     408       
     409        fun_del_ref(fun);
     410       
     411        async_answer_0(iid, (sysarg_t) rc);
     412}
     413
     414static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     415{
     416        devman_handle_t funh;
     417        ddf_fun_t *fun;
     418        int rc;
     419       
     420        funh = IPC_GET_ARG1(*icall);
     421       
     422        /*
     423         * Look the function up. Bump reference count so that
     424         * the function continues to exist until we return
     425         * from the driver.
     426         */
     427        fibril_mutex_lock(&functions_mutex);
     428       
     429        fun = driver_get_function(funh);
     430        if (fun != NULL)
     431                fun_add_ref(fun);
     432       
     433        fibril_mutex_unlock(&functions_mutex);
     434       
     435        if (fun == NULL) {
     436                async_answer_0(iid, ENOENT);
     437                return;
     438        }
     439       
     440        /* Call driver entry point */
     441        if (driver->driver_ops->fun_offline != NULL)
     442                rc = driver->driver_ops->fun_offline(fun);
     443        else
     444                rc = ENOTSUP;
     445       
     446        async_answer_0(iid, (sysarg_t) rc);
    273447}
    274448
     
    286460               
    287461                switch (IPC_GET_IMETHOD(call)) {
    288                 case DRIVER_ADD_DEVICE:
    289                         driver_add_device(callid, &call);
     462                case DRIVER_DEV_ADD:
     463                        driver_dev_add(callid, &call);
     464                        break;
     465                case DRIVER_DEV_ADDED:
     466                        async_answer_0(callid, EOK);
     467                        driver_dev_added(callid, &call);
     468                        break;
     469                case DRIVER_DEV_REMOVE:
     470                        driver_dev_remove(callid, &call);
     471                        break;
     472                case DRIVER_DEV_GONE:
     473                        driver_dev_gone(callid, &call);
     474                        break;
     475                case DRIVER_FUN_ONLINE:
     476                        driver_fun_online(callid, &call);
     477                        break;
     478                case DRIVER_FUN_OFFLINE:
     479                        driver_fun_offline(callid, &call);
    290480                        break;
    291481                default:
    292                         async_answer_0(callid, ENOENT);
     482                        async_answer_0(callid, ENOTSUP);
    293483                }
    294484        }
     
    308498         */
    309499        devman_handle_t handle = IPC_GET_ARG2(*icall);
    310         ddf_fun_t *fun = driver_get_function(&functions, handle);
     500
     501        fibril_mutex_lock(&functions_mutex);
     502        ddf_fun_t *fun = driver_get_function(handle);
     503        fibril_mutex_unlock(&functions_mutex);
     504        /* XXX Need a lock on fun */
    311505       
    312506        if (fun == NULL) {
     
    466660        ddf_dev_t *dev;
    467661
    468         dev = malloc(sizeof(ddf_dev_t));
     662        dev = calloc(1, sizeof(ddf_dev_t));
    469663        if (dev == NULL)
    470664                return NULL;
    471665
    472         memset(dev, 0, sizeof(ddf_dev_t));
    473666        return dev;
    474667}
     
    498691static void delete_device(ddf_dev_t *dev)
    499692{
     693        if (dev->driver_data != NULL)
     694                free(dev->driver_data);
    500695        free(dev);
    501696}
    502697
    503 /** Delete device structure.
     698/** Delete function structure.
    504699 *
    505700 * @param dev           The device structure.
     
    508703{
    509704        clean_match_ids(&fun->match_ids);
     705        if (fun->driver_data != NULL)
     706                free(fun->driver_data);
    510707        if (fun->name != NULL)
    511708                free(fun->name);
     
    513710}
    514711
     712/** Increase device reference count. */
     713static void dev_add_ref(ddf_dev_t *dev)
     714{
     715        atomic_inc(&dev->refcnt);
     716}
     717
     718/** Decrease device reference count.
     719 *
     720 * Free the device structure if the reference count drops to zero.
     721 */
     722static void dev_del_ref(ddf_dev_t *dev)
     723{
     724        if (atomic_predec(&dev->refcnt) == 0)
     725                delete_device(dev);
     726}
     727
     728/** Increase function reference count.
     729 *
     730 * This also increases reference count on the device. The device structure
     731 * will thus not be deallocated while there are some associated function
     732 * structures.
     733 */
     734static void fun_add_ref(ddf_fun_t *fun)
     735{
     736        dev_add_ref(fun->dev);
     737        atomic_inc(&fun->refcnt);
     738}
     739
     740/** Decrease function reference count.
     741 *
     742 * Free the function structure if the reference count drops to zero.
     743 */
     744static void fun_del_ref(ddf_fun_t *fun)
     745{
     746        ddf_dev_t *dev = fun->dev;
     747
     748        if (atomic_predec(&fun->refcnt) == 0)
     749                delete_function(fun);
     750
     751        dev_del_ref(dev);
     752}
     753
     754/** Allocate driver-specific device data. */
     755extern void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     756{
     757        void *data;
     758
     759        assert(dev->driver_data == NULL);
     760
     761        data = calloc(1, size);
     762        if (data == NULL)
     763                return NULL;
     764
     765        dev->driver_data = data;
     766        return data;
     767}
     768
    515769/** Create a DDF function node.
    516770 *
     
    544798                return NULL;
    545799
     800        /* Add one reference that will be dropped by ddf_fun_destroy() */
     801        fun->dev = dev;
     802        fun_add_ref(fun);
     803
    546804        fun->bound = false;
    547         fun->dev = dev;
    548805        fun->ftype = ftype;
    549806
     
    557814}
    558815
     816/** Allocate driver-specific function data. */
     817extern void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     818{
     819        void *data;
     820
     821        assert(fun->bound == false);
     822        assert(fun->driver_data == NULL);
     823
     824        data = calloc(1, size);
     825        if (data == NULL)
     826                return NULL;
     827
     828        fun->driver_data = data;
     829        return data;
     830}
     831
    559832/** Destroy DDF function node.
    560833 *
     
    567840{
    568841        assert(fun->bound == false);
    569         delete_function(fun);
     842
     843        /*
     844         * Drop the reference added by ddf_fun_create(). This will deallocate
     845         * the function as soon as all other references are dropped (i.e.
     846         * as soon control leaves all driver entry points called in context
     847         * of this function.
     848         */
     849        fun_del_ref(fun);
    570850}
    571851
     
    614894 * the function invisible to the system.
    615895 *
    616  * @param fun           Function to bind
     896 * @param fun           Function to unbind
    617897 * @return              EOK on success or negative error code
    618898 */
     
    623903        assert(fun->bound == true);
    624904       
    625         add_to_functions_list(fun);
    626905        res = devman_remove_function(fun->handle);
    627906        if (res != EOK)
     
    631910       
    632911        fun->bound = false;
     912        return EOK;
     913}
     914
     915/** Online function.
     916 *
     917 * @param fun           Function to online
     918 * @return              EOK on success or negative error code
     919 */
     920int ddf_fun_online(ddf_fun_t *fun)
     921{
     922        int res;
     923       
     924        assert(fun->bound == true);
     925       
     926        res = devman_drv_fun_online(fun->handle);
     927        if (res != EOK)
     928                return res;
     929       
     930        return EOK;
     931}
     932
     933/** Offline function.
     934 *
     935 * @param fun           Function to offline
     936 * @return              EOK on success or negative error code
     937 */
     938int ddf_fun_offline(ddf_fun_t *fun)
     939{
     940        int res;
     941       
     942        assert(fun->bound == true);
     943       
     944        res = devman_drv_fun_offline(fun->handle);
     945        if (res != EOK)
     946                return res;
     947       
    633948        return EOK;
    634949}
     
    657972       
    658973        match_id->id = str_dup(match_id_str);
    659         match_id->score = 90;
     974        match_id->score = match_score;
    660975       
    661976        add_match_id(&fun->match_ids, match_id);
     
    7031018         * incoming connections.
    7041019         */
    705         rc = devman_driver_register(driver->name, driver_connection);
     1020        async_set_client_connection(driver_connection);
     1021        rc = devman_driver_register(driver->name);
    7061022        if (rc != EOK) {
    7071023                printf("Error: Failed to register driver with device manager "
Note: See TracChangeset for help on using the changeset viewer.