Changes in uspace/srv/devman/main.c [a96a982:9934f7d] in mainline
- File:
-
- 1 edited
-
uspace/srv/devman/main.c (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/main.c
ra96a982 r9934f7d 56 56 #include <ipc/driver.h> 57 57 #include <thread.h> 58 #include < loc.h>58 #include <devmap.h> 59 59 60 60 #include "devman.h" … … 64 64 static driver_list_t drivers_list; 65 65 static dev_tree_t device_tree; 66 67 static int init_running_drv(void *drv); 66 static class_list_t class_list; 68 67 69 68 /** Register running driver. */ 70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call) 71 { 69 static driver_t *devman_driver_register(void) 70 { 71 ipc_call_t icall; 72 ipc_callid_t iid; 72 73 driver_t *driver = NULL; 74 75 log_msg(LVL_DEBUG, "devman_driver_register"); 76 77 iid = async_get_call(&icall); 78 if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) { 79 async_answer_0(iid, EREFUSED); 80 return NULL; 81 } 82 73 83 char *drv_name = NULL; 74 75 log_msg(LVL_DEBUG, "devman_driver_register");76 84 77 85 /* Get driver name. */ 78 86 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0); 79 87 if (rc != EOK) { 80 async_answer_0( callid, rc);88 async_answer_0(iid, rc); 81 89 return NULL; 82 90 } … … 91 99 free(drv_name); 92 100 drv_name = NULL; 93 async_answer_0( callid, ENOENT);101 async_answer_0(iid, ENOENT); 94 102 return NULL; 95 103 } … … 105 113 driver->name); 106 114 fibril_mutex_unlock(&driver->driver_mutex); 107 async_answer_0( callid, EEXISTS);115 async_answer_0(iid, EEXISTS); 108 116 return NULL; 109 117 } … … 127 135 log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.", 128 136 driver->name); 129 driver->sess = async_callback_receive(EXCHANGE_ PARALLEL);137 driver->sess = async_callback_receive(EXCHANGE_SERIALIZE); 130 138 if (!driver->sess) { 131 139 fibril_mutex_unlock(&driver->driver_mutex); 132 async_answer_0( callid, ENOTSUP);140 async_answer_0(iid, ENOTSUP); 133 141 return NULL; 134 142 } 135 /* FIXME: Work around problem with callback sessions */136 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);143 144 fibril_mutex_unlock(&driver->driver_mutex); 137 145 138 146 log_msg(LVL_NOTE, 139 147 "The `%s' driver was successfully registered as running.", 140 148 driver->name); 149 150 async_answer_0(iid, EOK); 151 152 return driver; 153 } 154 155 /** Receive device match ID from the device's parent driver and add it to the 156 * list of devices match ids. 157 * 158 * @param match_ids The list of the device's match ids. 159 * @return Zero on success, negative error code otherwise. 160 */ 161 static int devman_receive_match_id(match_id_list_t *match_ids) 162 { 163 match_id_t *match_id = create_match_id(); 164 ipc_callid_t callid; 165 ipc_call_t call; 166 int rc = 0; 167 168 callid = async_get_call(&call); 169 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) { 170 log_msg(LVL_ERROR, 171 "Invalid protocol when trying to receive match id."); 172 async_answer_0(callid, EINVAL); 173 delete_match_id(match_id); 174 return EINVAL; 175 } 176 177 if (match_id == NULL) { 178 log_msg(LVL_ERROR, "Failed to allocate match id."); 179 async_answer_0(callid, ENOMEM); 180 return ENOMEM; 181 } 182 183 async_answer_0(callid, EOK); 184 185 match_id->score = IPC_GET_ARG1(call); 186 187 char *match_id_str; 188 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0); 189 match_id->id = match_id_str; 190 if (rc != EOK) { 191 delete_match_id(match_id); 192 log_msg(LVL_ERROR, "Failed to receive match id string: %s.", 193 str_error(rc)); 194 return rc; 195 } 196 197 list_append(&match_id->link, &match_ids->ids); 198 199 log_msg(LVL_DEBUG, "Received match id `%s', score %d.", 200 match_id->id, match_id->score); 201 return rc; 202 } 203 204 /** Receive device match IDs from the device's parent driver and add them to the 205 * list of devices match ids. 206 * 207 * @param match_count The number of device's match ids to be received. 208 * @param match_ids The list of the device's match ids. 209 * @return Zero on success, negative error code otherwise. 210 */ 211 static int devman_receive_match_ids(sysarg_t match_count, 212 match_id_list_t *match_ids) 213 { 214 int ret = EOK; 215 size_t i; 216 217 for (i = 0; i < match_count; i++) { 218 if (EOK != (ret = devman_receive_match_id(match_ids))) 219 return ret; 220 } 221 return ret; 222 } 223 224 static int assign_driver_fibril(void *arg) 225 { 226 dev_node_t *dev_node = (dev_node_t *) arg; 227 assign_driver(dev_node, &drivers_list, &device_tree); 228 return EOK; 229 } 230 231 /** Handle function registration. 232 * 233 * Child devices are registered by their parent's device driver. 234 */ 235 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call) 236 { 237 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call); 238 devman_handle_t dev_handle = IPC_GET_ARG2(*call); 239 sysarg_t match_count = IPC_GET_ARG3(*call); 240 dev_tree_t *tree = &device_tree; 241 242 fibril_rwlock_write_lock(&tree->rwlock); 243 244 dev_node_t *dev = NULL; 245 dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle); 246 247 if (pdev == NULL) { 248 fibril_rwlock_write_unlock(&tree->rwlock); 249 async_answer_0(callid, ENOENT); 250 return; 251 } 252 253 if (ftype != fun_inner && ftype != fun_exposed) { 254 /* Unknown function type */ 255 log_msg(LVL_ERROR, 256 "Unknown function type %d provided by driver.", 257 (int) ftype); 258 259 fibril_rwlock_write_unlock(&tree->rwlock); 260 async_answer_0(callid, EINVAL); 261 return; 262 } 263 264 char *fun_name = NULL; 265 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0); 266 if (rc != EOK) { 267 fibril_rwlock_write_unlock(&tree->rwlock); 268 async_answer_0(callid, rc); 269 return; 270 } 271 272 /* Check that function with same name is not there already. */ 273 if (find_fun_node_in_device(pdev, fun_name) != NULL) { 274 fibril_rwlock_write_unlock(&tree->rwlock); 275 async_answer_0(callid, EEXISTS); 276 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 277 fun_name); 278 free(fun_name); 279 return; 280 } 281 282 fun_node_t *fun = create_fun_node(); 283 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 284 fibril_rwlock_write_unlock(&tree->rwlock); 285 delete_fun_node(fun); 286 async_answer_0(callid, ENOMEM); 287 return; 288 } 289 290 if (ftype == fun_inner) { 291 dev = create_dev_node(); 292 if (dev == NULL) { 293 fibril_rwlock_write_unlock(&tree->rwlock); 294 delete_fun_node(fun); 295 async_answer_0(callid, ENOMEM); 296 return; 297 } 298 299 insert_dev_node(tree, dev, fun); 300 } 301 302 fibril_rwlock_write_unlock(&tree->rwlock); 303 304 log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname); 305 306 devman_receive_match_ids(match_count, &fun->match_ids); 307 308 if (ftype == fun_inner) { 309 assert(dev != NULL); 310 /* 311 * Try to find a suitable driver and assign it to the device. We do 312 * not want to block the current fibril that is used for processing 313 * incoming calls: we will launch a separate fibril to handle the 314 * driver assigning. That is because assign_driver can actually include 315 * task spawning which could take some time. 316 */ 317 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev); 318 if (assign_fibril == 0) { 319 /* 320 * Fallback in case we are out of memory. 321 * Probably not needed as we will die soon anyway ;-). 322 */ 323 (void) assign_driver_fibril(fun); 324 } else { 325 fibril_add_ready(assign_fibril); 326 } 327 } else { 328 devmap_register_tree_function(fun, tree); 329 } 330 331 /* Return device handle to parent's driver. */ 332 async_answer_1(callid, EOK, fun->handle); 333 } 334 335 static void devmap_register_class_dev(dev_class_info_t *cli) 336 { 337 /* Create devmap path and name for the device. */ 338 char *devmap_pathname = NULL; 339 340 asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE, 341 cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name); 342 if (devmap_pathname == NULL) 343 return; 344 345 /* 346 * Register the device by the device mapper and remember its devmap 347 * handle. 348 */ 349 devmap_device_register_with_iface(devmap_pathname, 350 &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP); 351 352 /* 353 * Add device to the hash map of class devices registered by device 354 * mapper. 355 */ 356 class_add_devmap_function(&class_list, cli); 357 358 free(devmap_pathname); 359 } 360 361 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call) 362 { 363 devman_handle_t handle = IPC_GET_ARG1(*call); 364 365 /* Get class name. */ 366 char *class_name; 367 int rc = async_data_write_accept((void **) &class_name, true, 368 0, 0, 0, 0); 369 if (rc != EOK) { 370 async_answer_0(callid, rc); 371 return; 372 } 373 374 fun_node_t *fun = find_fun_node(&device_tree, handle); 375 if (fun == NULL) { 376 async_answer_0(callid, ENOENT); 377 return; 378 } 379 380 dev_class_t *cl = get_dev_class(&class_list, class_name); 381 dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL); 382 383 /* Register the device's class alias by devmapper. */ 384 devmap_register_class_dev(class_info); 385 386 log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.", 387 fun->pathname, class_name, class_info->dev_name); 388 389 async_answer_0(callid, EOK); 390 } 391 392 /** Initialize driver which has registered itself as running and ready. 393 * 394 * The initialization is done in a separate fibril to avoid deadlocks (if the 395 * driver needed to be served by devman during the driver's initialization). 396 */ 397 static int init_running_drv(void *drv) 398 { 399 driver_t *driver = (driver_t *) drv; 400 401 initialize_running_driver(driver, &device_tree); 402 log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.", 403 driver->name); 404 return 0; 405 } 406 407 /** Function for handling connections from a driver to the device manager. */ 408 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall) 409 { 410 /* Accept the connection. */ 411 async_answer_0(iid, EOK); 412 413 driver_t *driver = devman_driver_register(); 414 if (driver == NULL) 415 return; 141 416 142 417 /* … … 149 424 log_msg(LVL_ERROR, "Failed to create initialization fibril " \ 150 425 "for driver `%s'.", driver->name); 151 fibril_mutex_unlock(&driver->driver_mutex); 152 async_answer_0(callid, ENOMEM); 153 return NULL; 154 } 155 426 return; 427 } 156 428 fibril_add_ready(fid); 157 fibril_mutex_unlock(&driver->driver_mutex);158 159 async_answer_0(callid, EOK);160 return driver;161 }162 163 /** Receive device match ID from the device's parent driver and add it to the164 * list of devices match ids.165 *166 * @param match_ids The list of the device's match ids.167 * @return Zero on success, negative error code otherwise.168 */169 static int devman_receive_match_id(match_id_list_t *match_ids)170 {171 match_id_t *match_id = create_match_id();172 ipc_callid_t callid;173 ipc_call_t call;174 int rc = 0;175 176 callid = async_get_call(&call);177 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {178 log_msg(LVL_ERROR,179 "Invalid protocol when trying to receive match id.");180 async_answer_0(callid, EINVAL);181 delete_match_id(match_id);182 return EINVAL;183 }184 185 if (match_id == NULL) {186 log_msg(LVL_ERROR, "Failed to allocate match id.");187 async_answer_0(callid, ENOMEM);188 return ENOMEM;189 }190 191 async_answer_0(callid, EOK);192 193 match_id->score = IPC_GET_ARG1(call);194 195 char *match_id_str;196 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);197 match_id->id = match_id_str;198 if (rc != EOK) {199 delete_match_id(match_id);200 log_msg(LVL_ERROR, "Failed to receive match id string: %s.",201 str_error(rc));202 return rc;203 }204 205 list_append(&match_id->link, &match_ids->ids);206 207 log_msg(LVL_DEBUG, "Received match id `%s', score %d.",208 match_id->id, match_id->score);209 return rc;210 }211 212 /** Receive device match IDs from the device's parent driver and add them to the213 * list of devices match ids.214 *215 * @param match_count The number of device's match ids to be received.216 * @param match_ids The list of the device's match ids.217 * @return Zero on success, negative error code otherwise.218 */219 static int devman_receive_match_ids(sysarg_t match_count,220 match_id_list_t *match_ids)221 {222 int ret = EOK;223 size_t i;224 225 for (i = 0; i < match_count; i++) {226 if (EOK != (ret = devman_receive_match_id(match_ids)))227 return ret;228 }229 return ret;230 }231 232 static int assign_driver_fibril(void *arg)233 {234 dev_node_t *dev_node = (dev_node_t *) arg;235 assign_driver(dev_node, &drivers_list, &device_tree);236 237 /* Delete one reference we got from the caller. */238 dev_del_ref(dev_node);239 return EOK;240 }241 242 static 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) {256 dev = create_dev_node();257 if (dev == NULL) {258 fibril_rwlock_write_unlock(&device_tree.rwlock);259 return ENOMEM;260 }261 262 insert_dev_node(&device_tree, dev, fun);263 dev_add_ref(dev);264 }265 266 log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);267 268 if (fun->ftype == fun_inner) {269 dev = fun->child;270 assert(dev != NULL);271 272 /* Give one reference over to assign_driver_fibril(). */273 dev_add_ref(dev);274 /*275 * Try to find a suitable driver and assign it to the device. We do276 * not want to block the current fibril that is used for processing277 * incoming calls: we will launch a separate fibril to handle the278 * driver assigning. That is because assign_driver can actually include279 * task spawning which could take some time.280 */281 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);282 if (assign_fibril == 0) {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 299 static 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 device_state_t dev_state;319 320 dev_add_ref(dev);321 dev_state = dev->state;322 323 fibril_rwlock_write_unlock(&device_tree.rwlock);324 325 /* If device is owned by driver, ask driver to give it up. */326 if (dev_state == DEVICE_USABLE) {327 rc = driver_dev_remove(&device_tree, dev);328 if (rc != EOK) {329 dev_del_ref(dev);330 return ENOTSUP;331 }332 }333 334 /* Verify that driver removed all functions */335 fibril_rwlock_read_lock(&device_tree.rwlock);336 if (!list_empty(&dev->functions)) {337 fibril_rwlock_read_unlock(&device_tree.rwlock);338 dev_del_ref(dev);339 return EIO;340 }341 342 driver_t *driver = dev->drv;343 fibril_rwlock_read_unlock(&device_tree.rwlock);344 345 if (driver)346 detach_driver(&device_tree, dev);347 348 fibril_rwlock_write_lock(&device_tree.rwlock);349 remove_dev_node(&device_tree, dev);350 351 /* Delete ref created when node was inserted */352 dev_del_ref(dev);353 /* Delete ref created by dev_add_ref(dev) above */354 dev_del_ref(dev);355 }356 } else {357 /* Unregister from location service */358 rc = loc_service_unregister(fun->service_id);359 if (rc != EOK) {360 fibril_rwlock_write_unlock(&device_tree.rwlock);361 log_msg(LVL_ERROR, "Failed unregistering tree service.");362 return EIO;363 }364 365 fun->service_id = 0;366 }367 368 fun->state = FUN_OFF_LINE;369 fibril_rwlock_write_unlock(&device_tree.rwlock);370 371 return EOK;372 }373 374 /** Handle function registration.375 *376 * Child devices are registered by their parent's device driver.377 */378 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)379 {380 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);381 devman_handle_t dev_handle = IPC_GET_ARG2(*call);382 sysarg_t match_count = IPC_GET_ARG3(*call);383 dev_tree_t *tree = &device_tree;384 385 dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);386 if (pdev == NULL) {387 async_answer_0(callid, ENOENT);388 return;389 }390 391 if (ftype != fun_inner && ftype != fun_exposed) {392 /* Unknown function type */393 log_msg(LVL_ERROR,394 "Unknown function type %d provided by driver.",395 (int) ftype);396 397 dev_del_ref(pdev);398 async_answer_0(callid, EINVAL);399 return;400 }401 402 char *fun_name = NULL;403 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);404 if (rc != EOK) {405 dev_del_ref(pdev);406 async_answer_0(callid, rc);407 return;408 }409 410 fibril_rwlock_write_lock(&tree->rwlock);411 412 /* Check device state */413 if (pdev->state == DEVICE_REMOVED) {414 fibril_rwlock_write_unlock(&tree->rwlock);415 dev_del_ref(pdev);416 async_answer_0(callid, ENOENT);417 return;418 }419 420 /* Check that function with same name is not there already. */421 if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {422 fibril_rwlock_write_unlock(&tree->rwlock);423 dev_del_ref(pdev);424 async_answer_0(callid, EEXISTS);425 printf(NAME ": Warning, driver tried to register `%s' twice.\n",426 fun_name);427 free(fun_name);428 return;429 }430 431 fun_node_t *fun = create_fun_node();432 fun_add_ref(fun);433 fun->ftype = ftype;434 435 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {436 fibril_rwlock_write_unlock(&tree->rwlock);437 dev_del_ref(pdev);438 delete_fun_node(fun);439 async_answer_0(callid, ENOMEM);440 return;441 }442 443 fibril_rwlock_write_unlock(&tree->rwlock);444 dev_del_ref(pdev);445 446 devman_receive_match_ids(match_count, &fun->match_ids);447 448 rc = online_function(fun);449 if (rc != EOK) {450 /* XXX clean up */451 async_answer_0(callid, rc);452 return;453 }454 455 /* Return device handle to parent's driver. */456 async_answer_1(callid, EOK, fun->handle);457 }458 459 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)460 {461 devman_handle_t handle = IPC_GET_ARG1(*call);462 category_id_t cat_id;463 int rc;464 465 /* Get category name. */466 char *cat_name;467 rc = async_data_write_accept((void **) &cat_name, true,468 0, 0, 0, 0);469 if (rc != EOK) {470 async_answer_0(callid, rc);471 return;472 }473 474 fun_node_t *fun = find_fun_node(&device_tree, handle);475 if (fun == NULL) {476 async_answer_0(callid, ENOENT);477 return;478 }479 480 fibril_rwlock_read_lock(&device_tree.rwlock);481 482 /* Check function state */483 if (fun->state == FUN_REMOVED) {484 fibril_rwlock_read_unlock(&device_tree.rwlock);485 async_answer_0(callid, ENOENT);486 return;487 }488 489 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);490 if (rc == EOK) {491 loc_service_add_to_cat(fun->service_id, cat_id);492 log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",493 fun->pathname, cat_name);494 } else {495 log_msg(LVL_ERROR, "Failed adding function `%s' to category "496 "`%s'.", fun->pathname, cat_name);497 }498 499 fibril_rwlock_read_unlock(&device_tree.rwlock);500 fun_del_ref(fun);501 502 async_answer_0(callid, rc);503 }504 505 /** Online function by driver request.506 *507 */508 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,509 driver_t *drv)510 {511 fun_node_t *fun;512 int rc;513 514 log_msg(LVL_DEBUG, "devman_drv_fun_online()");515 516 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));517 if (fun == NULL) {518 async_answer_0(iid, ENOENT);519 return;520 }521 522 fibril_rwlock_read_lock(&device_tree.rwlock);523 if (fun->dev == NULL || fun->dev->drv != drv) {524 fibril_rwlock_read_unlock(&device_tree.rwlock);525 fun_del_ref(fun);526 async_answer_0(iid, ENOENT);527 return;528 }529 fibril_rwlock_read_unlock(&device_tree.rwlock);530 531 rc = online_function(fun);532 if (rc != EOK) {533 fun_del_ref(fun);534 async_answer_0(iid, (sysarg_t) rc);535 return;536 }537 538 fun_del_ref(fun);539 540 async_answer_0(iid, (sysarg_t) EOK);541 }542 543 544 /** Offline function by driver request.545 *546 */547 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,548 driver_t *drv)549 {550 fun_node_t *fun;551 int rc;552 553 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));554 if (fun == NULL) {555 async_answer_0(iid, ENOENT);556 return;557 }558 559 fibril_rwlock_write_lock(&device_tree.rwlock);560 if (fun->dev == NULL || fun->dev->drv != drv) {561 fun_del_ref(fun);562 async_answer_0(iid, ENOENT);563 return;564 }565 fibril_rwlock_write_unlock(&device_tree.rwlock);566 567 rc = offline_function(fun);568 if (rc != EOK) {569 fun_del_ref(fun);570 async_answer_0(iid, (sysarg_t) rc);571 return;572 }573 574 fun_del_ref(fun);575 async_answer_0(iid, (sysarg_t) EOK);576 }577 578 /** Remove function. */579 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)580 {581 devman_handle_t fun_handle = IPC_GET_ARG1(*call);582 dev_tree_t *tree = &device_tree;583 int rc;584 585 fun_node_t *fun = find_fun_node(&device_tree, fun_handle);586 if (fun == NULL) {587 async_answer_0(callid, ENOENT);588 return;589 }590 591 fibril_rwlock_write_lock(&tree->rwlock);592 593 log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);594 595 /* Check function state */596 if (fun->state == FUN_REMOVED) {597 fibril_rwlock_write_unlock(&tree->rwlock);598 async_answer_0(callid, ENOENT);599 return;600 }601 602 if (fun->ftype == fun_inner) {603 /* This is a surprise removal. Handle possible descendants */604 if (fun->child != NULL) {605 dev_node_t *dev = fun->child;606 device_state_t dev_state;607 int gone_rc;608 609 dev_add_ref(dev);610 dev_state = dev->state;611 612 fibril_rwlock_write_unlock(&device_tree.rwlock);613 614 /* If device is owned by driver, inform driver it is gone. */615 if (dev_state == DEVICE_USABLE)616 gone_rc = driver_dev_gone(&device_tree, dev);617 else618 gone_rc = EOK;619 620 fibril_rwlock_read_lock(&device_tree.rwlock);621 622 /* Verify that driver succeeded and removed all functions */623 if (gone_rc != EOK || !list_empty(&dev->functions)) {624 log_msg(LVL_ERROR, "Driver did not remove "625 "functions for device that is gone. "626 "Device node is now defunct.");627 628 /*629 * Not much we can do but mark the device630 * node as having invalid state. This631 * is a driver bug.632 */633 dev->state = DEVICE_INVALID;634 fibril_rwlock_read_unlock(&device_tree.rwlock);635 dev_del_ref(dev);636 return;637 }638 639 driver_t *driver = dev->drv;640 fibril_rwlock_read_unlock(&device_tree.rwlock);641 642 if (driver)643 detach_driver(&device_tree, dev);644 645 fibril_rwlock_write_lock(&device_tree.rwlock);646 remove_dev_node(&device_tree, dev);647 648 /* Delete ref created when node was inserted */649 dev_del_ref(dev);650 /* Delete ref created by dev_add_ref(dev) above */651 dev_del_ref(dev);652 }653 } else {654 if (fun->service_id != 0) {655 /* Unregister from location service */656 rc = loc_service_unregister(fun->service_id);657 if (rc != EOK) {658 log_msg(LVL_ERROR, "Failed unregistering tree "659 "service.");660 fibril_rwlock_write_unlock(&tree->rwlock);661 fun_del_ref(fun);662 async_answer_0(callid, EIO);663 return;664 }665 }666 }667 668 remove_fun_node(&device_tree, fun);669 fibril_rwlock_write_unlock(&tree->rwlock);670 671 /* Delete ref added when inserting function into tree */672 fun_del_ref(fun);673 /* Delete ref added above when looking up function */674 fun_del_ref(fun);675 676 log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");677 async_answer_0(callid, EOK);678 }679 680 /** Initialize driver which has registered itself as running and ready.681 *682 * The initialization is done in a separate fibril to avoid deadlocks (if the683 * driver needed to be served by devman during the driver's initialization).684 */685 static int init_running_drv(void *drv)686 {687 driver_t *driver = (driver_t *) drv;688 689 initialize_running_driver(driver, &device_tree);690 log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",691 driver->name);692 return 0;693 }694 695 /** Function for handling connections from a driver to the device manager. */696 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)697 {698 client_t *client;699 driver_t *driver;700 701 /* Accept the connection. */702 async_answer_0(iid, EOK);703 704 client = async_get_client_data();705 if (client == NULL) {706 log_msg(LVL_ERROR, "Failed to allocate client data.");707 return;708 }709 429 710 430 while (true) { … … 715 435 break; 716 436 717 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {718 fibril_mutex_lock(&client->mutex);719 driver = client->driver;720 fibril_mutex_unlock(&client->mutex);721 if (driver == NULL) {722 /* First call must be to DEVMAN_DRIVER_REGISTER */723 async_answer_0(callid, ENOTSUP);724 continue;725 }726 }727 728 437 switch (IPC_GET_IMETHOD(call)) { 729 case DEVMAN_DRIVER_REGISTER:730 fibril_mutex_lock(&client->mutex);731 if (client->driver != NULL) {732 fibril_mutex_unlock(&client->mutex);733 async_answer_0(callid, EINVAL);734 continue;735 }736 client->driver = devman_driver_register(callid, &call);737 fibril_mutex_unlock(&client->mutex);738 break;739 438 case DEVMAN_ADD_FUNCTION: 740 439 devman_add_function(callid, &call); 741 440 break; 742 case DEVMAN_ADD_DEVICE_TO_CATEGORY: 743 devman_add_function_to_cat(callid, &call); 744 break; 745 case DEVMAN_DRV_FUN_ONLINE: 746 devman_drv_fun_online(callid, &call, driver); 747 break; 748 case DEVMAN_DRV_FUN_OFFLINE: 749 devman_drv_fun_offline(callid, &call, driver); 750 break; 751 case DEVMAN_REMOVE_FUNCTION: 752 devman_remove_function(callid, &call); 441 case DEVMAN_ADD_DEVICE_TO_CLASS: 442 devman_add_function_to_class(callid, &call); 753 443 break; 754 444 default: 755 async_answer_0(callid, EINVAL); 445 async_answer_0(callid, EINVAL); 756 446 break; 757 447 } … … 764 454 { 765 455 char *pathname; 766 devman_handle_t handle;767 456 768 457 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0); … … 781 470 } 782 471 783 fibril_rwlock_read_lock(&device_tree.rwlock); 784 785 /* Check function state */ 786 if (fun->state == FUN_REMOVED) { 787 fibril_rwlock_read_unlock(&device_tree.rwlock); 472 async_answer_1(iid, EOK, fun->handle); 473 } 474 475 /** Find handle for the device instance identified by device class name. */ 476 static void devman_function_get_handle_by_class(ipc_callid_t iid, 477 ipc_call_t *icall) 478 { 479 char *classname; 480 char *devname; 481 482 int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0); 483 if (rc != EOK) { 484 async_answer_0(iid, rc); 485 return; 486 } 487 rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0); 488 if (rc != EOK) { 489 free(classname); 490 async_answer_0(iid, rc); 491 return; 492 } 493 494 495 fun_node_t *fun = find_fun_node_by_class(&class_list, 496 classname, devname); 497 498 free(classname); 499 free(devname); 500 501 if (fun == NULL) { 788 502 async_answer_0(iid, ENOENT); 789 503 return; 790 504 } 791 handle = fun->handle; 792 793 fibril_rwlock_read_unlock(&device_tree.rwlock); 794 795 /* Delete reference created above by find_fun_node_by_path() */ 796 fun_del_ref(fun); 797 798 async_answer_1(iid, EOK, handle); 799 } 800 801 /** Get device name. */ 802 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall) 505 506 async_answer_1(iid, EOK, fun->handle); 507 } 508 509 /** Find device path by its handle. */ 510 static void devman_get_device_path_by_handle(ipc_callid_t iid, 511 ipc_call_t *icall) 803 512 { 804 513 devman_handle_t handle = IPC_GET_ARG1(*icall); … … 814 523 if (!async_data_read_receive(&data_callid, &data_len)) { 815 524 async_answer_0(iid, EINVAL); 816 fun_del_ref(fun);817 525 return; 818 526 } … … 822 530 async_answer_0(data_callid, ENOMEM); 823 531 async_answer_0(iid, ENOMEM); 824 fun_del_ref(fun); 825 return; 826 } 827 828 fibril_rwlock_read_lock(&device_tree.rwlock); 829 830 /* Check function state */ 831 if (fun->state == FUN_REMOVED) { 832 fibril_rwlock_read_unlock(&device_tree.rwlock); 833 free(buffer); 834 835 async_answer_0(data_callid, ENOENT); 836 async_answer_0(iid, ENOENT); 837 fun_del_ref(fun); 838 return; 839 } 840 841 size_t sent_length = str_size(fun->name); 842 if (sent_length > data_len) { 843 sent_length = data_len; 844 } 845 846 async_data_read_finalize(data_callid, fun->name, sent_length); 847 async_answer_0(iid, EOK); 848 849 fibril_rwlock_read_unlock(&device_tree.rwlock); 850 fun_del_ref(fun); 851 free(buffer); 852 } 853 854 855 /** Get device path. */ 856 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall) 857 { 858 devman_handle_t handle = IPC_GET_ARG1(*icall); 859 860 fun_node_t *fun = find_fun_node(&device_tree, handle); 861 if (fun == NULL) { 862 async_answer_0(iid, ENOMEM); 863 return; 864 } 865 866 ipc_callid_t data_callid; 867 size_t data_len; 868 if (!async_data_read_receive(&data_callid, &data_len)) { 869 async_answer_0(iid, EINVAL); 870 fun_del_ref(fun); 871 return; 872 } 873 874 void *buffer = malloc(data_len); 875 if (buffer == NULL) { 876 async_answer_0(data_callid, ENOMEM); 877 async_answer_0(iid, ENOMEM); 878 fun_del_ref(fun); 879 return; 880 } 881 882 fibril_rwlock_read_lock(&device_tree.rwlock); 883 884 /* Check function state */ 885 if (fun->state == FUN_REMOVED) { 886 fibril_rwlock_read_unlock(&device_tree.rwlock); 887 free(buffer); 888 889 async_answer_0(data_callid, ENOENT); 890 async_answer_0(iid, ENOENT); 891 fun_del_ref(fun); 892 return; 893 } 894 532 return; 533 } 534 895 535 size_t sent_length = str_size(fun->pathname); 896 536 if (sent_length > data_len) { … … 901 541 async_answer_0(iid, EOK); 902 542 903 fibril_rwlock_read_unlock(&device_tree.rwlock);904 fun_del_ref(fun);905 543 free(buffer); 906 544 } 907 545 908 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)909 {910 ipc_callid_t callid;911 size_t size;912 size_t act_size;913 int rc;914 915 if (!async_data_read_receive(&callid, &size)) {916 async_answer_0(callid, EREFUSED);917 async_answer_0(iid, EREFUSED);918 return;919 }920 921 fibril_rwlock_read_lock(&device_tree.rwlock);922 923 dev_node_t *dev = find_dev_node_no_lock(&device_tree,924 IPC_GET_ARG1(*icall));925 if (dev == NULL || dev->state == DEVICE_REMOVED) {926 fibril_rwlock_read_unlock(&device_tree.rwlock);927 async_answer_0(callid, ENOENT);928 async_answer_0(iid, ENOENT);929 return;930 }931 932 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);933 if (hdl_buf == NULL) {934 fibril_rwlock_read_unlock(&device_tree.rwlock);935 async_answer_0(callid, ENOMEM);936 async_answer_0(iid, ENOMEM);937 return;938 }939 940 rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);941 if (rc != EOK) {942 fibril_rwlock_read_unlock(&device_tree.rwlock);943 async_answer_0(callid, rc);944 async_answer_0(iid, rc);945 return;946 }947 948 fibril_rwlock_read_unlock(&device_tree.rwlock);949 950 sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);951 free(hdl_buf);952 953 async_answer_1(iid, retval, act_size);954 }955 956 957 /** Get handle for child device of a function. */958 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)959 {960 fun_node_t *fun;961 962 fibril_rwlock_read_lock(&device_tree.rwlock);963 964 fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));965 if (fun == NULL || fun->state == FUN_REMOVED) {966 fibril_rwlock_read_unlock(&device_tree.rwlock);967 async_answer_0(iid, ENOENT);968 return;969 }970 971 if (fun->child == NULL) {972 fibril_rwlock_read_unlock(&device_tree.rwlock);973 async_answer_0(iid, ENOENT);974 return;975 }976 977 async_answer_1(iid, EOK, fun->child->handle);978 979 fibril_rwlock_read_unlock(&device_tree.rwlock);980 }981 982 /** Online function.983 *984 * Send a request to online a function to the responsible driver.985 * The driver may offline other functions if necessary (i.e. if the state986 * of this function is linked to state of another function somehow).987 */988 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)989 {990 fun_node_t *fun;991 int rc;992 993 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));994 if (fun == NULL) {995 async_answer_0(iid, ENOENT);996 return;997 }998 999 rc = driver_fun_online(&device_tree, fun);1000 fun_del_ref(fun);1001 1002 async_answer_0(iid, (sysarg_t) rc);1003 }1004 1005 /** Offline function.1006 *1007 * Send a request to offline a function to the responsible driver. As1008 * a result the subtree rooted at that function should be cleanly1009 * detatched. The driver may offline other functions if necessary1010 * (i.e. if the state of this function is linked to state of another1011 * function somehow).1012 */1013 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)1014 {1015 fun_node_t *fun;1016 int rc;1017 1018 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));1019 if (fun == NULL) {1020 async_answer_0(iid, ENOENT);1021 return;1022 }1023 1024 rc = driver_fun_offline(&device_tree, fun);1025 fun_del_ref(fun);1026 1027 async_answer_0(iid, (sysarg_t) rc);1028 }1029 1030 /** Find handle for the function instance identified by its service ID. */1031 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)1032 {1033 fun_node_t *fun;1034 1035 fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));1036 1037 if (fun == NULL) {1038 async_answer_0(iid, ENOENT);1039 return;1040 }1041 1042 fibril_rwlock_read_lock(&device_tree.rwlock);1043 1044 /* Check function state */1045 if (fun->state == FUN_REMOVED) {1046 fibril_rwlock_read_unlock(&device_tree.rwlock);1047 async_answer_0(iid, ENOENT);1048 return;1049 }1050 1051 async_answer_1(iid, EOK, fun->handle);1052 fibril_rwlock_read_unlock(&device_tree.rwlock);1053 fun_del_ref(fun);1054 }1055 546 1056 547 /** Function for handling connections from a client to the device manager. */ … … 1071 562 devman_function_get_handle(callid, &call); 1072 563 break; 1073 case DEVMAN_DEV _GET_FUNCTIONS:1074 devman_ dev_get_functions(callid, &call);564 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS: 565 devman_function_get_handle_by_class(callid, &call); 1075 566 break; 1076 case DEVMAN_FUN_GET_CHILD: 1077 devman_fun_get_child(callid, &call); 1078 break; 1079 case DEVMAN_FUN_GET_NAME: 1080 devman_fun_get_name(callid, &call); 1081 break; 1082 case DEVMAN_FUN_GET_PATH: 1083 devman_fun_get_path(callid, &call); 1084 break; 1085 case DEVMAN_FUN_ONLINE: 1086 devman_fun_online(callid, &call); 1087 break; 1088 case DEVMAN_FUN_OFFLINE: 1089 devman_fun_offline(callid, &call); 1090 break; 1091 case DEVMAN_FUN_SID_TO_HANDLE: 1092 devman_fun_sid_to_handle(callid, &call); 567 case DEVMAN_DEVICE_GET_DEVICE_PATH: 568 devman_get_device_path_by_handle(callid, &call); 1093 569 break; 1094 570 default: … … 1109 585 if (fun == NULL) 1110 586 dev = find_dev_node(&device_tree, handle); 1111 else { 1112 fibril_rwlock_read_lock(&device_tree.rwlock); 587 else 1113 588 dev = fun->dev; 1114 if (dev != NULL)1115 dev_add_ref(dev);1116 fibril_rwlock_read_unlock(&device_tree.rwlock);1117 }1118 589 1119 590 /* … … 1127 598 "function with handle %" PRIun " was found.", handle); 1128 599 async_answer_0(iid, ENOENT); 1129 goto cleanup;600 return; 1130 601 } 1131 602 … … 1135 606 handle); 1136 607 async_answer_0(iid, ENOENT); 1137 goto cleanup;608 return; 1138 609 } 1139 610 1140 611 driver_t *driver = NULL; 1141 1142 fibril_rwlock_read_lock(&device_tree.rwlock);1143 612 1144 613 if (drv_to_parent) { … … 1155 624 } 1156 625 1157 fibril_rwlock_read_unlock(&device_tree.rwlock);1158 1159 626 if (driver == NULL) { 1160 627 log_msg(LVL_ERROR, "IPC forwarding refused - " \ 1161 628 "the device %" PRIun " is not in usable state.", handle); 1162 629 async_answer_0(iid, ENOENT); 1163 goto cleanup;630 return; 1164 631 } 1165 632 … … 1174 641 "Could not forward to driver `%s'.", driver->name); 1175 642 async_answer_0(iid, EINVAL); 1176 goto cleanup;643 return; 1177 644 } 1178 645 … … 1190 657 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE); 1191 658 async_exchange_end(exch); 1192 1193 cleanup: 1194 if (dev != NULL) 1195 dev_del_ref(dev); 1196 if (fun != NULL) 1197 fun_del_ref(fun); 1198 } 1199 1200 /** Function for handling connections from a client forwarded by the location 1201 * service to the device manager. */ 1202 static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall) 1203 { 1204 service_id_t service_id = IPC_GET_ARG2(*icall); 659 } 660 661 /** Function for handling connections from a client forwarded by the device 662 * mapper to the device manager. */ 663 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall) 664 { 665 devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall); 1205 666 fun_node_t *fun; 1206 667 dev_node_t *dev; 1207 devman_handle_t handle; 1208 driver_t *driver; 1209 1210 fun = find_loc_tree_function(&device_tree, service_id); 1211 1212 fibril_rwlock_read_lock(&device_tree.rwlock); 1213 1214 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) { 1215 log_msg(LVL_WARN, "devman_connection_loc(): function " 1216 "not found.\n"); 1217 fibril_rwlock_read_unlock(&device_tree.rwlock); 668 669 fun = find_devmap_tree_function(&device_tree, devmap_handle); 670 if (fun == NULL) 671 fun = find_devmap_class_function(&class_list, devmap_handle); 672 673 if (fun == NULL || fun->dev->drv == NULL) { 1218 674 async_answer_0(iid, ENOENT); 1219 675 return; … … 1221 677 1222 678 dev = fun->dev; 1223 driver = dev->drv; 1224 handle = fun->handle; 1225 1226 fibril_rwlock_read_unlock(&device_tree.rwlock); 1227 1228 async_exch_t *exch = async_exchange_begin(driver->sess); 1229 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0, 679 680 if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) { 681 async_answer_0(iid, EINVAL); 682 return; 683 } 684 685 async_exch_t *exch = async_exchange_begin(dev->drv->sess); 686 async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0, 1230 687 IPC_FF_NONE); 1231 688 async_exchange_end(exch); 1232 689 1233 690 log_msg(LVL_DEBUG, 1234 "Forwarding loc service request for `%s' function to driver `%s'.", 1235 fun->pathname, driver->name); 1236 1237 fun_del_ref(fun); 691 "Forwarding devmapper request for `%s' function to driver `%s'.", 692 fun->pathname, dev->drv->name); 1238 693 } 1239 694 … … 1241 696 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 1242 697 { 1243 /* Select port. */698 /* Select interface. */ 1244 699 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 1245 700 case DEVMAN_DRIVER: … … 1253 708 devman_forward(iid, icall, false); 1254 709 break; 1255 case DEVMAN_CONNECT_FROM_ LOC:1256 /* Someone connected through locnode. */1257 devman_connection_ loc(iid, icall);710 case DEVMAN_CONNECT_FROM_DEVMAP: 711 /* Someone connected through devmap node. */ 712 devman_connection_devmapper(iid, icall); 1258 713 break; 1259 714 case DEVMAN_CONNECT_TO_PARENTS_DEVICE: … … 1267 722 } 1268 723 1269 static void *devman_client_data_create(void)1270 {1271 client_t *client;1272 1273 client = calloc(1, sizeof(client_t));1274 if (client == NULL)1275 return NULL;1276 1277 fibril_mutex_initialize(&client->mutex);1278 return client;1279 }1280 1281 static void devman_client_data_destroy(void *data)1282 {1283 free(data);1284 }1285 1286 724 /** Initialize device manager internal structures. */ 1287 725 static bool devman_init(void) … … 1305 743 } 1306 744 745 init_class_list(&class_list); 746 1307 747 /* 1308 * !!! devman_connection ... as the device manager is not a real loc748 * !!! devman_connection ... as the device manager is not a real devmap 1309 749 * driver (it uses a completely different ipc protocol than an ordinary 1310 * locdriver) forwarding a connection from client to the devman by1311 * location servicewould not work.750 * devmap driver) forwarding a connection from client to the devman by 751 * devmapper would not work. 1312 752 */ 1313 loc_server_register(NAME, devman_connection);753 devmap_driver_register(NAME, devman_connection); 1314 754 1315 755 return true; … … 1320 760 printf(NAME ": HelenOS Device Manager\n"); 1321 761 1322 if (log_init(NAME, LVL_ WARN) != EOK) {762 if (log_init(NAME, LVL_ERROR) != EOK) { 1323 763 printf(NAME ": Error initializing logging subsystem.\n"); 1324 764 return -1; … … 1330 770 } 1331 771 1332 /* Set handlers for incoming connections. */ 1333 async_set_client_data_constructor(devman_client_data_create); 1334 async_set_client_data_destructor(devman_client_data_destroy); 772 /* Set a handler of incomming connections. */ 1335 773 async_set_client_connection(devman_connection); 1336 774
Note:
See TracChangeset
for help on using the changeset viewer.
