Changes in uspace/srv/devman/main.c [80a96d2:7beb220] in mainline
- File:
-
- 1 edited
-
uspace/srv/devman/main.c (modified) (32 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/main.c
r80a96d2 r7beb220 65 65 static dev_tree_t device_tree; 66 66 67 static int init_running_drv(void *drv);68 69 67 /** Register running driver. */ 70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call) 71 { 68 static driver_t *devman_driver_register(void) 69 { 70 ipc_call_t icall; 71 ipc_callid_t iid; 72 72 driver_t *driver = NULL; 73 74 log_msg(LVL_DEBUG, "devman_driver_register"); 75 76 iid = async_get_call(&icall); 77 if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) { 78 async_answer_0(iid, EREFUSED); 79 return NULL; 80 } 81 73 82 char *drv_name = NULL; 74 75 log_msg(LVL_DEBUG, "devman_driver_register");76 83 77 84 /* Get driver name. */ 78 85 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0); 79 86 if (rc != EOK) { 80 async_answer_0( callid, rc);87 async_answer_0(iid, rc); 81 88 return NULL; 82 89 } … … 91 98 free(drv_name); 92 99 drv_name = NULL; 93 async_answer_0( callid, ENOENT);100 async_answer_0(iid, ENOENT); 94 101 return NULL; 95 102 } … … 105 112 driver->name); 106 113 fibril_mutex_unlock(&driver->driver_mutex); 107 async_answer_0( callid, EEXISTS);114 async_answer_0(iid, EEXISTS); 108 115 return NULL; 109 116 } … … 127 134 log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.", 128 135 driver->name); 129 driver->sess = async_callback_receive(EXCHANGE_ PARALLEL);136 driver->sess = async_callback_receive(EXCHANGE_SERIALIZE); 130 137 if (!driver->sess) { 131 138 fibril_mutex_unlock(&driver->driver_mutex); 132 async_answer_0( callid, ENOTSUP);139 async_answer_0(iid, ENOTSUP); 133 140 return NULL; 134 141 } 135 /* FIXME: Work around problem with callback sessions */136 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);142 143 fibril_mutex_unlock(&driver->driver_mutex); 137 144 138 145 log_msg(LVL_NOTE, 139 146 "The `%s' driver was successfully registered as running.", 140 147 driver->name); 148 149 async_answer_0(iid, EOK); 150 151 return driver; 152 } 153 154 /** Receive device match ID from the device's parent driver and add it to the 155 * list of devices match ids. 156 * 157 * @param match_ids The list of the device's match ids. 158 * @return Zero on success, negative error code otherwise. 159 */ 160 static int devman_receive_match_id(match_id_list_t *match_ids) 161 { 162 match_id_t *match_id = create_match_id(); 163 ipc_callid_t callid; 164 ipc_call_t call; 165 int rc = 0; 166 167 callid = async_get_call(&call); 168 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) { 169 log_msg(LVL_ERROR, 170 "Invalid protocol when trying to receive match id."); 171 async_answer_0(callid, EINVAL); 172 delete_match_id(match_id); 173 return EINVAL; 174 } 175 176 if (match_id == NULL) { 177 log_msg(LVL_ERROR, "Failed to allocate match id."); 178 async_answer_0(callid, ENOMEM); 179 return ENOMEM; 180 } 181 182 async_answer_0(callid, EOK); 183 184 match_id->score = IPC_GET_ARG1(call); 185 186 char *match_id_str; 187 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0); 188 match_id->id = match_id_str; 189 if (rc != EOK) { 190 delete_match_id(match_id); 191 log_msg(LVL_ERROR, "Failed to receive match id string: %s.", 192 str_error(rc)); 193 return rc; 194 } 195 196 list_append(&match_id->link, &match_ids->ids); 197 198 log_msg(LVL_DEBUG, "Received match id `%s', score %d.", 199 match_id->id, match_id->score); 200 return rc; 201 } 202 203 /** Receive device match IDs from the device's parent driver and add them to the 204 * list of devices match ids. 205 * 206 * @param match_count The number of device's match ids to be received. 207 * @param match_ids The list of the device's match ids. 208 * @return Zero on success, negative error code otherwise. 209 */ 210 static int devman_receive_match_ids(sysarg_t match_count, 211 match_id_list_t *match_ids) 212 { 213 int ret = EOK; 214 size_t i; 215 216 for (i = 0; i < match_count; i++) { 217 if (EOK != (ret = devman_receive_match_id(match_ids))) 218 return ret; 219 } 220 return ret; 221 } 222 223 static int assign_driver_fibril(void *arg) 224 { 225 dev_node_t *dev_node = (dev_node_t *) arg; 226 assign_driver(dev_node, &drivers_list, &device_tree); 227 return EOK; 228 } 229 230 /** Handle function registration. 231 * 232 * Child devices are registered by their parent's device driver. 233 */ 234 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call) 235 { 236 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call); 237 devman_handle_t dev_handle = IPC_GET_ARG2(*call); 238 sysarg_t match_count = IPC_GET_ARG3(*call); 239 dev_tree_t *tree = &device_tree; 240 241 fibril_rwlock_write_lock(&tree->rwlock); 242 243 dev_node_t *dev = NULL; 244 dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle); 245 246 if (pdev == NULL) { 247 fibril_rwlock_write_unlock(&tree->rwlock); 248 async_answer_0(callid, ENOENT); 249 return; 250 } 251 252 if (ftype != fun_inner && ftype != fun_exposed) { 253 /* Unknown function type */ 254 log_msg(LVL_ERROR, 255 "Unknown function type %d provided by driver.", 256 (int) ftype); 257 258 fibril_rwlock_write_unlock(&tree->rwlock); 259 async_answer_0(callid, EINVAL); 260 return; 261 } 262 263 char *fun_name = NULL; 264 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0); 265 if (rc != EOK) { 266 fibril_rwlock_write_unlock(&tree->rwlock); 267 async_answer_0(callid, rc); 268 return; 269 } 270 271 /* Check that function with same name is not there already. */ 272 if (find_fun_node_in_device(pdev, fun_name) != NULL) { 273 fibril_rwlock_write_unlock(&tree->rwlock); 274 async_answer_0(callid, EEXISTS); 275 printf(NAME ": Warning, driver tried to register `%s' twice.\n", 276 fun_name); 277 free(fun_name); 278 return; 279 } 280 281 fun_node_t *fun = create_fun_node(); 282 fun->ftype = ftype; 283 284 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) { 285 fibril_rwlock_write_unlock(&tree->rwlock); 286 delete_fun_node(fun); 287 async_answer_0(callid, ENOMEM); 288 return; 289 } 290 291 if (ftype == fun_inner) { 292 dev = create_dev_node(); 293 if (dev == NULL) { 294 fibril_rwlock_write_unlock(&tree->rwlock); 295 delete_fun_node(fun); 296 async_answer_0(callid, ENOMEM); 297 return; 298 } 299 300 insert_dev_node(tree, dev, fun); 301 } 302 303 fibril_rwlock_write_unlock(&tree->rwlock); 304 305 log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname); 306 307 devman_receive_match_ids(match_count, &fun->match_ids); 308 309 if (ftype == fun_inner) { 310 assert(dev != NULL); 311 /* 312 * Try to find a suitable driver and assign it to the device. We do 313 * not want to block the current fibril that is used for processing 314 * incoming calls: we will launch a separate fibril to handle the 315 * driver assigning. That is because assign_driver can actually include 316 * task spawning which could take some time. 317 */ 318 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev); 319 if (assign_fibril == 0) { 320 /* 321 * Fallback in case we are out of memory. 322 * Probably not needed as we will die soon anyway ;-). 323 */ 324 (void) assign_driver_fibril(fun); 325 } else { 326 fibril_add_ready(assign_fibril); 327 } 328 } else { 329 loc_register_tree_function(fun, tree); 330 } 331 332 /* Return device handle to parent's driver. */ 333 async_answer_1(callid, EOK, fun->handle); 334 } 335 336 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call) 337 { 338 devman_handle_t handle = IPC_GET_ARG1(*call); 339 category_id_t cat_id; 340 int rc; 341 342 /* Get category name. */ 343 char *cat_name; 344 rc = async_data_write_accept((void **) &cat_name, true, 345 0, 0, 0, 0); 346 if (rc != EOK) { 347 async_answer_0(callid, rc); 348 return; 349 } 350 351 fun_node_t *fun = find_fun_node(&device_tree, handle); 352 if (fun == NULL) { 353 async_answer_0(callid, ENOENT); 354 return; 355 } 356 357 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING); 358 if (rc == EOK) { 359 loc_service_add_to_cat(fun->service_id, cat_id); 360 } else { 361 log_msg(LVL_ERROR, "Failed adding function `%s' to category " 362 "`%s'.", fun->pathname, cat_name); 363 } 364 365 log_msg(LVL_NOTE, "Function `%s' added to category `%s'.", 366 fun->pathname, cat_name); 367 368 async_answer_0(callid, EOK); 369 } 370 371 /** Remove function. */ 372 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call) 373 { 374 devman_handle_t fun_handle = IPC_GET_ARG1(*call); 375 dev_tree_t *tree = &device_tree; 376 int rc; 377 378 fibril_rwlock_write_lock(&tree->rwlock); 379 380 fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle); 381 if (fun == NULL) { 382 fibril_rwlock_write_unlock(&tree->rwlock); 383 async_answer_0(callid, ENOENT); 384 return; 385 } 386 387 log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname); 388 389 if (fun->ftype == fun_inner) { 390 /* Handle possible descendants */ 391 /* TODO */ 392 log_msg(LVL_WARN, "devman_remove_function(): not handling " 393 "descendants\n"); 394 } else { 395 /* Unregister from location service */ 396 rc = loc_service_unregister(fun->service_id); 397 if (rc != EOK) { 398 log_msg(LVL_ERROR, "Failed unregistering tree service."); 399 fibril_rwlock_write_unlock(&tree->rwlock); 400 async_answer_0(callid, EIO); 401 return; 402 } 403 } 404 405 remove_fun_node(&device_tree, fun); 406 fibril_rwlock_write_unlock(&tree->rwlock); 407 delete_fun_node(fun); 408 409 log_msg(LVL_DEBUG, "devman_remove_function() succeeded."); 410 async_answer_0(callid, EOK); 411 } 412 413 /** Initialize driver which has registered itself as running and ready. 414 * 415 * The initialization is done in a separate fibril to avoid deadlocks (if the 416 * driver needed to be served by devman during the driver's initialization). 417 */ 418 static int init_running_drv(void *drv) 419 { 420 driver_t *driver = (driver_t *) drv; 421 422 initialize_running_driver(driver, &device_tree); 423 log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.", 424 driver->name); 425 return 0; 426 } 427 428 /** Function for handling connections from a driver to the device manager. */ 429 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall) 430 { 431 /* Accept the connection. */ 432 async_answer_0(iid, EOK); 433 434 driver_t *driver = devman_driver_register(); 435 if (driver == NULL) 436 return; 141 437 142 438 /* … … 149 445 log_msg(LVL_ERROR, "Failed to create initialization fibril " \ 150 446 "for driver `%s'.", driver->name); 151 fibril_mutex_unlock(&driver->driver_mutex); 152 async_answer_0(callid, ENOMEM); 153 return NULL; 154 } 155 447 return; 448 } 156 449 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 } else {493 log_msg(LVL_ERROR, "Failed adding function `%s' to category "494 "`%s'.", fun->pathname, cat_name);495 }496 497 log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",498 fun->pathname, cat_name);499 500 fibril_rwlock_read_unlock(&device_tree.rwlock);501 fun_del_ref(fun);502 503 async_answer_0(callid, EOK);504 }505 506 /** Online function by driver request.507 *508 */509 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,510 driver_t *drv)511 {512 fun_node_t *fun;513 int rc;514 515 log_msg(LVL_DEBUG, "devman_drv_fun_online()");516 517 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));518 if (fun == NULL) {519 async_answer_0(iid, ENOENT);520 return;521 }522 523 fibril_rwlock_read_lock(&device_tree.rwlock);524 if (fun->dev == NULL || fun->dev->drv != drv) {525 fibril_rwlock_read_unlock(&device_tree.rwlock);526 fun_del_ref(fun);527 async_answer_0(iid, ENOENT);528 return;529 }530 fibril_rwlock_read_unlock(&device_tree.rwlock);531 532 rc = online_function(fun);533 if (rc != EOK) {534 fun_del_ref(fun);535 async_answer_0(iid, (sysarg_t) rc);536 return;537 }538 539 fun_del_ref(fun);540 541 async_answer_0(iid, (sysarg_t) EOK);542 }543 544 545 /** Offline function by driver request.546 *547 */548 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,549 driver_t *drv)550 {551 fun_node_t *fun;552 int rc;553 554 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));555 if (fun == NULL) {556 async_answer_0(iid, ENOENT);557 return;558 }559 560 fibril_rwlock_write_lock(&device_tree.rwlock);561 if (fun->dev == NULL || fun->dev->drv != drv) {562 fun_del_ref(fun);563 async_answer_0(iid, ENOENT);564 return;565 }566 fibril_rwlock_write_unlock(&device_tree.rwlock);567 568 rc = offline_function(fun);569 if (rc != EOK) {570 fun_del_ref(fun);571 async_answer_0(iid, (sysarg_t) rc);572 return;573 }574 575 fun_del_ref(fun);576 async_answer_0(iid, (sysarg_t) EOK);577 }578 579 /** Remove function. */580 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)581 {582 devman_handle_t fun_handle = IPC_GET_ARG1(*call);583 dev_tree_t *tree = &device_tree;584 int rc;585 586 fun_node_t *fun = find_fun_node(&device_tree, fun_handle);587 if (fun == NULL) {588 async_answer_0(callid, ENOENT);589 return;590 }591 592 fibril_rwlock_write_lock(&tree->rwlock);593 594 log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);595 596 /* Check function state */597 if (fun->state == FUN_REMOVED) {598 fibril_rwlock_write_unlock(&tree->rwlock);599 async_answer_0(callid, ENOENT);600 return;601 }602 603 if (fun->ftype == fun_inner) {604 /* This is a surprise removal. Handle possible descendants */605 if (fun->child != NULL) {606 dev_node_t *dev = fun->child;607 device_state_t dev_state;608 int gone_rc;609 610 dev_add_ref(dev);611 dev_state = dev->state;612 613 fibril_rwlock_write_unlock(&device_tree.rwlock);614 615 /* If device is owned by driver, inform driver it is gone. */616 if (dev_state == DEVICE_USABLE)617 gone_rc = driver_dev_gone(&device_tree, dev);618 else619 gone_rc = EOK;620 621 fibril_rwlock_read_lock(&device_tree.rwlock);622 623 /* Verify that driver succeeded and removed all functions */624 if (gone_rc != EOK || !list_empty(&dev->functions)) {625 log_msg(LVL_ERROR, "Driver did not remove "626 "functions for device that is gone. "627 "Device node is now defunct.");628 629 /*630 * Not much we can do but mark the device631 * node as having invalid state. This632 * is a driver bug.633 */634 dev->state = DEVICE_INVALID;635 fibril_rwlock_read_unlock(&device_tree.rwlock);636 dev_del_ref(dev);637 return;638 }639 640 driver_t *driver = dev->drv;641 fibril_rwlock_read_unlock(&device_tree.rwlock);642 643 if (driver)644 detach_driver(&device_tree, dev);645 646 fibril_rwlock_write_lock(&device_tree.rwlock);647 remove_dev_node(&device_tree, dev);648 649 /* Delete ref created when node was inserted */650 dev_del_ref(dev);651 /* Delete ref created by dev_add_ref(dev) above */652 dev_del_ref(dev);653 }654 } else {655 if (fun->service_id != 0) {656 /* Unregister from location service */657 rc = loc_service_unregister(fun->service_id);658 if (rc != EOK) {659 log_msg(LVL_ERROR, "Failed unregistering tree "660 "service.");661 fibril_rwlock_write_unlock(&tree->rwlock);662 fun_del_ref(fun);663 async_answer_0(callid, EIO);664 return;665 }666 }667 }668 669 remove_fun_node(&device_tree, fun);670 fibril_rwlock_write_unlock(&tree->rwlock);671 672 /* Delete ref added when inserting function into tree */673 fun_del_ref(fun);674 /* Delete ref added above when looking up function */675 fun_del_ref(fun);676 677 log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");678 async_answer_0(callid, EOK);679 }680 681 /** Initialize driver which has registered itself as running and ready.682 *683 * The initialization is done in a separate fibril to avoid deadlocks (if the684 * driver needed to be served by devman during the driver's initialization).685 */686 static int init_running_drv(void *drv)687 {688 driver_t *driver = (driver_t *) drv;689 690 initialize_running_driver(driver, &device_tree);691 log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",692 driver->name);693 return 0;694 }695 696 /** Function for handling connections from a driver to the device manager. */697 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)698 {699 client_t *client;700 driver_t *driver;701 702 /* Accept the connection. */703 async_answer_0(iid, EOK);704 705 client = async_get_client_data();706 if (client == NULL) {707 log_msg(LVL_ERROR, "Failed to allocate client data.");708 return;709 }710 450 711 451 while (true) { … … 716 456 break; 717 457 718 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {719 fibril_mutex_lock(&client->mutex);720 driver = client->driver;721 fibril_mutex_unlock(&client->mutex);722 if (driver == NULL) {723 /* First call must be to DEVMAN_DRIVER_REGISTER */724 async_answer_0(callid, ENOTSUP);725 continue;726 }727 }728 729 458 switch (IPC_GET_IMETHOD(call)) { 730 case DEVMAN_DRIVER_REGISTER:731 fibril_mutex_lock(&client->mutex);732 if (client->driver != NULL) {733 fibril_mutex_unlock(&client->mutex);734 async_answer_0(callid, EINVAL);735 continue;736 }737 client->driver = devman_driver_register(callid, &call);738 fibril_mutex_unlock(&client->mutex);739 break;740 459 case DEVMAN_ADD_FUNCTION: 741 460 devman_add_function(callid, &call); … … 744 463 devman_add_function_to_cat(callid, &call); 745 464 break; 746 case DEVMAN_DRV_FUN_ONLINE:747 devman_drv_fun_online(callid, &call, driver);748 break;749 case DEVMAN_DRV_FUN_OFFLINE:750 devman_drv_fun_offline(callid, &call, driver);751 break;752 465 case DEVMAN_REMOVE_FUNCTION: 753 466 devman_remove_function(callid, &call); 754 467 break; 755 468 default: 756 async_answer_0(callid, EINVAL); 469 async_answer_0(callid, EINVAL); 757 470 break; 758 471 } … … 765 478 { 766 479 char *pathname; 767 devman_handle_t handle;768 480 769 481 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0); … … 782 494 } 783 495 784 fibril_rwlock_read_lock(&device_tree.rwlock); 785 786 /* Check function state */ 787 if (fun->state == FUN_REMOVED) { 788 fibril_rwlock_read_unlock(&device_tree.rwlock); 789 async_answer_0(iid, ENOENT); 790 return; 791 } 792 handle = fun->handle; 793 794 fibril_rwlock_read_unlock(&device_tree.rwlock); 795 796 /* Delete reference created above by find_fun_node_by_path() */ 797 fun_del_ref(fun); 798 799 async_answer_1(iid, EOK, handle); 496 async_answer_1(iid, EOK, fun->handle); 800 497 } 801 498 … … 815 512 if (!async_data_read_receive(&data_callid, &data_len)) { 816 513 async_answer_0(iid, EINVAL); 817 fun_del_ref(fun);818 514 return; 819 515 } … … 823 519 async_answer_0(data_callid, ENOMEM); 824 520 async_answer_0(iid, ENOMEM); 825 fun_del_ref(fun);826 return;827 }828 829 fibril_rwlock_read_lock(&device_tree.rwlock);830 831 /* Check function state */832 if (fun->state == FUN_REMOVED) {833 fibril_rwlock_read_unlock(&device_tree.rwlock);834 free(buffer);835 836 async_answer_0(data_callid, ENOENT);837 async_answer_0(iid, ENOENT);838 fun_del_ref(fun);839 521 return; 840 522 } … … 848 530 async_answer_0(iid, EOK); 849 531 850 fibril_rwlock_read_unlock(&device_tree.rwlock);851 fun_del_ref(fun);852 532 free(buffer); 853 533 } … … 869 549 if (!async_data_read_receive(&data_callid, &data_len)) { 870 550 async_answer_0(iid, EINVAL); 871 fun_del_ref(fun);872 551 return; 873 552 } … … 877 556 async_answer_0(data_callid, ENOMEM); 878 557 async_answer_0(iid, ENOMEM); 879 fun_del_ref(fun); 880 return; 881 } 882 883 fibril_rwlock_read_lock(&device_tree.rwlock); 884 885 /* Check function state */ 886 if (fun->state == FUN_REMOVED) { 887 fibril_rwlock_read_unlock(&device_tree.rwlock); 888 free(buffer); 889 890 async_answer_0(data_callid, ENOENT); 891 async_answer_0(iid, ENOENT); 892 fun_del_ref(fun); 893 return; 894 } 895 558 return; 559 } 560 896 561 size_t sent_length = str_size(fun->pathname); 897 562 if (sent_length > data_len) { … … 902 567 async_answer_0(iid, EOK); 903 568 904 fibril_rwlock_read_unlock(&device_tree.rwlock);905 fun_del_ref(fun);906 569 free(buffer); 907 570 } … … 924 587 dev_node_t *dev = find_dev_node_no_lock(&device_tree, 925 588 IPC_GET_ARG1(*icall)); 926 if (dev == NULL || dev->state == DEVICE_REMOVED) {589 if (dev == NULL) { 927 590 fibril_rwlock_read_unlock(&device_tree.rwlock); 928 591 async_answer_0(callid, ENOENT); … … 963 626 fibril_rwlock_read_lock(&device_tree.rwlock); 964 627 965 fun = find_fun_node _no_lock(&device_tree, IPC_GET_ARG1(*icall));966 if (fun == NULL || fun->state == FUN_REMOVED) {628 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall)); 629 if (fun == NULL) { 967 630 fibril_rwlock_read_unlock(&device_tree.rwlock); 968 631 async_answer_0(iid, ENOENT); … … 981 644 } 982 645 983 /** Online function.984 *985 * Send a request to online a function to the responsible driver.986 * The driver may offline other functions if necessary (i.e. if the state987 * of this function is linked to state of another function somehow).988 */989 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)990 {991 fun_node_t *fun;992 int rc;993 994 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));995 if (fun == NULL) {996 async_answer_0(iid, ENOENT);997 return;998 }999 1000 rc = driver_fun_online(&device_tree, fun);1001 fun_del_ref(fun);1002 1003 async_answer_0(iid, (sysarg_t) rc);1004 }1005 1006 /** Offline function.1007 *1008 * Send a request to offline a function to the responsible driver. As1009 * a result the subtree rooted at that function should be cleanly1010 * detatched. The driver may offline other functions if necessary1011 * (i.e. if the state of this function is linked to state of another1012 * function somehow).1013 */1014 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)1015 {1016 fun_node_t *fun;1017 int rc;1018 1019 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));1020 if (fun == NULL) {1021 async_answer_0(iid, ENOENT);1022 return;1023 }1024 1025 rc = driver_fun_offline(&device_tree, fun);1026 fun_del_ref(fun);1027 1028 async_answer_0(iid, (sysarg_t) rc);1029 }1030 1031 646 /** Find handle for the function instance identified by its service ID. */ 1032 647 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall) … … 1041 656 } 1042 657 1043 fibril_rwlock_read_lock(&device_tree.rwlock);1044 1045 /* Check function state */1046 if (fun->state == FUN_REMOVED) {1047 fibril_rwlock_read_unlock(&device_tree.rwlock);1048 async_answer_0(iid, ENOENT);1049 return;1050 }1051 1052 658 async_answer_1(iid, EOK, fun->handle); 1053 fibril_rwlock_read_unlock(&device_tree.rwlock);1054 fun_del_ref(fun);1055 659 } 1056 660 … … 1084 688 devman_fun_get_path(callid, &call); 1085 689 break; 1086 case DEVMAN_FUN_ONLINE:1087 devman_fun_online(callid, &call);1088 break;1089 case DEVMAN_FUN_OFFLINE:1090 devman_fun_offline(callid, &call);1091 break;1092 690 case DEVMAN_FUN_SID_TO_HANDLE: 1093 691 devman_fun_sid_to_handle(callid, &call); … … 1110 708 if (fun == NULL) 1111 709 dev = find_dev_node(&device_tree, handle); 1112 else { 1113 fibril_rwlock_read_lock(&device_tree.rwlock); 710 else 1114 711 dev = fun->dev; 1115 if (dev != NULL)1116 dev_add_ref(dev);1117 fibril_rwlock_read_unlock(&device_tree.rwlock);1118 }1119 712 1120 713 /* … … 1128 721 "function with handle %" PRIun " was found.", handle); 1129 722 async_answer_0(iid, ENOENT); 1130 goto cleanup;723 return; 1131 724 } 1132 725 … … 1136 729 handle); 1137 730 async_answer_0(iid, ENOENT); 1138 goto cleanup;731 return; 1139 732 } 1140 733 1141 734 driver_t *driver = NULL; 1142 1143 fibril_rwlock_read_lock(&device_tree.rwlock);1144 735 1145 736 if (drv_to_parent) { … … 1156 747 } 1157 748 1158 fibril_rwlock_read_unlock(&device_tree.rwlock);1159 1160 749 if (driver == NULL) { 1161 750 log_msg(LVL_ERROR, "IPC forwarding refused - " \ 1162 751 "the device %" PRIun " is not in usable state.", handle); 1163 752 async_answer_0(iid, ENOENT); 1164 goto cleanup;753 return; 1165 754 } 1166 755 … … 1175 764 "Could not forward to driver `%s'.", driver->name); 1176 765 async_answer_0(iid, EINVAL); 1177 goto cleanup;766 return; 1178 767 } 1179 768 … … 1191 780 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE); 1192 781 async_exchange_end(exch); 1193 1194 cleanup:1195 if (dev != NULL)1196 dev_del_ref(dev);1197 if (fun != NULL)1198 fun_del_ref(fun);1199 782 } 1200 783 … … 1206 789 fun_node_t *fun; 1207 790 dev_node_t *dev; 1208 devman_handle_t handle;1209 driver_t *driver;1210 791 1211 792 fun = find_loc_tree_function(&device_tree, service_id); 1212 793 1213 fibril_rwlock_read_lock(&device_tree.rwlock); 1214 1215 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) { 794 if (fun == NULL || fun->dev->drv == NULL) { 1216 795 log_msg(LVL_WARN, "devman_connection_loc(): function " 1217 796 "not found.\n"); 1218 fibril_rwlock_read_unlock(&device_tree.rwlock);1219 797 async_answer_0(iid, ENOENT); 1220 798 return; … … 1222 800 1223 801 dev = fun->dev; 1224 driver = dev->drv; 1225 handle = fun->handle; 1226 1227 fibril_rwlock_read_unlock(&device_tree.rwlock); 1228 1229 async_exch_t *exch = async_exchange_begin(driver->sess); 1230 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0, 802 803 async_exch_t *exch = async_exchange_begin(dev->drv->sess); 804 async_forward_fast(iid, exch, DRIVER_CLIENT, fun->handle, 0, 1231 805 IPC_FF_NONE); 1232 806 async_exchange_end(exch); … … 1234 808 log_msg(LVL_DEBUG, 1235 809 "Forwarding loc service request for `%s' function to driver `%s'.", 1236 fun->pathname, driver->name); 1237 1238 fun_del_ref(fun); 810 fun->pathname, dev->drv->name); 1239 811 } 1240 812 … … 1242 814 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) 1243 815 { 1244 /* Select port. */816 /* Select interface. */ 1245 817 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) { 1246 818 case DEVMAN_DRIVER: … … 1268 840 } 1269 841 1270 static void *devman_client_data_create(void)1271 {1272 client_t *client;1273 1274 client = calloc(1, sizeof(client_t));1275 if (client == NULL)1276 return NULL;1277 1278 fibril_mutex_initialize(&client->mutex);1279 return client;1280 }1281 1282 static void devman_client_data_destroy(void *data)1283 {1284 free(data);1285 }1286 1287 842 /** Initialize device manager internal structures. */ 1288 843 static bool devman_init(void) … … 1331 886 } 1332 887 1333 /* Set handlers for incoming connections. */ 1334 async_set_client_data_constructor(devman_client_data_create); 1335 async_set_client_data_destructor(devman_client_data_destroy); 888 /* Set a handler of incomming connections. */ 1336 889 async_set_client_connection(devman_connection); 1337 890
Note:
See TracChangeset
for help on using the changeset viewer.
