Index: uspace/srv/fs/devfs/devfs.c
===================================================================
--- uspace/srv/fs/devfs/devfs.c	(revision a095d202b1caf823b2b66c86fe55c5a3b8bdd306)
+++ uspace/srv/fs/devfs/devfs.c	(revision 9db9b10d117f0270316d82b7abfc8c4114e2b00d)
@@ -29,5 +29,5 @@
 /** @addtogroup fs
  * @{
- */ 
+ */
 
 /**
@@ -75,4 +75,10 @@
 			devfs_lookup(callid, &call);
 			break;
+		case VFS_OPEN_NODE:
+			devfs_open_node(callid, &call);
+			break;
+		case VFS_DEVICE:
+			devfs_device(callid, &call);
+			break;
 		case VFS_READ:
 			devfs_read(callid, &call);
@@ -83,4 +89,10 @@
 		case VFS_TRUNCATE:
 			devfs_truncate(callid, &call);
+			break;
+		case VFS_CLOSE:
+			devfs_close(callid, &call);
+			break;
+		case VFS_SYNC:
+			devfs_sync(callid, &call);
 			break;
 		case VFS_DESTROY:
@@ -123,5 +135,5 @@
 }
 
-/** 
+/**
  * @}
  */
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision a095d202b1caf823b2b66c86fe55c5a3b8bdd306)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 9db9b10d117f0270316d82b7abfc8c4114e2b00d)
@@ -42,4 +42,5 @@
 #include <string.h>
 #include <libfs.h>
+#include <libadt/hash_table.h>
 #include "devfs.h"
 #include "devfs_ops.h"
@@ -47,6 +48,48 @@
 #define PLB_GET_CHAR(pos)  (devfs_reg.plb_ro[pos % PLB_SIZE])
 
+/** Opened devices structure */
+typedef struct {
+	dev_handle_t handle;
+	int phone;
+	size_t refcount;
+	link_t link;
+} device_t;
+
+/** Hash table of opened devices */
+static hash_table_t devices;
+
+#define DEVICES_KEYS        1
+#define DEVICES_KEY_HANDLE  0
+#define DEVICES_BUCKETS     256
+
+/* Implementation of hash table interface for the nodes hash table. */
+static hash_index_t devices_hash(unsigned long key[])
+{
+	return key[DEVICES_KEY_HANDLE] % DEVICES_BUCKETS;
+}
+
+static int devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	device_t *dev = hash_table_get_instance(item, device_t, link);
+	return (dev->handle == (dev_handle_t) key[DEVICES_KEY_HANDLE]);
+}
+
+static void devices_remove_callback(link_t *item)
+{
+	free(hash_table_get_instance(item, device_t, link));
+}
+
+static hash_table_operations_t devices_ops = {
+	.hash = devices_hash,
+	.compare = devices_compare,
+	.remove_callback = devices_remove_callback
+};
+
 bool devfs_init(void)
 {
+	if (!hash_table_create(&devices, DEVICES_BUCKETS,
+	    DEVICES_KEYS, &devices_ops))
+		return false;
+	
 	if (devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING) < 0)
 		return false;
@@ -104,6 +147,5 @@
 	}
 	
-	/* This is a read-only filesystem */
-	if ((lflag & L_CREATE) || (lflag & L_LINK) || (lflag & L_UNLINK)) {
+	if ((lflag & L_LINK) || (lflag & L_UNLINK)) {
 		ipc_answer_0(rid, ENOTSUP);
 		return;
@@ -124,5 +166,5 @@
 	} else {
 		if (lflag & L_FILE) {
-			count_t len;
+			size_t len;
 			if (last >= first)
 				len = last - first + 1;
@@ -136,5 +178,5 @@
 			}
 			
-			count_t i;
+			size_t i;
 			for (i = 0; i < len; i++)
 				name[i] = PLB_GET_CHAR(first + i);
@@ -149,4 +191,36 @@
 			}
 			
+			if (lflag & L_OPEN) {
+				unsigned long key[] = {
+					[DEVICES_KEY_HANDLE] = (unsigned long) handle
+				};
+				
+				link_t *lnk = hash_table_find(&devices, key);
+				if (lnk == NULL) {
+					int phone = devmap_device_connect(handle, 0);
+					if (phone < 0) {
+						free(name);
+						ipc_answer_0(rid, ENOENT);
+						return;
+					}
+					
+					device_t *dev = (device_t *) malloc(sizeof(device_t));
+					if (dev == NULL) {
+						free(name);
+						ipc_answer_0(rid, ENOMEM);
+						return;
+					}
+					
+					dev->handle = handle;
+					dev->phone = phone;
+					dev->refcount = 1;
+					
+					hash_table_insert(&devices, key, &dev->link);
+				} else {
+					device_t *dev = hash_table_get_instance(lnk, device_t, link);
+					dev->refcount++;
+				}
+			}
+			
 			free(name);
 			
@@ -157,4 +231,59 @@
 }
 
