00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038 #include <macros.h>
00039 #include <bool.h>
00040 #include <errno.h>
00041 #include <malloc.h>
00042 #include <str.h>
00043 #include <libfs.h>
00044 #include <fibril_synch.h>
00045 #include <adt/hash_table.h>
00046 #include <ipc/devmap.h>
00047 #include <sys/stat.h>
00048 #include <libfs.h>
00049 #include <assert.h>
00050 #include "devfs.h"
00051 #include "devfs_ops.h"
00052
00053 typedef struct {
00054 devmap_handle_type_t type;
00055 devmap_handle_t handle;
00056 } devfs_node_t;
00057
00059 typedef struct {
00060 devmap_handle_t handle;
00061 int phone;
00062 size_t refcount;
00063 link_t link;
00064 fibril_condvar_t cv;
00065 } device_t;
00066
00068 static hash_table_t devices;
00069
00071 static FIBRIL_MUTEX_INITIALIZE(devices_mutex);
00072
00073 #define DEVICES_KEYS 1
00074 #define DEVICES_KEY_HANDLE 0
00075 #define DEVICES_BUCKETS 256
00076
00077
00078 static hash_index_t devices_hash(unsigned long key[])
00079 {
00080 return key[DEVICES_KEY_HANDLE] % DEVICES_BUCKETS;
00081 }
00082
00083 static int devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
00084 {
00085 device_t *dev = hash_table_get_instance(item, device_t, link);
00086 return (dev->handle == (devmap_handle_t) key[DEVICES_KEY_HANDLE]);
00087 }
00088
00089 static void devices_remove_callback(link_t *item)
00090 {
00091 free(hash_table_get_instance(item, device_t, link));
00092 }
00093
00094 static hash_table_operations_t devices_ops = {
00095 .hash = devices_hash,
00096 .compare = devices_compare,
00097 .remove_callback = devices_remove_callback
00098 };
00099
00100 static int devfs_node_get_internal(fs_node_t **rfn, devmap_handle_type_t type,
00101 devmap_handle_t handle)
00102 {
00103 devfs_node_t *node = (devfs_node_t *) malloc(sizeof(devfs_node_t));
00104 if (node == NULL) {
00105 *rfn = NULL;
00106 return ENOMEM;
00107 }
00108
00109 *rfn = (fs_node_t *) malloc(sizeof(fs_node_t));
00110 if (*rfn == NULL) {
00111 free(node);
00112 *rfn = NULL;
00113 return ENOMEM;
00114 }
00115
00116 fs_node_initialize(*rfn);
00117 node->type = type;
00118 node->handle = handle;
00119
00120 (*rfn)->data = node;
00121 return EOK;
00122 }
00123
00124 static int devfs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
00125 {
00126 return devfs_node_get_internal(rfn, DEV_HANDLE_NONE, 0);
00127 }
00128
00129 static int devfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
00130 {
00131 devfs_node_t *node = (devfs_node_t *) pfn->data;
00132 int ret;
00133
00134 if (node->handle == 0) {
00135
00136
00137 dev_desc_t *devs;
00138 size_t count = devmap_get_namespaces(&devs);
00139
00140 if (count > 0) {
00141 size_t pos;
00142 for (pos = 0; pos < count; pos++) {
00143
00144 if (str_cmp(devs[pos].name, "") == 0)
00145 continue;
00146
00147 if (str_cmp(devs[pos].name, component) == 0) {
00148 ret = devfs_node_get_internal(rfn, DEV_HANDLE_NAMESPACE, devs[pos].handle);
00149 free(devs);
00150 return ret;
00151 }
00152 }
00153
00154 free(devs);
00155 }
00156
00157
00158 devmap_handle_t namespace;
00159 if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
00160 count = devmap_get_devices(namespace, &devs);
00161
00162 if (count > 0) {
00163 size_t pos;
00164 for (pos = 0; pos < count; pos++) {
00165 if (str_cmp(devs[pos].name, component) == 0) {
00166 ret = devfs_node_get_internal(rfn, DEV_HANDLE_DEVICE, devs[pos].handle);
00167 free(devs);
00168 return ret;
00169 }
00170 }
00171
00172 free(devs);
00173 }
00174 }
00175
00176 *rfn = NULL;
00177 return EOK;
00178 }
00179
00180 if (node->type == DEV_HANDLE_NAMESPACE) {
00181
00182
00183 dev_desc_t *devs;
00184 size_t count = devmap_get_devices(node->handle, &devs);
00185 if (count > 0) {
00186 size_t pos;
00187 for (pos = 0; pos < count; pos++) {
00188 if (str_cmp(devs[pos].name, component) == 0) {
00189 ret = devfs_node_get_internal(rfn, DEV_HANDLE_DEVICE, devs[pos].handle);
00190 free(devs);
00191 return ret;
00192 }
00193 }
00194
00195 free(devs);
00196 }
00197
00198 *rfn = NULL;
00199 return EOK;
00200 }
00201
00202 *rfn = NULL;
00203 return EOK;
00204 }
00205
00206 static int devfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
00207 {
00208 return devfs_node_get_internal(rfn, devmap_handle_probe(index), index);
00209 }
00210
00211 static int devfs_node_open(fs_node_t *fn)
00212 {
00213 devfs_node_t *node = (devfs_node_t *) fn->data;
00214
00215 if (node->handle == 0) {
00216
00217 return EOK;
00218 }
00219
00220 devmap_handle_type_t type = devmap_handle_probe(node->handle);
00221
00222 if (type == DEV_HANDLE_NAMESPACE) {
00223
00224 return EOK;
00225 }
00226
00227 if (type == DEV_HANDLE_DEVICE) {
00228
00229
00230 unsigned long key[] = {
00231 [DEVICES_KEY_HANDLE] = (unsigned long) node->handle
00232 };
00233 link_t *lnk;
00234
00235 fibril_mutex_lock(&devices_mutex);
00236 restart:
00237 lnk = hash_table_find(&devices, key);
00238 if (lnk == NULL) {
00239 device_t *dev = (device_t *) malloc(sizeof(device_t));
00240 if (dev == NULL) {
00241 fibril_mutex_unlock(&devices_mutex);
00242 return ENOMEM;
00243 }
00244
00245 dev->handle = node->handle;
00246 dev->phone = -1;
00247 dev->refcount = 1;
00248 fibril_condvar_initialize(&dev->cv);
00249
00250
00251
00252
00253
00254
00255 hash_table_insert(&devices, key, &dev->link);
00256
00257
00258
00259
00260 fibril_mutex_unlock(&devices_mutex);
00261
00262 int phone = devmap_device_connect(node->handle, 0);
00263
00264 fibril_mutex_lock(&devices_mutex);
00265
00266
00267
00268
00269
00270 fibril_condvar_broadcast(&dev->cv);
00271
00272 if (phone < 0) {
00273
00274
00275
00276
00277 hash_table_remove(&devices, key, DEVICES_KEYS);
00278 fibril_mutex_unlock(&devices_mutex);
00279
00280 return ENOENT;
00281 }
00282
00283
00284 dev->phone = phone;
00285 } else {
00286 device_t *dev = hash_table_get_instance(lnk, device_t, link);
00287
00288 if (dev->phone < 0) {
00289
00290
00291
00292
00293
00294
00295
00296 fibril_condvar_wait(&dev->cv, &devices_mutex);
00297 goto restart;
00298 }
00299
00300 dev->refcount++;
00301 }
00302
00303 fibril_mutex_unlock(&devices_mutex);
00304
00305 return EOK;
00306 }
00307
00308 return ENOENT;
00309 }
00310
00311 static int devfs_node_put(fs_node_t *fn)
00312 {
00313 free(fn->data);
00314 free(fn);
00315 return EOK;
00316 }
00317
00318 static int devfs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
00319 {
00320 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
00321
00322 *rfn = NULL;
00323 return ENOTSUP;
00324 }
00325
00326 static int devfs_destroy_node(fs_node_t *fn)
00327 {
00328 return ENOTSUP;
00329 }
00330
00331 static int devfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00332 {
00333 return ENOTSUP;
00334 }
00335
00336 static int devfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00337 {
00338 return ENOTSUP;
00339 }
00340
00341 static int devfs_has_children(bool *has_children, fs_node_t *fn)
00342 {
00343 devfs_node_t *node = (devfs_node_t *) fn->data;
00344
00345 if (node->handle == 0) {
00346 size_t count = devmap_count_namespaces();
00347 if (count > 0) {
00348 *has_children = true;
00349 return EOK;
00350 }
00351
00352
00353 devmap_handle_t namespace;
00354 if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
00355 count = devmap_count_devices(namespace);
00356 if (count > 0) {
00357 *has_children = true;
00358 return EOK;
00359 }
00360 }
00361
00362 *has_children = false;
00363 return EOK;
00364 }
00365
00366 if (node->type == DEV_HANDLE_NAMESPACE) {
00367 size_t count = devmap_count_devices(node->handle);
00368 if (count > 0) {
00369 *has_children = true;
00370 return EOK;
00371 }
00372
00373 *has_children = false;
00374 return EOK;
00375 }
00376
00377 *has_children = false;
00378 return EOK;
00379 }
00380
00381 static fs_index_t devfs_index_get(fs_node_t *fn)
00382 {
00383 devfs_node_t *node = (devfs_node_t *) fn->data;
00384 return node->handle;
00385 }
00386
00387 static aoff64_t devfs_size_get(fs_node_t *fn)
00388 {
00389 return 0;
00390 }
00391
00392 static unsigned int devfs_lnkcnt_get(fs_node_t *fn)
00393 {
00394 devfs_node_t *node = (devfs_node_t *) fn->data;
00395
00396 if (node->handle == 0)
00397 return 0;
00398
00399 return 1;
00400 }
00401
00402 static char devfs_plb_get_char(unsigned pos)
00403 {
00404 return devfs_reg.plb_ro[pos % PLB_SIZE];
00405 }
00406
00407 static bool devfs_is_directory(fs_node_t *fn)
00408 {
00409 devfs_node_t *node = (devfs_node_t *) fn->data;
00410
00411 return ((node->type == DEV_HANDLE_NONE) || (node->type == DEV_HANDLE_NAMESPACE));
00412 }
00413
00414 static bool devfs_is_file(fs_node_t *fn)
00415 {
00416 devfs_node_t *node = (devfs_node_t *) fn->data;
00417
00418 return (node->type == DEV_HANDLE_DEVICE);
00419 }
00420
00421 static devmap_handle_t devfs_device_get(fs_node_t *fn)
00422 {
00423 devfs_node_t *node = (devfs_node_t *) fn->data;
00424
00425 if (node->type == DEV_HANDLE_DEVICE)
00426 return node->handle;
00427
00428 return 0;
00429 }
00430
00432 libfs_ops_t devfs_libfs_ops = {
00433 .root_get = devfs_root_get,
00434 .match = devfs_match,
00435 .node_get = devfs_node_get,
00436 .node_open = devfs_node_open,
00437 .node_put = devfs_node_put,
00438 .create = devfs_create_node,
00439 .destroy = devfs_destroy_node,
00440 .link = devfs_link_node,
00441 .unlink = devfs_unlink_node,
00442 .has_children = devfs_has_children,
00443 .index_get = devfs_index_get,
00444 .size_get = devfs_size_get,
00445 .lnkcnt_get = devfs_lnkcnt_get,
00446 .plb_get_char = devfs_plb_get_char,
00447 .is_directory = devfs_is_directory,
00448 .is_file = devfs_is_file,
00449 .device_get = devfs_device_get
00450 };
00451
00452 bool devfs_init(void)
00453 {
00454 if (!hash_table_create(&devices, DEVICES_BUCKETS,
00455 DEVICES_KEYS, &devices_ops))
00456 return false;
00457
00458 return true;
00459 }
00460
00461 void devfs_mounted(ipc_callid_t rid, ipc_call_t *request)
00462 {
00463 char *opts;
00464
00465
00466 sysarg_t retval = async_data_write_accept((void **) &opts, true, 0, 0,
00467 0, NULL);
00468 if (retval != EOK) {
00469 async_answer_0(rid, retval);
00470 return;
00471 }
00472
00473 free(opts);
00474 async_answer_3(rid, EOK, 0, 0, 0);
00475 }
00476
00477 void devfs_mount(ipc_callid_t rid, ipc_call_t *request)
00478 {
00479 libfs_mount(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
00480 }
00481
00482 void devfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
00483 {
00484 async_answer_0(rid, ENOTSUP);
00485 }
00486
00487 void devfs_unmount(ipc_callid_t rid, ipc_call_t *request)
00488 {
00489 libfs_unmount(&devfs_libfs_ops, rid, request);
00490 }
00491
00492 void devfs_lookup(ipc_callid_t rid, ipc_call_t *request)
00493 {
00494 libfs_lookup(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
00495 }
00496
00497 void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
00498 {
00499 libfs_open_node(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
00500 }
00501
00502 void devfs_stat(ipc_callid_t rid, ipc_call_t *request)
00503 {
00504 libfs_stat(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
00505 }
00506
00507 void devfs_read(ipc_callid_t rid, ipc_call_t *request)
00508 {
00509 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00510 aoff64_t pos =
00511 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00512
00513 if (index == 0) {
00514 ipc_callid_t callid;
00515 size_t size;
00516 if (!async_data_read_receive(&callid, &size)) {
00517 async_answer_0(callid, EINVAL);
00518 async_answer_0(rid, EINVAL);
00519 return;
00520 }
00521
00522 dev_desc_t *desc;
00523 size_t count = devmap_get_namespaces(&desc);
00524
00525
00526 size_t i;
00527 for (i = 0; i < count; i++) {
00528 if (str_cmp(desc[i].name, "") == 0) {
00529 if (pos >= i)
00530 pos++;
00531
00532 break;
00533 }
00534 }
00535
00536 if (pos < count) {
00537 async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
00538 free(desc);
00539 async_answer_1(rid, EOK, 1);
00540 return;
00541 }
00542
00543 free(desc);
00544 pos -= count;
00545
00546
00547 devmap_handle_t namespace;
00548 if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
00549 count = devmap_get_devices(namespace, &desc);
00550
00551 if (pos < count) {
00552 async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
00553 free(desc);
00554 async_answer_1(rid, EOK, 1);
00555 return;
00556 }
00557
00558 free(desc);
00559 }
00560
00561 async_answer_0(callid, ENOENT);
00562 async_answer_1(rid, ENOENT, 0);
00563 return;
00564 }
00565
00566 devmap_handle_type_t type = devmap_handle_probe(index);
00567
00568 if (type == DEV_HANDLE_NAMESPACE) {
00569
00570 ipc_callid_t callid;
00571 size_t size;
00572 if (!async_data_read_receive(&callid, &size)) {
00573 async_answer_0(callid, EINVAL);
00574 async_answer_0(rid, EINVAL);
00575 return;
00576 }
00577
00578 dev_desc_t *desc;
00579 size_t count = devmap_get_devices(index, &desc);
00580
00581 if (pos < count) {
00582 async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
00583 free(desc);
00584 async_answer_1(rid, EOK, 1);
00585 return;
00586 }
00587
00588 free(desc);
00589 async_answer_0(callid, ENOENT);
00590 async_answer_1(rid, ENOENT, 0);
00591 return;
00592 }
00593
00594 if (type == DEV_HANDLE_DEVICE) {
00595
00596
00597 unsigned long key[] = {
00598 [DEVICES_KEY_HANDLE] = (unsigned long) index
00599 };
00600
00601 fibril_mutex_lock(&devices_mutex);
00602 link_t *lnk = hash_table_find(&devices, key);
00603 if (lnk == NULL) {
00604 fibril_mutex_unlock(&devices_mutex);
00605 async_answer_0(rid, ENOENT);
00606 return;
00607 }
00608
00609 device_t *dev = hash_table_get_instance(lnk, device_t, link);
00610 assert(dev->phone >= 0);
00611
00612 ipc_callid_t callid;
00613 if (!async_data_read_receive(&callid, NULL)) {
00614 fibril_mutex_unlock(&devices_mutex);
00615 async_answer_0(callid, EINVAL);
00616 async_answer_0(rid, EINVAL);
00617 return;
00618 }
00619
00620
00621 ipc_call_t answer;
00622 aid_t msg = async_send_3(dev->phone, IPC_GET_IMETHOD(*request),
00623 IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
00624 IPC_GET_ARG3(*request), &answer);
00625
00626
00627 async_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
00628 fibril_mutex_unlock(&devices_mutex);
00629
00630
00631 sysarg_t rc;
00632 async_wait_for(msg, &rc);
00633 size_t bytes = IPC_GET_ARG1(answer);
00634
00635
00636 async_answer_1(rid, rc, bytes);
00637 return;
00638 }
00639
00640 async_answer_0(rid, ENOENT);
00641 }
00642
00643 void devfs_write(ipc_callid_t rid, ipc_call_t *request)
00644 {
00645 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00646 if (index == 0) {
00647 async_answer_0(rid, ENOTSUP);
00648 return;
00649 }
00650
00651 devmap_handle_type_t type = devmap_handle_probe(index);
00652
00653 if (type == DEV_HANDLE_NAMESPACE) {
00654
00655 async_answer_0(rid, ENOTSUP);
00656 return;
00657 }
00658
00659 if (type == DEV_HANDLE_DEVICE) {
00660
00661 unsigned long key[] = {
00662 [DEVICES_KEY_HANDLE] = (unsigned long) index
00663 };
00664
00665 fibril_mutex_lock(&devices_mutex);
00666 link_t *lnk = hash_table_find(&devices, key);
00667 if (lnk == NULL) {
00668 fibril_mutex_unlock(&devices_mutex);
00669 async_answer_0(rid, ENOENT);
00670 return;
00671 }
00672
00673 device_t *dev = hash_table_get_instance(lnk, device_t, link);
00674 assert(dev->phone >= 0);
00675
00676 ipc_callid_t callid;
00677 if (!async_data_write_receive(&callid, NULL)) {
00678 fibril_mutex_unlock(&devices_mutex);
00679 async_answer_0(callid, EINVAL);
00680 async_answer_0(rid, EINVAL);
00681 return;
00682 }
00683
00684
00685 ipc_call_t answer;
00686 aid_t msg = async_send_3(dev->phone, IPC_GET_IMETHOD(*request),
00687 IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
00688 IPC_GET_ARG3(*request), &answer);
00689
00690
00691 async_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
00692
00693 fibril_mutex_unlock(&devices_mutex);
00694
00695
00696 sysarg_t rc;
00697 async_wait_for(msg, &rc);
00698 size_t bytes = IPC_GET_ARG1(answer);
00699
00700
00701 async_answer_1(rid, rc, bytes);
00702 return;
00703 }
00704
00705 async_answer_0(rid, ENOENT);
00706 }
00707
00708 void devfs_truncate(ipc_callid_t rid, ipc_call_t *request)
00709 {
00710 async_answer_0(rid, ENOTSUP);
00711 }
00712
00713 void devfs_close(ipc_callid_t rid, ipc_call_t *request)
00714 {
00715 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00716
00717 if (index == 0) {
00718 async_answer_0(rid, EOK);
00719 return;
00720 }
00721
00722 devmap_handle_type_t type = devmap_handle_probe(index);
00723
00724 if (type == DEV_HANDLE_NAMESPACE) {
00725
00726 async_answer_0(rid, EOK);
00727 return;
00728 }
00729
00730 if (type == DEV_HANDLE_DEVICE) {
00731 unsigned long key[] = {
00732 [DEVICES_KEY_HANDLE] = (unsigned long) index
00733 };
00734
00735 fibril_mutex_lock(&devices_mutex);
00736 link_t *lnk = hash_table_find(&devices, key);
00737 if (lnk == NULL) {
00738 fibril_mutex_unlock(&devices_mutex);
00739 async_answer_0(rid, ENOENT);
00740 return;
00741 }
00742
00743 device_t *dev = hash_table_get_instance(lnk, device_t, link);
00744 assert(dev->phone >= 0);
00745 dev->refcount--;
00746
00747 if (dev->refcount == 0) {
00748 async_hangup(dev->phone);
00749 hash_table_remove(&devices, key, DEVICES_KEYS);
00750 }
00751
00752 fibril_mutex_unlock(&devices_mutex);
00753
00754 async_answer_0(rid, EOK);
00755 return;
00756 }
00757
00758 async_answer_0(rid, ENOENT);
00759 }
00760
00761 void devfs_sync(ipc_callid_t rid, ipc_call_t *request)
00762 {
00763 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00764
00765 if (index == 0) {
00766 async_answer_0(rid, EOK);
00767 return;
00768 }
00769
00770 devmap_handle_type_t type = devmap_handle_probe(index);
00771
00772 if (type == DEV_HANDLE_NAMESPACE) {
00773
00774 async_answer_0(rid, EOK);
00775 return;
00776 }
00777
00778 if (type == DEV_HANDLE_DEVICE) {
00779 unsigned long key[] = {
00780 [DEVICES_KEY_HANDLE] = (unsigned long) index
00781 };
00782
00783 fibril_mutex_lock(&devices_mutex);
00784 link_t *lnk = hash_table_find(&devices, key);
00785 if (lnk == NULL) {
00786 fibril_mutex_unlock(&devices_mutex);
00787 async_answer_0(rid, ENOENT);
00788 return;
00789 }
00790
00791 device_t *dev = hash_table_get_instance(lnk, device_t, link);
00792 assert(dev->phone >= 0);
00793
00794
00795 ipc_call_t answer;
00796 aid_t msg = async_send_2(dev->phone, IPC_GET_IMETHOD(*request),
00797 IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
00798
00799 fibril_mutex_unlock(&devices_mutex);
00800
00801
00802 sysarg_t rc;
00803 async_wait_for(msg, &rc);
00804
00805
00806 async_answer_0(rid, rc);
00807 return;
00808 }
00809
00810 async_answer_0(rid, ENOENT);
00811 }
00812
00813 void devfs_destroy(ipc_callid_t rid, ipc_call_t *request)
00814 {
00815 async_answer_0(rid, ENOTSUP);
00816 }
00817