Changeset a1b7e80 in mainline


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

Location:
uspace
Files:
24 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/devctl/devctl.c

    r7a72ce1a ra1b7e80  
    3737#include <stdio.h>
    3838#include <stdlib.h>
     39#include <str_error.h>
    3940#include <sys/typefmt.h>
    4041
     
    4344#define MAX_NAME_LENGTH 1024
    4445
    45 static int fun_tree_print(devman_handle_t funh, int lvl)
     46static int fun_subtree_print(devman_handle_t funh, int lvl)
    4647{
    4748        char name[MAX_NAME_LENGTH];
     
    8485
    8586        for (i = 0; i < count; i++)
    86                 fun_tree_print(cfuns[i], lvl + 1);
     87                fun_subtree_print(cfuns[i], lvl + 1);
    8788
    8889        free(cfuns);
     
    9091}
    9192
    92 int main(int argc, char *argv[])
     93static int fun_tree_print(void)
    9394{
    9495        devman_handle_t root_fun;
     
    9899        if (rc != EOK) {
    99100                printf(NAME ": Error resolving root function.\n");
     101                return EIO;
     102        }
     103
     104        rc = fun_subtree_print(root_fun, 0);
     105        if (rc != EOK)
     106                return EIO;
     107
     108        return EOK;
     109}
     110
     111static int fun_online(const char *path)
     112{
     113        devman_handle_t funh;
     114        int rc;
     115
     116        rc = devman_fun_get_handle(path, &funh, 0);
     117        if (rc != EOK) {
     118                printf(NAME ": Error resolving device function '%s' (%s)\n",
     119                    path, str_error(rc));
     120                return rc;
     121        }
     122
     123        rc = devman_fun_online(funh);
     124        if (rc != EOK) {
     125                printf(NAME ": Failed to online function '%s'.\n", path);
     126                return rc;
     127        }
     128
     129        return EOK;
     130}
     131
     132static int fun_offline(const char *path)
     133{
     134        devman_handle_t funh;
     135        int rc;
     136
     137        rc = devman_fun_get_handle(path, &funh, 0);
     138        if (rc != EOK) {
     139                printf(NAME ": Error resolving device function '%s' (%s)\n",
     140                    path, str_error(rc));
     141                return rc;
     142        }
     143
     144        rc = devman_fun_offline(funh);
     145        if (rc != EOK) {
     146                printf(NAME ": Failed to offline function '%s'.\n", path);
     147                return rc;
     148        }
     149
     150        return EOK;
     151}
     152
     153static void print_syntax(void)
     154{
     155        printf("syntax: devctl [(online|offline) <function>]\n");
     156}
     157
     158int main(int argc, char *argv[])
     159{
     160        int rc;
     161
     162        if (argc == 1) {
     163                rc = fun_tree_print();
     164                if (rc != EOK)
     165                        return 2;
     166        } else if (str_cmp(argv[1], "online") == 0) {
     167                if (argc < 3) {
     168                        printf(NAME ": Argument missing.\n");
     169                        print_syntax();
     170                        return 1;
     171                }
     172
     173                rc = fun_online(argv[2]);
     174                if (rc != EOK) {
     175                        return 2;
     176                }
     177        } else if (str_cmp(argv[1], "offline") == 0) {
     178                if (argc < 3) {
     179                        printf(NAME ": Argument missing.\n");
     180                        print_syntax();
     181                        return 1;
     182                }
     183
     184                rc = fun_offline(argv[2]);
     185                if (rc != EOK) {
     186                        return 2;
     187                }
     188        } else {
     189                printf(NAME ": Invalid argument '%s'.\n", argv[1]);
     190                print_syntax();
    100191                return 1;
    101192        }
    102 
    103         rc = fun_tree_print(root_fun, 0);
    104         if (rc != EOK)
    105                 return 1;
    106193
    107194        return 0;
  • uspace/drv/bus/pci/pciintel/pci.c

    r7a72ce1a ra1b7e80  
    215215};
    216216
    217 static pci_bus_t *pci_bus_new(void)
    218 {
    219         pci_bus_t *bus;
    220        
    221         bus = (pci_bus_t *) calloc(1, sizeof(pci_bus_t));
    222         if (bus == NULL)
    223                 return NULL;
    224        
    225         fibril_mutex_initialize(&bus->conf_mutex);
    226         return bus;
    227 }
    228 
    229 static void pci_bus_delete(pci_bus_t *bus)
    230 {
    231         assert(bus != NULL);
    232         free(bus);
    233 }
    234 
    235217static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
    236218{
     
    584566        dnode->parent_sess = NULL;
    585567       
    586         bus = pci_bus_new();
     568        bus = ddf_dev_data_alloc(dnode, sizeof(pci_bus_t));
    587569        if (bus == NULL) {
    588570                ddf_msg(LVL_ERROR, "pci_add_device allocation failed.");
     
    590572                goto fail;
    591573        }
     574        fibril_mutex_initialize(&bus->conf_mutex);
     575
    592576        bus->dnode = dnode;
    593577        dnode->driver_data = bus;
     
    655639       
    656640fail:
    657         if (bus != NULL)
    658                 pci_bus_delete(bus);
    659        
    660641        if (dnode->parent_sess)
    661642                async_hangup(dnode->parent_sess);
  • uspace/drv/bus/usb/uhci/uhci.c

    r7a72ce1a ra1b7e80  
    192192                ddf_fun_destroy(instance->rh_fun); \
    193193        } \
    194         free(instance); \
    195194        device->driver_data = NULL; \
    196195        usb_log_error(message); \
  • uspace/drv/bus/usb/usbhid/kbd/kbddev.c

    r7a72ce1a ra1b7e80  
    734734        int rc = usb_kbd_create_function(hid_dev, kbd_dev);
    735735        if (rc != EOK) {
    736                 usb_kbd_free(&kbd_dev);
     736                usb_kbd_destroy(kbd_dev);
    737737                return rc;
    738738        }
     
    779779 * @param kbd_dev Pointer to the structure to be destroyed.
    780780 */
    781 void usb_kbd_free(usb_kbd_t **kbd_dev)
    782 {
    783         if (kbd_dev == NULL || *kbd_dev == NULL) {
     781void usb_kbd_destroy(usb_kbd_t *kbd_dev)
     782{
     783        if (kbd_dev == NULL) {
    784784                return;
    785785        }
    786786       
    787787        // hangup phone to the console
    788         async_obsolete_hangup((*kbd_dev)->console_phone);
    789        
    790         if ((*kbd_dev)->repeat_mtx != NULL) {
     788        async_obsolete_hangup(kbd_dev->console_phone);
     789       
     790        if (kbd_dev->repeat_mtx != NULL) {
    791791                //assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
    792792                // FIXME - the fibril_mutex_is_locked may not cause
    793793                // fibril scheduling
    794                 while (fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)) {}
    795                 free((*kbd_dev)->repeat_mtx);
     794                while (fibril_mutex_is_locked(kbd_dev->repeat_mtx)) {}
     795                free(kbd_dev->repeat_mtx);
    796796        }
    797797       
    798798        // free all buffers
    799         if ((*kbd_dev)->keys != NULL) {
    800                 free((*kbd_dev)->keys);
    801         }
    802         if ((*kbd_dev)->keys_old != NULL) {
    803                 free((*kbd_dev)->keys_old);
    804         }
    805         if ((*kbd_dev)->led_data != NULL) {
    806                 free((*kbd_dev)->led_data);
    807         }
    808         if ((*kbd_dev)->led_path != NULL) {
    809                 usb_hid_report_path_free((*kbd_dev)->led_path);
    810         }
    811         if ((*kbd_dev)->output_buffer != NULL) {
    812                 usb_hid_report_output_free((*kbd_dev)->output_buffer);
    813         }
    814 
    815         free(*kbd_dev);
    816         *kbd_dev = NULL;
     799        if (kbd_dev->keys != NULL) {
     800                free(kbd_dev->keys);
     801        }
     802        if (kbd_dev->keys_old != NULL) {
     803                free(kbd_dev->keys_old);
     804        }
     805        if (kbd_dev->led_data != NULL) {
     806                free(kbd_dev->led_data);
     807        }
     808        if (kbd_dev->led_path != NULL) {
     809                usb_hid_report_path_free(kbd_dev->led_path);
     810        }
     811        if (kbd_dev->output_buffer != NULL) {
     812                usb_hid_report_output_free(kbd_dev->output_buffer);
     813        }
    817814}
    818815
     
    830827                        usb_kbd_mark_unusable(kbd_dev);
    831828                } else {
    832                         usb_kbd_free(&kbd_dev);
     829                        usb_kbd_destroy(kbd_dev);
    833830                }
    834831        }
  • uspace/drv/bus/usb/usbhid/kbd/kbddev.h

    r7a72ce1a ra1b7e80  
    131131int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev);
    132132
    133 void usb_kbd_free(usb_kbd_t **kbd_dev);
     133void usb_kbd_destroy(usb_kbd_t *kbd_dev);
    134134
    135135void usb_kbd_push_ev(struct usb_hid_dev *hid_dev, usb_kbd_t *kbd_dev,
  • uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c

    r7a72ce1a ra1b7e80  
    8080                if (!usb_kbd_is_initialized(kbd)) {
    8181                        if (usb_kbd_is_ready_to_destroy(kbd)) {
    82                                 usb_kbd_free(&kbd);
    83                                 assert(kbd == NULL);
     82                                usb_kbd_destroy(kbd);
    8483                        }
    8584                        return;
  • uspace/drv/bus/usb/usbhid/main.c

    r7a72ce1a ra1b7e80  
    9393        if (rc != EOK) {
    9494                usb_log_error("Failed to initialize USB/HID device.\n");
    95                 usb_hid_free(&hid_dev);
     95                usb_hid_destroy(hid_dev);
    9696                return rc;
    9797        }       
  • uspace/drv/bus/usb/usbhid/mouse/mousedev.c

    r7a72ce1a ra1b7e80  
    183183/*----------------------------------------------------------------------------*/
    184184
    185 static void usb_mouse_free(usb_mouse_t **mouse_dev)
    186 {
    187         assert(mouse_dev != NULL && *mouse_dev != NULL);
     185static void usb_mouse_destroy(usb_mouse_t *mouse_dev)
     186{
     187        assert(mouse_dev != NULL);
    188188       
    189189        // hangup phone to the console
    190         if ((*mouse_dev)->mouse_phone >= 0) {
    191                 async_obsolete_hangup((*mouse_dev)->mouse_phone);
    192         }
    193        
    194         if ((*mouse_dev)->wheel_phone >= 0) {
    195                 async_obsolete_hangup((*mouse_dev)->wheel_phone);
    196         }
    197        
    198         free(*mouse_dev);
    199         *mouse_dev = NULL;
     190        if (mouse_dev->mouse_phone >= 0) {
     191                async_obsolete_hangup(mouse_dev->mouse_phone);
     192        }
     193       
     194        if (mouse_dev->wheel_phone >= 0) {
     195                async_obsolete_hangup(mouse_dev->wheel_phone);
     196        }
    200197}
    201198
     
    437434        int rc = usb_mouse_create_function(hid_dev, mouse_dev);
    438435        if (rc != EOK) {
    439                 usb_mouse_free(&mouse_dev);
     436                usb_mouse_destroy(mouse_dev);
    440437                return rc;
    441438        }
     
    464461{
    465462        if (data != NULL) {
    466                 usb_mouse_free((usb_mouse_t **)&data);
     463                usb_mouse_destroy((usb_mouse_t *)data);
    467464        }
    468465}
  • uspace/drv/bus/usb/usbhid/multimedia/multimedia.c

    r7a72ce1a ra1b7e80  
    167167/*----------------------------------------------------------------------------*/
    168168
    169 static void usb_multimedia_free(usb_multimedia_t **multim_dev)
    170 {
    171         if (multim_dev == NULL || *multim_dev == NULL) {
    172                 return;
    173         }
    174        
    175         // hangup phone to the console
    176         async_obsolete_hangup((*multim_dev)->console_phone);
    177 
    178         free(*multim_dev);
    179         *multim_dev = NULL;
    180 }
    181 
    182 /*----------------------------------------------------------------------------*/
    183 
    184169static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev,
    185170    usb_multimedia_t *multim_dev)
     
    247232       
    248233        int rc = usb_multimedia_create_function(hid_dev, multim_dev);
    249         if (rc != EOK) {
    250                 usb_multimedia_free(&multim_dev);
     234        if (rc != EOK)
    251235                return rc;
    252         }
    253236       
    254237        usb_log_debug(NAME " HID/multimedia structure initialized.\n");
     
    267250        if (data != NULL) {
    268251                usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
    269                 usb_multimedia_free(&multim_dev);
     252                // hangup phone to the console
     253                async_obsolete_hangup(multim_dev->console_phone);
    270254        }
    271255}
  • uspace/drv/bus/usb/usbhid/usbhid.c

    r7a72ce1a ra1b7e80  
    627627        }
    628628       
    629         usb_hid_free(&hid_dev);
     629        usb_hid_destroy(hid_dev);
    630630}
    631631
     
    646646/*----------------------------------------------------------------------------*/
    647647
    648 void usb_hid_free(usb_hid_dev_t **hid_dev)
     648void usb_hid_destroy(usb_hid_dev_t *hid_dev)
    649649{
    650650        int i;
    651651       
    652         if (hid_dev == NULL || *hid_dev == NULL) {
     652        if (hid_dev == NULL) {
    653653                return;
    654654        }
    655655       
    656656        usb_log_debug("Subdrivers: %p, subdriver count: %d\n",
    657             (*hid_dev)->subdrivers, (*hid_dev)->subdriver_count);
    658        
    659         assert((*hid_dev)->subdrivers != NULL
    660             || (*hid_dev)->subdriver_count == 0);
    661        
    662         for (i = 0; i < (*hid_dev)->subdriver_count; ++i) {
    663                 if ((*hid_dev)->subdrivers[i].deinit != NULL) {
    664                         (*hid_dev)->subdrivers[i].deinit(*hid_dev,
    665                             (*hid_dev)->subdrivers[i].data);
     657            hid_dev->subdrivers, hid_dev->subdriver_count);
     658       
     659        assert(hid_dev->subdrivers != NULL
     660            || hid_dev->subdriver_count == 0);
     661       
     662        for (i = 0; i < hid_dev->subdriver_count; ++i) {
     663                if (hid_dev->subdrivers[i].deinit != NULL) {
     664                        hid_dev->subdrivers[i].deinit(hid_dev,
     665                            hid_dev->subdrivers[i].data);
    666666                }
    667667        }
    668668       
    669669        // free the subdrivers info
    670         if ((*hid_dev)->subdrivers != NULL) {
    671                 free((*hid_dev)->subdrivers);
     670        if (hid_dev->subdrivers != NULL) {
     671                free(hid_dev->subdrivers);
    672672        }
    673673
    674674        // destroy the parser
    675         if ((*hid_dev)->report != NULL) {
    676                 usb_hid_free_report((*hid_dev)->report);
    677         }
    678 
    679         if ((*hid_dev)->report_desc != NULL) {
    680                 free((*hid_dev)->report_desc);
    681         }
    682 
    683         free(*hid_dev);
    684         *hid_dev = NULL;
     675        if (hid_dev->report != NULL) {
     676                usb_hid_free_report(hid_dev->report);
     677        }
     678
     679        if (hid_dev->report_desc != NULL) {
     680                free(hid_dev->report_desc);
     681        }
    685682}
    686683
  • uspace/drv/bus/usb/usbhid/usbhid.h

    r7a72ce1a ra1b7e80  
    158158int usb_hid_report_number(usb_hid_dev_t *hid_dev);
    159159
    160 void usb_hid_free(usb_hid_dev_t **hid_dev);
     160void usb_hid_destroy(usb_hid_dev_t *hid_dev);
    161161
    162162#endif /* USB_HID_USBHID_H_ */
  • uspace/drv/bus/usb/usbmast/main.c

    r7a72ce1a ra1b7e80  
    145145        usbmast_fun_t *mfun = NULL;
    146146
    147         /* Allocate softstate */
    148         mfun = calloc(1, sizeof(usbmast_fun_t));
    149         if (mfun == NULL) {
    150                 usb_log_error("Failed allocating softstate.\n");
    151                 rc = ENOMEM;
    152                 goto error;
    153         }
    154 
    155         mfun->mdev = mdev;
    156         mfun->lun = lun;
    157 
    158147        if (asprintf(&fun_name, "l%u", lun) < 0) {
    159148                usb_log_error("Out of memory.\n");
     
    170159
    171160        free(fun_name);
     161
     162        /* Allocate soft state */
     163        mfun = ddf_dev_data_alloc(mdev->ddf_dev, sizeof(usbmast_fun_t));
     164        if (mfun == NULL) {
     165                usb_log_error("Failed allocating softstate.\n");
     166                rc = ENOMEM;
     167                goto error;
     168        }
     169
     170        mfun->mdev = mdev;
     171        mfun->lun = lun;
     172
    172173        fun_name = NULL;
    173174
     
    227228        if (fun_name != NULL)
    228229                free(fun_name);
    229         if (mfun != NULL)
    230                 free(mfun);
    231230        return rc;
    232231}
  • uspace/drv/char/ns8250/ns8250.c

    r7a72ce1a ra1b7e80  
    112112        fibril_mutex_t mutex;
    113113} ns8250_t;
    114 
    115 /** Create per-device soft-state structure.
    116  *
    117  * @return      Pointer to soft-state structure.
    118  */
    119 static ns8250_t *ns8250_new(void)
    120 {
    121         ns8250_t *ns;
    122        
    123         ns = (ns8250_t *) calloc(1, sizeof(ns8250_t));
    124         if (ns == NULL)
    125                 return NULL;
    126        
    127         fibril_mutex_initialize(&ns->mutex);
    128         return ns;
    129 }
    130 
    131 /** Delete soft-state structure.
    132  *
    133  * @param ns    The driver data structure.
    134  */
    135 static void ns8250_delete(ns8250_t *ns)
    136 {
    137         assert(ns != NULL);
    138         free(ns);
    139 }
    140114
    141115/** Find out if there is some incomming data available on the serial port.
     
    721695       
    722696        /* Allocate soft-state for the device */
    723         ns = ns8250_new();
     697        ns = ddf_dev_data_alloc(dev, sizeof(ns8250_t));
    724698        if (ns == NULL) {
    725699                rc = ENOMEM;
     
    727701        }
    728702       
     703        fibril_mutex_initialize(&ns->mutex);
    729704        ns->dev = dev;
    730         dev->driver_data = ns;
    731705       
    732706        rc = ns8250_dev_initialize(ns);
     
    792766        if (need_cleanup)
    793767                ns8250_dev_cleanup(ns);
    794         if (ns != NULL)
    795                 ns8250_delete(ns);
    796768        return rc;
    797769}
  • uspace/drv/infrastructure/rootvirt/rootvirt.c

    r7a72ce1a ra1b7e80  
    6363
    6464static int rootvirt_add_device(ddf_dev_t *dev);
     65static int rootvirt_fun_online(ddf_fun_t *fun);
     66static int rootvirt_fun_offline(ddf_fun_t *fun);
    6567
    6668static driver_ops_t rootvirt_ops = {
    67         .add_device = &rootvirt_add_device
     69        .add_device = &rootvirt_add_device,
     70        .fun_online = &rootvirt_fun_online,
     71        .fun_offline = &rootvirt_fun_offline
    6872};
    6973
     
    140144}
    141145
     146static int rootvirt_fun_online(ddf_fun_t *fun)
     147{
     148        ddf_msg(LVL_DEBUG, "rootvirt_fun_online()");
     149        return ddf_fun_online(fun);
     150}
     151
     152static int rootvirt_fun_offline(ddf_fun_t *fun)
     153{
     154        ddf_msg(LVL_DEBUG, "rootvirt_fun_offline()");
     155        return ddf_fun_offline(fun);
     156}
     157
    142158int main(int argc, char *argv[])
    143159{
  • uspace/drv/test/test1/test1.c

    r7a72ce1a ra1b7e80  
    11/*
    22 * Copyright (c) 2010 Vojtech Horky
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    4041
    4142static int test1_add_device(ddf_dev_t *dev);
     43static int test1_dev_remove(ddf_dev_t *dev);
     44static int test1_fun_online(ddf_fun_t *fun);
     45static int test1_fun_offline(ddf_fun_t *fun);
    4246
    4347static driver_ops_t driver_ops = {
    44         .add_device = &test1_add_device
     48        .add_device = &test1_add_device,
     49        .dev_remove = &test1_dev_remove,
     50        .fun_online = &test1_fun_online,
     51        .fun_offline = &test1_fun_offline
    4552};
    4653
     
    4956        .driver_ops = &driver_ops
    5057};
     58
     59typedef struct {
     60        ddf_fun_t *fun_a;
     61        ddf_fun_t *clone;
     62        ddf_fun_t *child;
     63} test1_t;
    5164
    5265/** Register child and inform user about it.
     
    6073static int register_fun_verbose(ddf_dev_t *parent, const char *message,
    6174    const char *name, const char *match_id, int match_score,
    62     int expected_rc)
     75    int expected_rc, ddf_fun_t **pfun)
    6376{
    6477        ddf_fun_t *fun = NULL;
     
    103116        }
    104117
     118        if (pfun != NULL)
     119                *pfun = fun;
     120
    105121        return rc;
    106122}
     
    126142{
    127143        ddf_fun_t *fun_a;
     144        test1_t *test1;
    128145        int rc;
    129146
    130147        ddf_msg(LVL_DEBUG, "add_device(name=\"%s\", handle=%d)",
    131148            dev->name, (int) dev->handle);
     149
     150        test1 = ddf_dev_data_alloc(dev, sizeof(test1_t));
     151        if (test1 == NULL) {
     152                ddf_msg(LVL_ERROR, "Failed allocating soft state.\n");
     153                return ENOMEM;
     154        }
    132155
    133156        fun_a = ddf_fun_create(dev, fun_exposed, "a");
     
    137160        }
    138161
     162        test1->fun_a = fun_a;
     163
    139164        rc = ddf_fun_bind(fun_a);
    140165        if (rc != EOK) {
    141166                ddf_msg(LVL_ERROR, "Failed binding function 'a'.");
     167                ddf_fun_destroy(fun_a);
    142168                return rc;
    143169        }
     
    151177                (void) register_fun_verbose(dev,
    152178                    "cloning myself ;-)", "clone",
    153                     "virtual&test1", 10, EOK);
     179                    "virtual&test1", 10, EOK, &test1->clone);
    154180                (void) register_fun_verbose(dev,
    155181                    "cloning myself twice ;-)", "clone",
    156                     "virtual&test1", 10, EEXISTS);
     182                    "virtual&test1", 10, EEXISTS, NULL);
    157183        } else if (str_cmp(dev->name, "clone") == 0) {
    158184                (void) register_fun_verbose(dev,
    159185                    "run by the same task", "child",
    160                     "virtual&test1&child", 10, EOK);
     186                    "virtual&test1&child", 10, EOK, &test1->child);
    161187        }
    162188
     
    164190
    165191        return EOK;
     192}
     193
     194static int fun_remove(ddf_fun_t *fun, const char *name)
     195{
     196        int rc;
     197
     198        ddf_msg(LVL_DEBUG, "fun_remove(%p, '%s')\n", fun, name);
     199        rc = ddf_fun_offline(fun);
     200        if (rc != EOK) {
     201                ddf_msg(LVL_ERROR, "Error offlining function '%s'.", name);
     202                return rc;
     203        }
     204
     205        rc = ddf_fun_unbind(fun);
     206        if (rc != EOK) {
     207                ddf_msg(LVL_ERROR, "Failed offlining function '%s'.", name);
     208                return rc;
     209        }
     210
     211        ddf_fun_destroy(fun);
     212        return EOK;
     213}
     214
     215static int test1_dev_remove(ddf_dev_t *dev)
     216{
     217        test1_t *test1 = (test1_t *)dev->driver_data;
     218        int rc;
     219
     220        ddf_msg(LVL_DEBUG, "test1_dev_remove(%p)", dev);
     221
     222        if (test1->fun_a != NULL) {
     223                rc = fun_remove(test1->fun_a, "a");
     224                if (rc != EOK)
     225                        return rc;
     226        }
     227
     228        if (test1->clone != NULL) {
     229                rc = fun_remove(test1->clone, "clone");
     230                if (rc != EOK)
     231                        return rc;
     232        }
     233
     234        if (test1->child != NULL) {
     235                rc = fun_remove(test1->child, "child");
     236                if (rc != EOK)
     237                        return rc;
     238        }
     239
     240        return EOK;
     241}
     242
     243static int test1_fun_online(ddf_fun_t *fun)
     244{
     245        ddf_msg(LVL_DEBUG, "test1_fun_online()");
     246        return ddf_fun_online(fun);
     247}
     248
     249static int test1_fun_offline(ddf_fun_t *fun)
     250{
     251        ddf_msg(LVL_DEBUG, "test1_fun_offline()");
     252        return ddf_fun_offline(fun);
    166253}
    167254
  • uspace/lib/c/generic/devman.c

    r7a72ce1a ra1b7e80  
    327327}
    328328
     329int devman_drv_fun_online(devman_handle_t funh)
     330{
     331        async_exch_t *exch = devman_exchange_begin(DEVMAN_DRIVER);
     332        if (exch == NULL)
     333                return ENOMEM;
     334       
     335        sysarg_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_ONLINE, funh);
     336       
     337        devman_exchange_end(exch);
     338        return (int) retval;
     339}
     340
     341int devman_drv_fun_offline(devman_handle_t funh)
     342{
     343        async_exch_t *exch = devman_exchange_begin(DEVMAN_DRIVER);
     344        if (exch == NULL)
     345                return ENOMEM;
     346       
     347        sysarg_t retval = async_req_1_0(exch, DEVMAN_DRV_FUN_OFFLINE, funh);
     348       
     349        devman_exchange_end(exch);
     350        return (int) retval;
     351}
     352
    329353async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
    330354    devman_handle_t handle, unsigned int flags)
     
    430454}
    431455
     456int devman_fun_online(devman_handle_t funh)
     457{
     458        async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
     459        if (exch == NULL)
     460                return ENOMEM;
     461       
     462        sysarg_t retval = async_req_1_0(exch, DEVMAN_FUN_ONLINE, funh);
     463       
     464        devman_exchange_end(exch);
     465        return (int) retval;
     466}
     467
     468int devman_fun_offline(devman_handle_t funh)
     469{
     470        async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
     471        if (exch == NULL)
     472                return ENOMEM;
     473       
     474        sysarg_t retval = async_req_1_0(exch, DEVMAN_FUN_OFFLINE, funh);
     475       
     476        devman_exchange_end(exch);
     477        return (int) retval;
     478}
     479
    432480static int devman_get_handles_once(sysarg_t method, sysarg_t arg1,
    433481    devman_handle_t *handle_buf, size_t buf_size, size_t *act_size)
  • uspace/lib/c/include/devman.h

    r7a72ce1a ra1b7e80  
    5050    devman_handle_t, devman_handle_t *);
    5151extern int devman_remove_function(devman_handle_t);
     52extern int devman_drv_fun_online(devman_handle_t);
     53extern int devman_drv_fun_offline(devman_handle_t);
    5254
    5355extern async_sess_t *devman_device_connect(exch_mgmt_t, devman_handle_t,
     
    6365extern int devman_fun_get_name(devman_handle_t, char *, size_t);
    6466extern int devman_fun_get_path(devman_handle_t, char *, size_t);
     67extern int devman_fun_online(devman_handle_t);
     68extern int devman_fun_offline(devman_handle_t);
    6569
    6670extern int devman_add_device_to_category(devman_handle_t, const char *);
  • uspace/lib/c/include/ipc/devman.h

    r7a72ce1a ra1b7e80  
    139139        DEVMAN_ADD_MATCH_ID,
    140140        DEVMAN_ADD_DEVICE_TO_CATEGORY,
     141        DEVMAN_DRV_FUN_ONLINE,
     142        DEVMAN_DRV_FUN_OFFLINE,
    141143        DEVMAN_REMOVE_FUNCTION
    142144} driver_to_devman_t;
    143145
    144146typedef enum {
    145         DRIVER_ADD_DEVICE = IPC_FIRST_USER_METHOD
     147        DRIVER_DEV_ADD = IPC_FIRST_USER_METHOD,
     148        DRIVER_DEV_REMOVE,
     149        DRIVER_FUN_ONLINE,
     150        DRIVER_FUN_OFFLINE,
    146151
    147152} devman_to_driver_t;
     
    152157        DEVMAN_FUN_GET_CHILD,
    153158        DEVMAN_FUN_GET_NAME,
     159        DEVMAN_FUN_ONLINE,
     160        DEVMAN_FUN_OFFLINE,
    154161        DEVMAN_FUN_GET_PATH,
    155162        DEVMAN_FUN_SID_TO_HANDLE
  • 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}
  • uspace/lib/drv/include/ddf/driver.h

    r7a72ce1a ra1b7e80  
    8181         */
    8282        devman_handle_t handle;
     83        /** Reference count */
     84        atomic_t refcnt;
    8385       
    8486        /**
     
    104106        /** Function indentifier (asigned by device manager) */
    105107        devman_handle_t handle;
     108        /** Reference count */
     109        atomic_t refcnt;
    106110       
    107111        /** Device which this function belogs to */
     
    132136typedef struct driver_ops {
    133137        /** Callback method for passing a new device to the device driver */
    134         int (*add_device)(ddf_dev_t *dev);
    135         /* TODO: add other generic driver operations */
     138        int (*add_device)(ddf_dev_t *);
     139        /** Ask driver to remove a device */
     140        int (*dev_remove)(ddf_dev_t *);
     141        /** Ask driver to online a specific function */
     142        int (*fun_online)(ddf_fun_t *);
     143        /** Ask driver to offline a specific function */
     144        int (*fun_offline)(ddf_fun_t *);
    136145} driver_ops_t;
    137146
     
    146155extern int ddf_driver_main(driver_t *);
    147156
     157extern void *ddf_dev_data_alloc(ddf_dev_t *, size_t);
    148158extern ddf_fun_t *ddf_fun_create(ddf_dev_t *, fun_type_t, const char *);
    149159extern void ddf_fun_destroy(ddf_fun_t *);
     160extern void *ddf_fun_data_alloc(ddf_fun_t *, size_t);
    150161extern int ddf_fun_bind(ddf_fun_t *);
    151162extern int ddf_fun_unbind(ddf_fun_t *);
     163extern int ddf_fun_online(ddf_fun_t *);
     164extern int ddf_fun_offline(ddf_fun_t *);
    152165extern int ddf_fun_add_match_id(ddf_fun_t *, const char *, int);
    153166
  • uspace/srv/devman/devman.c

    r7a72ce1a ra1b7e80  
    3030 * @{
    3131 */
     32/** @file Device Manager
     33 *
     34 * Locking order:
     35 *   (1) driver_t.driver_mutex
     36 *   (2) dev_tree_t.rwlock
     37 *
     38 * Synchronization:
     39 *    - device_tree.rwlock protects:
     40 *        - tree root, complete tree topology
     41 *        - complete contents of device and function nodes
     42 *    - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
     43 *      being deallocated
     44 *    - find_xxx() functions increase reference count of returned object
     45 *    - find_xxx_no_lock() do not increase reference count
     46 *
     47 * TODO
     48 *    - Track all steady and transient device/function states
     49 *    - Check states, wait for steady state on certain operations
     50 */
    3251
    3352#include <errno.h>
     
    4362#include "devman.h"
    4463
    45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);
     64static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
    4665
    4766/* hash table operations */
     
    406425        }
    407426       
     427        fun_add_ref(fun);
    408428        insert_fun_node(tree, fun, str_dup(""), NULL);
     429       
    409430        match_id_t *id = create_match_id();
    410431        id->id = str_dup("root");
     
    422443        }
    423444       
     445        dev_add_ref(dev);
    424446        insert_dev_node(tree, dev, fun);
    425447       
     
    467489/** Assign a driver to a device.
    468490 *
     491 * @param tree          Device tree
    469492 * @param node          The device's node in the device tree.
    470493 * @param drv           The driver.
    471494 */
    472 void attach_driver(dev_node_t *dev, driver_t *drv)
     495void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
    473496{
    474497        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
     
    476499       
    477500        fibril_mutex_lock(&drv->driver_mutex);
     501        fibril_rwlock_write_lock(&tree->rwlock);
    478502       
    479503        dev->drv = drv;
    480504        list_append(&dev->driver_devices, &drv->devices);
    481505       
     506        fibril_rwlock_write_unlock(&tree->rwlock);
     507        fibril_mutex_unlock(&drv->driver_mutex);
     508}
     509
     510/** Detach driver from device.
     511 *
     512 * @param tree          Device tree
     513 * @param node          The device's node in the device tree.
     514 * @param drv           The driver.
     515 */
     516void detach_driver(dev_tree_t *tree, dev_node_t *dev)
     517{
     518        driver_t *drv = dev->drv;
     519       
     520        assert(drv != NULL);
     521       
     522        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
     523            dev->pfun->pathname, drv->name);
     524       
     525        fibril_mutex_lock(&drv->driver_mutex);
     526        fibril_rwlock_write_lock(&tree->rwlock);
     527       
     528        dev->drv = NULL;
     529        list_remove(&dev->driver_devices);
     530       
     531        fibril_rwlock_write_unlock(&tree->rwlock);
    482532        fibril_mutex_unlock(&drv->driver_mutex);
    483533}
     
    556606        while (link != &driver->devices.head) {
    557607                dev = list_get_instance(link, dev_node_t, driver_devices);
     608                fibril_rwlock_write_lock(&tree->rwlock);
     609               
    558610                if (dev->passed_to_driver) {
     611                        fibril_rwlock_write_unlock(&tree->rwlock);
    559612                        link = link->next;
    560613                        continue;
    561614                }
    562615
    563                 /*
    564                  * We remove the device from the list to allow safe adding
    565                  * of new devices (no one will touch our item this way).
    566                  */
    567                 list_remove(link);
     616                log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
     617                    (int)atomic_get(&dev->refcnt));
     618                dev_add_ref(dev);
    568619
    569620                /*
     
    572623                 */
    573624                fibril_mutex_unlock(&driver->driver_mutex);
     625                fibril_rwlock_write_unlock(&tree->rwlock);
    574626
    575627                add_device(driver, dev, tree);
     628
     629                dev_del_ref(dev);
    576630
    577631                /*
     
    580634                 */
    581635                fibril_mutex_lock(&driver->driver_mutex);
    582 
    583                 /*
    584                  * Insert the device back.
    585                  * The order is not relevant here so no harm is done
    586                  * (actually, the order would be preserved in most cases).
    587                  */
    588                 list_append(link, &driver->devices);
    589636
    590637                /*
     
    679726        char *loc_name = NULL;
    680727       
     728        assert(fibril_rwlock_is_locked(&tree->rwlock));
     729       
    681730        asprintf(&loc_name, "%s", fun->pathname);
    682731        if (loc_name == NULL)
     
    726775       
    727776        ipc_call_t answer;
    728         aid_t req = async_send_2(exch, DRIVER_ADD_DEVICE, dev->handle,
     777        aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
    729778            parent_handle, &answer);
    730779       
     
    783832       
    784833        /* Attach the driver to the device. */
    785         attach_driver(dev, drv);
     834        attach_driver(tree, dev, drv);
    786835       
    787836        fibril_mutex_lock(&drv->driver_mutex);
     
    797846                add_device(drv, dev, tree);
    798847       
     848        fibril_mutex_lock(&drv->driver_mutex);
     849        fibril_mutex_unlock(&drv->driver_mutex);
     850
     851        fibril_rwlock_write_lock(&tree->rwlock);
     852        if (dev->pfun != NULL) {
     853                dev->pfun->state = FUN_ON_LINE;
     854        }
     855        fibril_rwlock_write_unlock(&tree->rwlock);
    799856        return true;
     857}
     858
     859int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
     860{
     861        async_exch_t *exch;
     862        sysarg_t retval;
     863        driver_t *drv;
     864        devman_handle_t handle;
     865       
     866        assert(dev != NULL);
     867       
     868        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
     869       
     870        fibril_rwlock_read_lock(&tree->rwlock);
     871        drv = dev->drv;
     872        handle = dev->handle;
     873        fibril_rwlock_read_unlock(&tree->rwlock);
     874       
     875        exch = async_exchange_begin(drv->sess);
     876        retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
     877        async_exchange_end(exch);
     878       
     879        return retval;
     880
     881}
     882
     883int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
     884{
     885        async_exch_t *exch;
     886        sysarg_t retval;
     887        driver_t *drv;
     888        devman_handle_t handle;
     889       
     890        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
     891
     892        fibril_rwlock_read_lock(&tree->rwlock);
     893       
     894        if (fun->dev == NULL) {
     895                /* XXX root function? */
     896                fibril_rwlock_read_unlock(&tree->rwlock);
     897                return EINVAL;
     898        }
     899       
     900        drv = fun->dev->drv;
     901        handle = fun->handle;
     902        fibril_rwlock_read_unlock(&tree->rwlock);
     903       
     904        exch = async_exchange_begin(drv->sess);
     905        retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
     906        loc_exchange_end(exch);
     907       
     908        return retval;
     909}
     910
     911int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
     912{
     913        async_exch_t *exch;
     914        sysarg_t retval;
     915        driver_t *drv;
     916        devman_handle_t handle;
     917       
     918        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
     919
     920        fibril_rwlock_read_lock(&tree->rwlock);
     921        if (fun->dev == NULL) {
     922                /* XXX root function? */
     923                fibril_rwlock_read_unlock(&tree->rwlock);
     924                return EINVAL;
     925        }
     926       
     927        drv = fun->dev->drv;
     928        handle = fun->handle;
     929        fibril_rwlock_read_unlock(&tree->rwlock);
     930       
     931        exch = async_exchange_begin(drv->sess);
     932        retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
     933        loc_exchange_end(exch);
     934       
     935        return retval;
     936
    800937}
    801938
     
    826963        if (!create_root_nodes(tree))
    827964                return false;
    828 
     965   
    829966        /* Find suitable driver and start it. */
    830         return assign_driver(tree->root_node->child, drivers_list, tree);
     967        dev_node_t *rdev = tree->root_node->child;
     968        dev_add_ref(rdev);
     969        int rc = assign_driver(rdev, drivers_list, tree);
     970        dev_del_ref(rdev);
     971       
     972        return rc;
    831973}
    832974
     
    839981dev_node_t *create_dev_node(void)
    840982{
    841         dev_node_t *res = malloc(sizeof(dev_node_t));
    842        
    843         if (res != NULL) {
    844                 memset(res, 0, sizeof(dev_node_t));
    845                 list_initialize(&res->functions);
    846                 link_initialize(&res->driver_devices);
    847                 link_initialize(&res->devman_dev);
    848         }
    849        
    850         return res;
     983        dev_node_t *dev;
     984       
     985        dev = calloc(1, sizeof(dev_node_t));
     986        if (dev == NULL)
     987                return NULL;
     988       
     989        atomic_set(&dev->refcnt, 0);
     990        list_initialize(&dev->functions);
     991        link_initialize(&dev->driver_devices);
     992        link_initialize(&dev->devman_dev);
     993       
     994        return dev;
    851995}
    852996
     
    8641008}
    8651009
     1010/** Increase device node reference count.
     1011 *
     1012 * @param dev   Device node
     1013 */
     1014void dev_add_ref(dev_node_t *dev)
     1015{
     1016        atomic_inc(&dev->refcnt);
     1017}
     1018
     1019/** Decrease device node reference count.
     1020 *
     1021 * When the count drops to zero the device node is freed.
     1022 *
     1023 * @param dev   Device node
     1024 */
     1025void dev_del_ref(dev_node_t *dev)
     1026{
     1027        if (atomic_predec(&dev->refcnt) == 0)
     1028                delete_dev_node(dev);
     1029}
     1030
     1031
    8661032/** Find the device node structure of the device witch has the specified handle.
    8671033 *
     
    8931059        fibril_rwlock_read_lock(&tree->rwlock);
    8941060        dev = find_dev_node_no_lock(tree, handle);
     1061        if (dev != NULL)
     1062                dev_add_ref(dev);
     1063       
    8951064        fibril_rwlock_read_unlock(&tree->rwlock);
    8961065       
     
    9201089                    list_get_instance(item, fun_node_t, dev_functions);
    9211090
    922                 if (pos < buf_cnt)
     1091                if (pos < buf_cnt) {
    9231092                        hdl_buf[pos] = fun->handle;
     1093                }
     1094
    9241095                pos++;
    9251096        }
     
    9371108fun_node_t *create_fun_node(void)
    9381109{
    939         fun_node_t *res = malloc(sizeof(fun_node_t));
    940        
    941         if (res != NULL) {
    942                 memset(res, 0, sizeof(fun_node_t));
    943                 link_initialize(&res->dev_functions);
    944                 list_initialize(&res->match_ids.ids);
    945                 link_initialize(&res->devman_fun);
    946                 link_initialize(&res->loc_fun);
    947         }
    948        
    949         return res;
     1110        fun_node_t *fun;
     1111
     1112        fun = calloc(1, sizeof(fun_node_t));
     1113        if (fun == NULL)
     1114                return NULL;
     1115       
     1116        fun->state = FUN_INIT;
     1117        atomic_set(&fun->refcnt, 0);
     1118        link_initialize(&fun->dev_functions);
     1119        list_initialize(&fun->match_ids.ids);
     1120        link_initialize(&fun->devman_fun);
     1121        link_initialize(&fun->loc_fun);
     1122       
     1123        return fun;
    9501124}
    9511125
     
    9651139}
    9661140
     1141/** Increase function node reference count.
     1142 *
     1143 * @param fun   Function node
     1144 */
     1145void fun_add_ref(fun_node_t *fun)
     1146{
     1147        atomic_inc(&fun->refcnt);
     1148}
     1149
     1150/** Decrease function node reference count.
     1151 *
     1152 * When the count drops to zero the function node is freed.
     1153 *
     1154 * @param fun   Function node
     1155 */
     1156void fun_del_ref(fun_node_t *fun)
     1157{
     1158        if (atomic_predec(&fun->refcnt) == 0)
     1159                delete_fun_node(fun);
     1160}
     1161
    9671162/** Find the function node with the specified handle.
    9681163 *
     
    9751170        unsigned long key = handle;
    9761171        link_t *link;
     1172        fun_node_t *fun;
    9771173       
    9781174        assert(fibril_rwlock_is_locked(&tree->rwlock));
     
    9821178                return NULL;
    9831179       
    984         return hash_table_get_instance(link, fun_node_t, devman_fun);
     1180        fun = hash_table_get_instance(link, fun_node_t, devman_fun);
     1181       
     1182        return fun;
    9851183}
    9861184
     
    9961194       
    9971195        fibril_rwlock_read_lock(&tree->rwlock);
     1196       
    9981197        fun = find_fun_node_no_lock(tree, handle);
     1198        if (fun != NULL)
     1199                fun_add_ref(fun);
     1200       
    9991201        fibril_rwlock_read_unlock(&tree->rwlock);
    10001202       
     
    10041206/** Create and set device's full path in device tree.
    10051207 *
     1208 * @param tree          Device tree
    10061209 * @param node          The device's device node.
    10071210 * @param parent        The parent device node.
     
    10091212 *                      resources etc.).
    10101213 */
    1011 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
    1012 {
     1214static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
     1215{
     1216        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10131217        assert(fun->name != NULL);
    10141218       
     
    10371241 *
    10381242 * @param tree          The device tree.
    1039  * @param node          The newly added device node.
    1040  * @param dev_name      The name of the newly added device.
    1041  * @param parent        The parent device node.
     1243 * @param dev           The newly added device node.
     1244 * @param pfun          The parent function node.
    10421245 *
    10431246 * @return              True on success, false otherwise (insufficient resources
     
    10461249bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
    10471250{
    1048         assert(dev != NULL);
    1049         assert(tree != NULL);
    10501251        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    10511252       
     
    10651266}
    10661267
     1268/** Remove device from device tree.
     1269 *
     1270 * @param tree          Device tree
     1271 * @param dev           Device node
     1272 */
     1273void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
     1274{
     1275        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1276       
     1277        log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
     1278       
     1279        /* Remove node from the handle-to-node map. */
     1280        unsigned long key = dev->handle;
     1281        hash_table_remove(&tree->devman_devices, &key, 1);
     1282       
     1283        /* Unlink from parent function. */
     1284        dev->pfun->child = NULL;
     1285        dev->pfun = NULL;
     1286       
     1287        dev->state = DEVICE_REMOVED;
     1288}
     1289
     1290
    10671291/** Insert new function into device tree.
    10681292 *
    10691293 * @param tree          The device tree.
    1070  * @param node          The newly added function node.
    1071  * @param dev_name      The name of the newly added function.
    1072  * @param parent        Owning device node.
     1294 * @param fun           The newly added function node.
     1295 * @param fun_name      The name of the newly added function.
     1296 * @param dev           Owning device node.
    10731297 *
    10741298 * @return              True on success, false otherwise (insufficient resources
     
    10801304        fun_node_t *pfun;
    10811305       
    1082         assert(fun != NULL);
    1083         assert(tree != NULL);
    10841306        assert(fun_name != NULL);
    10851307        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     
    10921314       
    10931315        fun->name = fun_name;
    1094         if (!set_fun_path(fun, pfun)) {
     1316        if (!set_fun_path(tree, fun, pfun)) {
    10951317                return false;
    10961318        }
     
    11161338void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
    11171339{
    1118         assert(tree != NULL);
    1119         assert(fun != NULL);
    11201340        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
    11211341       
     
    11271347        if (fun->dev != NULL)
    11281348                list_remove(&fun->dev_functions);
     1349       
     1350        fun->dev = NULL;
     1351        fun->state = FUN_REMOVED;
    11291352}
    11301353
     
    11481371       
    11491372        fun_node_t *fun = tree->root_node;
     1373        fun_add_ref(fun);
    11501374        /*
    11511375         * Relative path to the function from its parent (but with '/' at the
     
    11651389                }
    11661390               
    1167                 fun = find_node_child(fun, rel_path + 1);
     1391                fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
     1392                fun_del_ref(fun);
     1393                fun = cfun;
    11681394               
    11691395                if (cont) {
     
    11831409 * Device tree rwlock should be held at least for reading.
    11841410 *
     1411 * @param tree Device tree
    11851412 * @param dev Device the function belongs to.
    11861413 * @param name Function name (not path).
     
    11881415 * @retval NULL No function with given name.
    11891416 */
    1190 fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
    1191 {
    1192         assert(dev != NULL);
     1417fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
     1418    const char *name)
     1419{
    11931420        assert(name != NULL);
     1421        assert(fibril_rwlock_is_locked(&tree->rwlock));
    11941422
    11951423        fun_node_t *fun;
     
    11981426                fun = list_get_instance(link, fun_node_t, dev_functions);
    11991427
    1200                 if (str_cmp(name, fun->name) == 0)
     1428                if (str_cmp(name, fun->name) == 0) {
     1429                        fun_add_ref(fun);
    12011430                        return fun;
     1431                }
    12021432        }
    12031433
     
    12091439 * Device tree rwlock should be held at least for reading.
    12101440 *
     1441 * @param tree          Device tree
    12111442 * @param parent        The parent function node.
    12121443 * @param name          The name of the child function.
    12131444 * @return              The child function node.
    12141445 */
    1215 fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
    1216 {
    1217         return find_fun_node_in_device(pfun->child, name);
     1446static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
     1447    const char *name)
     1448{
     1449        return find_fun_node_in_device(tree, pfun->child, name);
    12181450}
    12191451
     
    12281460        fibril_rwlock_read_lock(&tree->rwlock);
    12291461        link = hash_table_find(&tree->loc_functions, &key);
    1230         if (link != NULL)
     1462        if (link != NULL) {
    12311463                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
     1464                fun_add_ref(fun);
     1465        }
    12321466        fibril_rwlock_read_unlock(&tree->rwlock);
    12331467       
     
    12371471void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
    12381472{
     1473        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
     1474       
    12391475        unsigned long key = (unsigned long) fun->service_id;
    1240         fibril_rwlock_write_lock(&tree->rwlock);
    12411476        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
    1242         fibril_rwlock_write_unlock(&tree->rwlock);
    12431477}
    12441478
  • uspace/srv/devman/devman.h

    r7a72ce1a ra1b7e80  
    118118} driver_list_t;
    119119
    120 /** The state of the device. */
     120/** Device state */
    121121typedef enum {
    122122        DEVICE_NOT_INITIALIZED = 0,
    123123        DEVICE_USABLE,
    124124        DEVICE_NOT_PRESENT,
    125         DEVICE_INVALID
     125        DEVICE_INVALID,
     126        /** Device node has been removed from the tree */
     127        DEVICE_REMOVED
    126128} device_state_t;
    127129
    128130/** Device node in the device tree. */
    129131struct dev_node {
     132        /** Reference count */
     133        atomic_t refcnt;
     134       
    130135        /** The global unique identifier of the device. */
    131136        devman_handle_t handle;
     
    154159};
    155160
     161/** Function state */
     162typedef enum {
     163        FUN_INIT = 0,
     164        FUN_OFF_LINE,
     165        FUN_ON_LINE,
     166        /** Function node has been removed from the tree */
     167        FUN_REMOVED
     168} fun_state_t;
     169
    156170/** Function node in the device tree. */
    157171struct fun_node {
     172        /** Reference count */
     173        atomic_t refcnt;
     174        /** State */
     175        fun_state_t state;
     176       
    158177        /** The global unique identifier of the function */
    159178        devman_handle_t handle;
     
    239258
    240259extern void add_driver(driver_list_t *, driver_t *);
    241 extern void attach_driver(dev_node_t *, driver_t *);
     260extern void attach_driver(dev_tree_t *, dev_node_t *, driver_t *);
     261extern void detach_driver(dev_tree_t *, dev_node_t *);
    242262extern void add_device(driver_t *, dev_node_t *, dev_tree_t *);
    243263extern bool start_driver(driver_t *);
     264extern int driver_dev_remove(dev_tree_t *, dev_node_t *);
     265extern int driver_fun_online(dev_tree_t *, fun_node_t *);
     266extern int driver_fun_offline(dev_tree_t *, fun_node_t *);
    244267
    245268extern driver_t *find_driver(driver_list_t *, const char *);
     
    254277extern dev_node_t *create_dev_node(void);
    255278extern void delete_dev_node(dev_node_t *node);
     279extern void dev_add_ref(dev_node_t *);
     280extern void dev_del_ref(dev_node_t *);
    256281extern dev_node_t *find_dev_node_no_lock(dev_tree_t *tree,
    257282    devman_handle_t handle);
     
    263288extern fun_node_t *create_fun_node(void);
    264289extern void delete_fun_node(fun_node_t *);
     290extern void fun_add_ref(fun_node_t *);
     291extern void fun_del_ref(fun_node_t *);
    265292extern fun_node_t *find_fun_node_no_lock(dev_tree_t *tree,
    266293    devman_handle_t handle);
    267294extern fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle);
    268295extern fun_node_t *find_fun_node_by_path(dev_tree_t *, char *);
    269 extern fun_node_t *find_fun_node_in_device(dev_node_t *, const char *);
     296extern fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *,
     297    const char *);
    270298
    271299/* Device tree */
     
    274302extern bool create_root_nodes(dev_tree_t *);
    275303extern bool insert_dev_node(dev_tree_t *, dev_node_t *, fun_node_t *);
     304extern void remove_dev_node(dev_tree_t *, dev_node_t *);
    276305extern bool insert_fun_node(dev_tree_t *, fun_node_t *, char *, dev_node_t *);
    277306extern void remove_fun_node(dev_tree_t *, fun_node_t *);
  • uspace/srv/devman/main.c

    r7a72ce1a ra1b7e80  
    234234        dev_node_t *dev_node = (dev_node_t *) arg;
    235235        assign_driver(dev_node, &drivers_list, &device_tree);
     236
     237        /* Delete one reference we got from the caller. */
     238        dev_del_ref(dev_node);
    236239        return EOK;
    237240}
    238241
    239 /** Handle function registration.
    240  *
    241  * Child devices are registered by their parent's device driver.
    242  */
    243 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
    244 {
    245         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
    246         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
    247         sysarg_t match_count = IPC_GET_ARG3(*call);
    248         dev_tree_t *tree = &device_tree;
    249        
    250         fibril_rwlock_write_lock(&tree->rwlock);
    251 
    252         dev_node_t *dev = NULL;
    253         dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
    254        
    255         if (pdev == NULL) {
    256                 fibril_rwlock_write_unlock(&tree->rwlock);
    257                 async_answer_0(callid, ENOENT);
    258                 return;
    259         }
    260        
    261         if (ftype != fun_inner && ftype != fun_exposed) {
    262                 /* Unknown function type */
    263                 log_msg(LVL_ERROR,
    264                     "Unknown function type %d provided by driver.",
    265                     (int) ftype);
    266 
    267                 fibril_rwlock_write_unlock(&tree->rwlock);
    268                 async_answer_0(callid, EINVAL);
    269                 return;
    270         }
    271        
    272         char *fun_name = NULL;
    273         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    274         if (rc != EOK) {
    275                 fibril_rwlock_write_unlock(&tree->rwlock);
    276                 async_answer_0(callid, rc);
    277                 return;
    278         }
    279        
    280         /* Check that function with same name is not there already. */
    281         if (find_fun_node_in_device(pdev, fun_name) != NULL) {
    282                 fibril_rwlock_write_unlock(&tree->rwlock);
    283                 async_answer_0(callid, EEXISTS);
    284                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
    285                     fun_name);
    286                 free(fun_name);
    287                 return;
    288         }
    289        
    290         fun_node_t *fun = create_fun_node();
    291         fun->ftype = ftype;
    292        
    293         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    294                 fibril_rwlock_write_unlock(&tree->rwlock);
    295                 delete_fun_node(fun);
    296                 async_answer_0(callid, ENOMEM);
    297                 return;
    298         }
    299 
    300         if (ftype == fun_inner) {
     242static int online_function(fun_node_t *fun)
     243{
     244        dev_node_t *dev;
     245       
     246        fibril_rwlock_write_lock(&device_tree.rwlock);
     247
     248        if (fun->state == FUN_ON_LINE) {
     249                fibril_rwlock_write_unlock(&device_tree.rwlock);
     250                log_msg(LVL_WARN, "Function %s is already on line.",
     251                    fun->pathname);
     252                return EOK;
     253        }
     254       
     255        if (fun->ftype == fun_inner) {
    301256                dev = create_dev_node();
    302257                if (dev == NULL) {
    303                         fibril_rwlock_write_unlock(&tree->rwlock);
    304                         delete_fun_node(fun);
    305                         async_answer_0(callid, ENOMEM);
    306                         return;
     258                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     259                        return ENOMEM;
    307260                }
    308261
    309                 insert_dev_node(tree, dev, fun);
    310         }
    311 
    312         fibril_rwlock_write_unlock(&tree->rwlock);
     262                insert_dev_node(&device_tree, dev, fun);
     263                dev_add_ref(dev);
     264        }
    313265       
    314266        log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    315267       
    316         devman_receive_match_ids(match_count, &fun->match_ids);
    317 
    318         if (ftype == fun_inner) {
     268        if (fun->ftype == fun_inner) {
     269                dev = fun->child;
    319270                assert(dev != NULL);
     271               
     272                /* Give one reference over to assign_driver_fibril(). */
     273                dev_add_ref(dev);
    320274                /*
    321275                 * Try to find a suitable driver and assign it to the device.  We do
     
    327281                fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
    328282                if (assign_fibril == 0) {
    329                         /*
    330                          * Fallback in case we are out of memory.
    331                          * Probably not needed as we will die soon anyway ;-).
    332                          */
    333                         (void) assign_driver_fibril(fun);
    334                 } else {
    335                         fibril_add_ready(assign_fibril);
     283                        log_msg(LVL_ERROR, "Failed to create fibril for "
     284                            "assigning driver.");
     285                        /* XXX Cleanup */
     286                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     287                        return ENOMEM;
     288                }
     289                fibril_add_ready(assign_fibril);
     290        } else {
     291                loc_register_tree_function(fun, &device_tree);
     292        }
     293       
     294        fibril_rwlock_write_unlock(&device_tree.rwlock);
     295       
     296        return EOK;
     297}
     298
     299static int offline_function(fun_node_t *fun)
     300{
     301        int rc;
     302       
     303        fibril_rwlock_write_lock(&device_tree.rwlock);
     304       
     305        if (fun->state == FUN_OFF_LINE) {
     306                fibril_rwlock_write_unlock(&device_tree.rwlock);
     307                log_msg(LVL_WARN, "Function %s is already off line.",
     308                    fun->pathname);
     309                return EOK;
     310        }
     311       
     312        if (fun->ftype == fun_inner) {
     313                log_msg(LVL_DEBUG, "Offlining inner function %s.",
     314                    fun->pathname);
     315               
     316                if (fun->child != NULL) {
     317                        dev_node_t *dev = fun->child;
     318                       
     319                        dev_add_ref(dev);
     320                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     321                       
     322                        rc = driver_dev_remove(&device_tree, dev);
     323                        if (rc != EOK) {
     324                                dev_del_ref(dev);
     325                                return ENOTSUP;
     326                        }
     327                       
     328                        detach_driver(&device_tree, dev);
     329                       
     330                        fibril_rwlock_write_lock(&device_tree.rwlock);
     331                        remove_dev_node(&device_tree, dev);
     332                       
     333                        /* Delete ref created when node was inserted */
     334                        dev_del_ref(dev);
     335                        /* Delete ref created by dev_add_ref(dev) above */
     336                        dev_del_ref(dev);
    336337                }
    337338        } else {
    338                 loc_register_tree_function(fun, tree);
     339                /* Unregister from location service */
     340                rc = loc_service_unregister(fun->service_id);
     341                if (rc != EOK) {
     342                        fibril_rwlock_write_unlock(&device_tree.rwlock);
     343                        log_msg(LVL_ERROR, "Failed unregistering tree service.");
     344                        return EIO;
     345                }
     346               
     347                fun->service_id = 0;
     348        }
     349       
     350        fun->state = FUN_OFF_LINE;
     351        fibril_rwlock_write_unlock(&device_tree.rwlock);
     352       
     353        return EOK;
     354}
     355
     356/** Handle function registration.
     357 *
     358 * Child devices are registered by their parent's device driver.
     359 */
     360static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
     361{
     362        fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
     363        devman_handle_t dev_handle = IPC_GET_ARG2(*call);
     364        sysarg_t match_count = IPC_GET_ARG3(*call);
     365        dev_tree_t *tree = &device_tree;
     366       
     367        dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
     368        if (pdev == NULL) {
     369                async_answer_0(callid, ENOENT);
     370                return;
     371        }
     372       
     373        if (ftype != fun_inner && ftype != fun_exposed) {
     374                /* Unknown function type */
     375                log_msg(LVL_ERROR,
     376                    "Unknown function type %d provided by driver.",
     377                    (int) ftype);
     378
     379                dev_del_ref(pdev);
     380                async_answer_0(callid, EINVAL);
     381                return;
     382        }
     383       
     384        char *fun_name = NULL;
     385        int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
     386        if (rc != EOK) {
     387                dev_del_ref(pdev);
     388                async_answer_0(callid, rc);
     389                return;
     390        }
     391       
     392        fibril_rwlock_write_lock(&tree->rwlock);
     393       
     394        /* Check device state */
     395        if (pdev->state == DEVICE_REMOVED) {
     396                fibril_rwlock_write_unlock(&tree->rwlock);
     397                dev_del_ref(pdev);
     398                async_answer_0(callid, ENOENT);
     399                return;
     400        }
     401       
     402        /* Check that function with same name is not there already. */
     403        if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {
     404                fibril_rwlock_write_unlock(&tree->rwlock);
     405                dev_del_ref(pdev);
     406                async_answer_0(callid, EEXISTS);
     407                printf(NAME ": Warning, driver tried to register `%s' twice.\n",
     408                    fun_name);
     409                free(fun_name);
     410                return;
     411        }
     412       
     413        fun_node_t *fun = create_fun_node();
     414        fun_add_ref(fun);
     415        fun->ftype = ftype;
     416       
     417        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
     418                fibril_rwlock_write_unlock(&tree->rwlock);
     419                dev_del_ref(pdev);
     420                delete_fun_node(fun);
     421                async_answer_0(callid, ENOMEM);
     422                return;
     423        }
     424       
     425        fibril_rwlock_write_unlock(&tree->rwlock);
     426        dev_del_ref(pdev);
     427       
     428        devman_receive_match_ids(match_count, &fun->match_ids);
     429       
     430        rc = online_function(fun);
     431        if (rc != EOK) {
     432                /* XXX clean up */
     433                async_answer_0(callid, rc);
     434                return;
    339435        }
    340436       
     
    356452                async_answer_0(callid, rc);
    357453                return;
    358         }       
     454        }
    359455       
    360456        fun_node_t *fun = find_fun_node(&device_tree, handle);
    361457        if (fun == NULL) {
     458                async_answer_0(callid, ENOENT);
     459                return;
     460        }
     461       
     462        fibril_rwlock_read_lock(&device_tree.rwlock);
     463       
     464        /* Check function state */
     465        if (fun->state == FUN_REMOVED) {
     466                fibril_rwlock_read_unlock(&device_tree.rwlock);
    362467                async_answer_0(callid, ENOENT);
    363468                return;
     
    375480            fun->pathname, cat_name);
    376481
     482        fibril_rwlock_read_unlock(&device_tree.rwlock);
     483        fun_del_ref(fun);
     484
    377485        async_answer_0(callid, EOK);
     486}
     487
     488/** Online function by driver request.
     489 *
     490 */
     491static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
     492    driver_t *drv)
     493{
     494        fun_node_t *fun;
     495        int rc;
     496
     497        printf("devman_drv_fun_online()\n");
     498        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     499        if (fun == NULL) {
     500                async_answer_0(iid, ENOENT);
     501                return;
     502        }
     503       
     504        fibril_rwlock_read_lock(&device_tree.rwlock);
     505        if (fun->dev == NULL || fun->dev->drv != drv) {
     506                fibril_rwlock_read_unlock(&device_tree.rwlock);
     507                fun_del_ref(fun);
     508                async_answer_0(iid, ENOENT);
     509                return;
     510        }
     511        fibril_rwlock_read_unlock(&device_tree.rwlock);
     512       
     513        rc = online_function(fun);
     514        if (rc != EOK) {
     515                printf("devman_drv_fun_online() online_fun->ERROR\n");
     516                fun_del_ref(fun);
     517                async_answer_0(iid, (sysarg_t) rc);
     518                return;
     519        }
     520       
     521        fun_del_ref(fun);
     522        printf("devman_drv_fun_online() online_fun->OK\n");
     523       
     524        async_answer_0(iid, (sysarg_t) EOK);
     525}
     526
     527
     528/** Offline function by driver request.
     529 *
     530 */
     531static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
     532    driver_t *drv)
     533{
     534        fun_node_t *fun;
     535        int rc;
     536
     537        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     538        if (fun == NULL) {
     539                async_answer_0(iid, ENOENT);
     540                return;
     541        }
     542       
     543        fibril_rwlock_write_lock(&device_tree.rwlock);
     544        if (fun->dev == NULL || fun->dev->drv != drv) {
     545                fun_del_ref(fun);
     546                async_answer_0(iid, ENOENT);
     547                return;
     548        }
     549        fibril_rwlock_write_unlock(&device_tree.rwlock);
     550       
     551        rc = offline_function(fun);
     552        if (rc != EOK) {
     553                fun_del_ref(fun);
     554                async_answer_0(iid, (sysarg_t) rc);
     555                return;
     556        }
     557       
     558        fun_del_ref(fun);
     559        async_answer_0(iid, (sysarg_t) EOK);
    378560}
    379561
     
    385567        int rc;
    386568       
     569       
     570        fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
     571        if (fun == NULL) {
     572                async_answer_0(callid, ENOENT);
     573                return;
     574        }
     575       
    387576        fibril_rwlock_write_lock(&tree->rwlock);
    388577       
    389         fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
    390         if (fun == NULL) {
     578        log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
     579       
     580        /* Check function state */
     581        if (fun->state == FUN_REMOVED) {
    391582                fibril_rwlock_write_unlock(&tree->rwlock);
    392583                async_answer_0(callid, ENOENT);
     
    394585        }
    395586       
    396         log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    397        
    398587        if (fun->ftype == fun_inner) {
    399588                /* Handle possible descendants */
    400                 /* TODO */
    401                 log_msg(LVL_WARN, "devman_remove_function(): not handling "
    402                     "descendants\n");
     589                /* TODO - This is a surprise removal */
     590                if (fun->child != NULL) {
     591                        log_msg(LVL_WARN, "devman_remove_function(): not handling "
     592                            "descendants\n");
     593                }
    403594        } else {
    404                 /* Unregister from location service */
    405                 rc = loc_service_unregister(fun->service_id);
    406                 if (rc != EOK) {
    407                         log_msg(LVL_ERROR, "Failed unregistering tree service.");
    408                         fibril_rwlock_write_unlock(&tree->rwlock);
    409                         async_answer_0(callid, EIO);
    410                         return;
     595                if (fun->service_id != 0) {
     596                        /* Unregister from location service */
     597                        rc = loc_service_unregister(fun->service_id);
     598                        if (rc != EOK) {
     599                                log_msg(LVL_ERROR, "Failed unregistering tree "
     600                                    "service.");
     601                                fibril_rwlock_write_unlock(&tree->rwlock);
     602                                fun_del_ref(fun);
     603                                async_answer_0(callid, EIO);
     604                                return;
     605                        }
    411606                }
    412607        }
     
    414609        remove_fun_node(&device_tree, fun);
    415610        fibril_rwlock_write_unlock(&tree->rwlock);
    416         delete_fun_node(fun);
     611       
     612        /* Delete ref added when inserting function into tree */
     613        fun_del_ref(fun);
     614        /* Delete ref added above when looking up function */
     615        fun_del_ref(fun);
    417616       
    418617        log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
     
    485684                        devman_add_function_to_cat(callid, &call);
    486685                        break;
     686                case DEVMAN_DRV_FUN_ONLINE:
     687                        devman_drv_fun_online(callid, &call, driver);
     688                        break;
     689                case DEVMAN_DRV_FUN_OFFLINE:
     690                        devman_drv_fun_offline(callid, &call, driver);
     691                        break;
    487692                case DEVMAN_REMOVE_FUNCTION:
    488693                        devman_remove_function(callid, &call);
    489694                        break;
    490695                default:
    491                         async_answer_0(callid, EINVAL); 
     696                        async_answer_0(callid, EINVAL);
    492697                        break;
    493698                }
     
    500705{
    501706        char *pathname;
     707        devman_handle_t handle;
    502708       
    503709        int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
     
    516722        }
    517723
    518         async_answer_1(iid, EOK, fun->handle);
     724        fibril_rwlock_read_lock(&device_tree.rwlock);
     725
     726        /* Check function state */
     727        if (fun->state == FUN_REMOVED) {
     728                fibril_rwlock_read_unlock(&device_tree.rwlock);
     729                async_answer_0(iid, ENOENT);
     730                return;
     731        }
     732        handle = fun->handle;
     733
     734        fibril_rwlock_read_unlock(&device_tree.rwlock);
     735
     736        /* Delete reference created above by find_fun_node_by_path() */
     737        fun_del_ref(fun);
     738
     739        async_answer_1(iid, EOK, handle);
    519740}
    520741
     
    534755        if (!async_data_read_receive(&data_callid, &data_len)) {
    535756                async_answer_0(iid, EINVAL);
     757                fun_del_ref(fun);
    536758                return;
    537759        }
     
    541763                async_answer_0(data_callid, ENOMEM);
    542764                async_answer_0(iid, ENOMEM);
     765                fun_del_ref(fun);
     766                return;
     767        }
     768
     769        fibril_rwlock_read_lock(&device_tree.rwlock);
     770
     771        /* Check function state */
     772        if (fun->state == FUN_REMOVED) {
     773                fibril_rwlock_read_unlock(&device_tree.rwlock);
     774                free(buffer);
     775
     776                async_answer_0(data_callid, ENOENT);
     777                async_answer_0(iid, ENOENT);
     778                fun_del_ref(fun);
    543779                return;
    544780        }
     
    552788        async_answer_0(iid, EOK);
    553789
     790        fibril_rwlock_read_unlock(&device_tree.rwlock);
     791        fun_del_ref(fun);
    554792        free(buffer);
    555793}
     
    571809        if (!async_data_read_receive(&data_callid, &data_len)) {
    572810                async_answer_0(iid, EINVAL);
     811                fun_del_ref(fun);
    573812                return;
    574813        }
     
    578817                async_answer_0(data_callid, ENOMEM);
    579818                async_answer_0(iid, ENOMEM);
    580                 return;
    581         }
    582 
     819                fun_del_ref(fun);
     820                return;
     821        }
     822       
     823        fibril_rwlock_read_lock(&device_tree.rwlock);
     824       
     825        /* Check function state */
     826        if (fun->state == FUN_REMOVED) {
     827                fibril_rwlock_read_unlock(&device_tree.rwlock);
     828                free(buffer);
     829
     830                async_answer_0(data_callid, ENOENT);
     831                async_answer_0(iid, ENOENT);
     832                fun_del_ref(fun);
     833                return;
     834        }
     835       
    583836        size_t sent_length = str_size(fun->pathname);
    584837        if (sent_length > data_len) {
     
    589842        async_answer_0(iid, EOK);
    590843
     844        fibril_rwlock_read_unlock(&device_tree.rwlock);
     845        fun_del_ref(fun);
    591846        free(buffer);
    592847}
     
    609864        dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    610865            IPC_GET_ARG1(*icall));
    611         if (dev == NULL) {
     866        if (dev == NULL || dev->state == DEVICE_REMOVED) {
    612867                fibril_rwlock_read_unlock(&device_tree.rwlock);
    613868                async_answer_0(callid, ENOENT);
     
    648903        fibril_rwlock_read_lock(&device_tree.rwlock);
    649904       
     905        fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
     906        if (fun == NULL || fun->state == FUN_REMOVED) {
     907                fibril_rwlock_read_unlock(&device_tree.rwlock);
     908                async_answer_0(iid, ENOENT);
     909                return;
     910        }
     911       
     912        if (fun->child == NULL) {
     913                fibril_rwlock_read_unlock(&device_tree.rwlock);
     914                async_answer_0(iid, ENOENT);
     915                return;
     916        }
     917       
     918        async_answer_1(iid, EOK, fun->child->handle);
     919       
     920        fibril_rwlock_read_unlock(&device_tree.rwlock);
     921}
     922
     923/** Online function.
     924 *
     925 * Send a request to online a function to the responsible driver.
     926 * The driver may offline other functions if necessary (i.e. if the state
     927 * of this function is linked to state of another function somehow).
     928 */
     929static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     930{
     931        fun_node_t *fun;
     932        int rc;
     933
    650934        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    651935        if (fun == NULL) {
    652                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    653                 async_answer_0(iid, ENOENT);
    654                 return;
    655         }
    656        
    657         if (fun->child == NULL) {
    658                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    659                 async_answer_0(iid, ENOENT);
    660                 return;
    661         }
    662        
    663         async_answer_1(iid, EOK, fun->child->handle);
    664        
    665         fibril_rwlock_read_unlock(&device_tree.rwlock);
     936                async_answer_0(iid, ENOENT);
     937                return;
     938        }
     939       
     940        rc = driver_fun_online(&device_tree, fun);
     941        fun_del_ref(fun);
     942       
     943        async_answer_0(iid, (sysarg_t) rc);
     944}
     945
     946/** Offline function.
     947 *
     948 * Send a request to offline a function to the responsible driver. As
     949 * a result the subtree rooted at that function should be cleanly
     950 * detatched. The driver may offline other functions if necessary
     951 * (i.e. if the state of this function is linked to state of another
     952 * function somehow).
     953 */
     954static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     955{
     956        fun_node_t *fun;
     957        int rc;
     958
     959        fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
     960        if (fun == NULL) {
     961                async_answer_0(iid, ENOENT);
     962                return;
     963        }
     964       
     965        rc = driver_fun_offline(&device_tree, fun);
     966        fun_del_ref(fun);
     967       
     968        async_answer_0(iid, (sysarg_t) rc);
    666969}
    667970
     
    678981        }
    679982
     983        fibril_rwlock_read_lock(&device_tree.rwlock);
     984
     985        /* Check function state */
     986        if (fun->state == FUN_REMOVED) {
     987                fibril_rwlock_read_unlock(&device_tree.rwlock);
     988                async_answer_0(iid, ENOENT);
     989                return;
     990        }
     991
    680992        async_answer_1(iid, EOK, fun->handle);
     993        fibril_rwlock_read_unlock(&device_tree.rwlock);
     994        fun_del_ref(fun);
    681995}
    682996
     
    7101024                        devman_fun_get_path(callid, &call);
    7111025                        break;
     1026                case DEVMAN_FUN_ONLINE:
     1027                        devman_fun_online(callid, &call);
     1028                        break;
     1029                case DEVMAN_FUN_OFFLINE:
     1030                        devman_fun_offline(callid, &call);
     1031                        break;
    7121032                case DEVMAN_FUN_SID_TO_HANDLE:
    7131033                        devman_fun_sid_to_handle(callid, &call);
     
    7301050        if (fun == NULL)
    7311051                dev = find_dev_node(&device_tree, handle);
    732         else
     1052        else {
     1053                fibril_rwlock_read_lock(&device_tree.rwlock);
    7331054                dev = fun->dev;
     1055                if (dev != NULL)
     1056                        dev_add_ref(dev);
     1057                fibril_rwlock_read_unlock(&device_tree.rwlock);
     1058        }
    7341059
    7351060        /*
     
    7431068                    "function with handle %" PRIun " was found.", handle);
    7441069                async_answer_0(iid, ENOENT);
    745                 return;
     1070                goto cleanup;
    7461071        }
    7471072
     
    7511076                    handle);
    7521077                async_answer_0(iid, ENOENT);
    753                 return;
     1078                goto cleanup;
    7541079        }
    7551080       
    7561081        driver_t *driver = NULL;
     1082       
     1083        fibril_rwlock_read_lock(&device_tree.rwlock);
    7571084       
    7581085        if (drv_to_parent) {
     
    7691096        }
    7701097       
     1098        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1099       
    7711100        if (driver == NULL) {
    7721101                log_msg(LVL_ERROR, "IPC forwarding refused - " \
    7731102                    "the device %" PRIun " is not in usable state.", handle);
    7741103                async_answer_0(iid, ENOENT);
    775                 return;
     1104                goto cleanup;
    7761105        }
    7771106       
     
    7861115                    "Could not forward to driver `%s'.", driver->name);
    7871116                async_answer_0(iid, EINVAL);
    788                 return;
     1117                goto cleanup;
    7891118        }
    7901119
     
    8021131        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    8031132        async_exchange_end(exch);
     1133
     1134cleanup:
     1135        if (dev != NULL)
     1136                dev_del_ref(dev);
     1137        if (fun != NULL)
     1138                fun_del_ref(fun);
    8041139}
    8051140
     
    8111146        fun_node_t *fun;
    8121147        dev_node_t *dev;
     1148        devman_handle_t handle;
     1149        driver_t *driver;
    8131150
    8141151        fun = find_loc_tree_function(&device_tree, service_id);
    8151152       
    816         if (fun == NULL || fun->dev->drv == NULL) {
     1153        fibril_rwlock_read_lock(&device_tree.rwlock);
     1154       
     1155        if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
    8171156                log_msg(LVL_WARN, "devman_connection_loc(): function "
    8181157                    "not found.\n");
     1158                fibril_rwlock_read_unlock(&device_tree.rwlock);
    8191159                async_answer_0(iid, ENOENT);
    8201160                return;
     
    8221162       
    8231163        dev = fun->dev;
    824        
    825         async_exch_t *exch = async_exchange_begin(dev->drv->sess);
    826         async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0,
     1164        driver = dev->drv;
     1165        handle = fun->handle;
     1166       
     1167        fibril_rwlock_read_unlock(&device_tree.rwlock);
     1168       
     1169        async_exch_t *exch = async_exchange_begin(driver->sess);
     1170        async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
    8271171            IPC_FF_NONE);
    8281172        async_exchange_end(exch);
     
    8301174        log_msg(LVL_DEBUG,
    8311175            "Forwarding loc service request for `%s' function to driver `%s'.",
    832             fun->pathname, dev->drv->name);
     1176            fun->pathname, driver->name);
     1177
     1178        fun_del_ref(fun);
    8331179}
    8341180
  • uspace/srv/loc/loc.c

    r7a72ce1a ra1b7e80  
    12311231        svc = loc_service_find_id(svc_id);
    12321232       
     1233        if (cat == NULL || svc == NULL) {
     1234                fibril_mutex_unlock(&cdir.mutex);
     1235                fibril_mutex_unlock(&services_list_mutex);
     1236                async_answer_0(iid, ENOENT);
     1237                return;
     1238        }
     1239       
    12331240        fibril_mutex_lock(&cat->mutex);
    12341241        retval = category_add_service(cat, svc);
Note: See TracChangeset for help on using the changeset viewer.