+void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	dev_handle_t handle = IPC_GET_ARG2(*request);
+	
+	unsigned long key[] = {
+		[DEVICES_KEY_HANDLE] = (unsigned long) handle
+	};
+	
+	link_t *lnk = hash_table_find(&devices, key);
+	if (lnk == NULL) {
+		int phone = devmap_device_connect(handle, 0);
+		if (phone < 0) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+		
+		device_t *dev = (device_t *) malloc(sizeof(device_t));
+		if (dev == NULL) {
+			ipc_answer_0(rid, ENOMEM);
+			return;
+		}
+		
+		dev->handle = handle;
+		dev->phone = phone;
+		dev->refcount = 1;
+		
+		hash_table_insert(&devices, key, &dev->link);
+	} else {
+		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		dev->refcount++;
+	}
+	
+	ipc_answer_3(rid, EOK, 0, 1, L_FILE);
+}
+
+void devfs_device(ipc_callid_t rid, ipc_call_t *request)
+{
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	if (index != 0) {
+		unsigned long key[] = {
+			[DEVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		link_t *lnk = hash_table_find(&devices, key);
+		if (lnk == NULL) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+		
+		ipc_answer_1(rid, EOK, (ipcarg_t) index);
+	} else
+		ipc_answer_0(rid, ENOTSUP);
+}
+
 void devfs_read(ipc_callid_t rid, ipc_call_t *request)
 {
@@ -163,32 +292,57 @@
 	
 	if (index != 0) {
-		ipc_answer_1(rid, ENOENT, 0);
-		return;
-	}
-	
-	/*
-	 * Receive the read request.
-	 */
-	ipc_callid_t callid;
-	size_t size;
-	if (!ipc_data_read_receive(&callid, &size)) {
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(rid, EINVAL);
-		return;
-	}
-	
-	size_t bytes = 0;
-	if (index != 0) {
-		(void) ipc_data_read_finalize(callid, NULL, bytes);
+		unsigned long key[] = {
+			[DEVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		link_t *lnk = hash_table_find(&devices, key);
+		if (lnk == NULL) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+		
+		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		
+		ipc_callid_t callid;
+		if (!ipc_data_read_receive(&callid, NULL)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			return;
+		}
+		
+		/* Make a request at the driver */
+		ipc_call_t answer;
+		aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
+		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
+		    IPC_GET_ARG3(*request), &answer);
+		
+		/* Forward the IPC_M_DATA_READ request to the driver */
+		ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		
+		/* Wait for reply from the driver. */
+		ipcarg_t rc;
+		async_wait_for(msg, &rc);
+		size_t bytes = IPC_GET_ARG1(answer);
+		
+		/* Driver reply is the final result of the whole operation */
+		ipc_answer_1(rid, rc, bytes);
 	} else {
-		count_t count = devmap_device_get_count();
+		ipc_callid_t callid;
+		size_t size;
+		if (!ipc_data_read_receive(&callid, &size)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			return;
+		}
+		
+		size_t count = devmap_device_get_count();
 		dev_desc_t *desc = malloc(count * sizeof(dev_desc_t));
 		if (desc == NULL) {
-			ipc_answer_0(callid, ENOENT);
-			ipc_answer_1(rid, ENOENT, 0);
-			return;
-		}
-		
-		count_t max = devmap_device_get_devices(count, desc);
+			ipc_answer_0(callid, ENOMEM);
+			ipc_answer_1(rid, ENOMEM, 0);
+			return;
+		}
+		
+		size_t max = devmap_device_get_devices(count, desc);
 		
 		if (pos < max) {
@@ -201,8 +355,7 @@
 		
 		free(desc);
-		bytes = 1;
-	}
-	
-	ipc_answer_1(rid, EOK, bytes);
+		
+		ipc_answer_1(rid, EOK, 1);
+	}
 }
 
@@ -212,18 +365,44 @@
 	off_t pos = (off_t) IPC_GET_ARG3(*request);
 	
-	/*
-	 * Receive the write request.
-	 */
-	ipc_callid_t callid;
-	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(rid, EINVAL);
-		return;
-	}
-	
-	// TODO
-	ipc_answer_0(callid, ENOENT);
-	ipc_answer_2(rid, ENOENT, 0, 0);
+	if (index != 0) {
+		unsigned long key[] = {
+			[DEVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		link_t *lnk = hash_table_find(&devices, key);
+		if (lnk == NULL) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+		
+		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		
+		ipc_callid_t callid;
+		if (!ipc_data_write_receive(&callid, NULL)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			return;
+		}
+		
+		/* Make a request at the driver */
+		ipc_call_t answer;
+		aid_t msg = async_send_3(dev->phone, IPC_GET_METHOD(*request),
+		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request),
+		    IPC_GET_ARG3(*request), &answer);
+		
+		/* Forward the IPC_M_DATA_WRITE request to the driver */
+		ipc_forward_fast(callid, dev->phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		
+		/* Wait for reply from the driver. */
+		ipcarg_t rc;
+		async_wait_for(msg, &rc);
+		size_t bytes = IPC_GET_ARG1(answer);
+		
+		/* Driver reply is the final result of the whole operation */
+		ipc_answer_1(rid, rc, bytes);
+	} else {
+		/* Read-only filesystem */
+		ipc_answer_0(rid, ENOTSUP);
+	}
 }
 
@@ -231,4 +410,64 @@
 {
 	ipc_answer_0(rid, ENOTSUP);
+}
+
+void devfs_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	if (index != 0) {
+		unsigned long key[] = {
+			[DEVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		link_t *lnk = hash_table_find(&devices, key);
+		if (lnk == NULL) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+		
+		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		dev->refcount--;
+		
+		if (dev->refcount == 0) {
+			ipc_hangup(dev->phone);
+			hash_table_remove(&devices, key, DEVICES_KEYS);
+		}
+		
+		ipc_answer_0(rid, EOK);
+	} else
+		ipc_answer_0(rid, ENOTSUP);
+}
+
+void devfs_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	if (index != 0) {
+		unsigned long key[] = {
+			[DEVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		link_t *lnk = hash_table_find(&devices, key);
+		if (lnk == NULL) {
+			ipc_answer_0(rid, ENOENT);
+			return;
+		}
+		
+		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		
+		/* Make a request at the driver */
+		ipc_call_t answer;
+		aid_t msg = async_send_2(dev->phone, IPC_GET_METHOD(*request),
+		    IPC_GET_ARG1(*request), IPC_GET_ARG2(*request), &answer);
+		
+		/* Wait for reply from the driver */
+		ipcarg_t rc;
+		async_wait_for(msg, &rc);
+		
+		/* Driver reply is the final result of the whole operation */
+		ipc_answer_0(rid, rc);
+	} else
+		ipc_answer_0(rid, ENOTSUP);
 }
 
@@ -240,3 +479,3 @@
 /**
  * @}
- */ 
+ */
Index: uspace/srv/fs/devfs/devfs_ops.h
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.h	(revision a095d202b1caf823b2b66c86fe55c5a3b8bdd306)
+++ uspace/srv/fs/devfs/devfs_ops.h	(revision 9db9b10d117f0270316d82b7abfc8c4114e2b00d)
@@ -29,5 +29,5 @@
 /** @addtogroup fs
  * @{
- */ 
+ */
 
 #ifndef DEVFS_DEVFS_OPS_H_
@@ -42,7 +42,11 @@
 extern void devfs_mount(ipc_callid_t, ipc_call_t *);
 extern void devfs_lookup(ipc_callid_t, ipc_call_t *);
+extern void devfs_open_node(ipc_callid_t, ipc_call_t *);
+extern void devfs_device(ipc_callid_t, ipc_call_t *);
+extern void devfs_sync(ipc_callid_t, ipc_call_t *);
 extern void devfs_read(ipc_callid_t, ipc_call_t *);
 extern void devfs_write(ipc_callid_t, ipc_call_t *);
 extern void devfs_truncate(ipc_callid_t, ipc_call_t *);
+extern void devfs_close(ipc_callid_t, ipc_call_t *);
 extern void devfs_destroy(ipc_callid_t, ipc_call_t *);
 
