Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ boot/Makefile.common	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -102,4 +102,5 @@
 	$(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
 	$(USPACE_PATH)/srv/fs/fat/fat \
+	$(USPACE_PATH)/srv/fs/cdfs/cdfs \
 	$(USPACE_PATH)/srv/fs/minixfs/mfs \
 	$(USPACE_PATH)/srv/fs/exfat/exfat \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/Makefile	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -82,4 +82,5 @@
 	srv/fs/exfat \
 	srv/fs/fat \
+	srv/fs/cdfs \
 	srv/fs/tmpfs \
 	srv/fs/minixfs \
Index: pace/drv/bus/usb/usbhid/kbd.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,5 +1,0 @@
-/*
- * Dummy file because of shared layout sources.
- *
- * Do not delete.
- */
Index: pace/drv/bus/usb/usbhid/kbd/layout.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/layout.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,1 +1,0 @@
-../layout.h
Index: pace/drv/bus/usb/usbhid/kbd/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/main.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,244 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * Copyright (c) 2011 Lubos Slovak
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbhid
- * @{
- */
-/**
- * @file
- * Main routines of USB KBD driver.
- */
-
-#include <ddf/driver.h>
-#include <usb/debug.h>
-#include <errno.h>
-#include <str_error.h>
-
-#include <usb/dev/driver.h>
-
-#include "kbddev.h"
-#include "kbdrepeat.h"
-
-/*----------------------------------------------------------------------------*/
-
-#define NAME "usbkbd"
-
-/**
- * Function for adding a new device of type USB/HID/keyboard.
- *
- * This functions initializes required structures from the device's descriptors
- * and starts new fibril for polling the keyboard for events and another one for
- * handling auto-repeat of keys.
- *
- * During initialization, the keyboard is switched into boot protocol, the idle
- * rate is set to 0 (infinity), resulting in the keyboard only reporting event
- * when a key is pressed or released. Finally, the LED lights are turned on 
- * according to the default setup of lock keys.
- *
- * @note By default, the keyboards is initialized with Num Lock turned on and 
- *       other locks turned off.
- * @note Currently supports only boot-protocol keyboards.
- *
- * @param dev Device to add.
- *
- * @retval EOK if successful.
- * @retval ENOMEM if there
- * @return Other error code inherited from one of functions usb_kbd_init(),
- *         ddf_fun_bind() and ddf_fun_add_to_class().
- *
- * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
- */
-static int usb_kbd_try_add_device(usb_device_t *dev)
-{
-	/* Create the function exposed under /dev/devices. */
-	ddf_fun_t *kbd_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
-	    "keyboard");
-	if (kbd_fun == NULL) {
-		usb_log_error("Could not create DDF function node.\n");
-		return ENOMEM;
-	}
-	
-	/* 
-	 * Initialize device (get and process descriptors, get address, etc.)
-	 */
-	usb_log_debug("Initializing USB/HID KBD device...\n");
-	
-	usb_kbd_t *kbd_dev = usb_kbd_new();
-	if (kbd_dev == NULL) {
-		usb_log_error("Error while creating USB/HID KBD device "
-		    "structure.\n");
-		ddf_fun_destroy(kbd_fun);
-		return ENOMEM;  // TODO: some other code??
-	}
-	
-	int rc = usb_kbd_init(kbd_dev, dev);
-	
-	if (rc != EOK) {
-		usb_log_error("Failed to initialize USB/HID KBD device.\n");
-		ddf_fun_destroy(kbd_fun);
-		usb_kbd_free(&kbd_dev);
-		return rc;
-	}	
-	
-	usb_log_debug("USB/HID KBD device structure initialized.\n");
-	
-	/*
-	 * Store the initialized keyboard device and keyboard ops
-	 * to the DDF function.
-	 */
-	kbd_fun->driver_data = kbd_dev;
-	kbd_fun->ops = &keyboard_ops;
-
-	rc = ddf_fun_bind(kbd_fun);
-	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function: %s.\n",
-		    str_error(rc));
-		// TODO: Can / should I destroy the DDF function?
-		ddf_fun_destroy(kbd_fun);
-		usb_kbd_free(&kbd_dev);
-		return rc;
-	}
-	
-	rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
-	if (rc != EOK) {
-		usb_log_error(
-		    "Could not add DDF function to class 'keyboard': %s.\n",
-		    str_error(rc));
-		ddf_fun_destroy(kbd_fun);
-		usb_kbd_free(&kbd_dev);
-		return rc;
-	}
-	
-	/* Start automated polling function.
-	 * This will create a separate fibril that will query the device
-	 * for the data continuously 
-	 */
-       rc = usb_device_auto_poll(dev,
-	   /* Index of the polling pipe. */
-	   USB_KBD_POLL_EP_NO,
-	   /* Callback when data arrives. */
-	   usb_kbd_polling_callback,
-	   /* How much data to request. */
-	   dev->pipes[USB_KBD_POLL_EP_NO].pipe->max_packet_size,
-	   /* Callback when the polling ends. */
-	   usb_kbd_polling_ended_callback,
-	   /* Custom argument. */
-	   kbd_dev);
-	
-	
-	if (rc != EOK) {
-		usb_log_error("Failed to start polling fibril for `%s'.\n",
-		    dev->ddf_dev->name);
-		return rc;
-	}
-	
-	/*
-	 * Create new fibril for auto-repeat
-	 */
-	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
-	if (fid == 0) {
-		usb_log_error("Failed to start fibril for KBD auto-repeat");
-		return ENOMEM;
-	}
-	fibril_add_ready(fid);
-
-	(void)keyboard_ops;
-
-	/*
-	 * Hurrah, device is initialized.
-	 */
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * Callback for passing a new device to the driver.
- *
- * @note Currently, only boot-protocol keyboards are supported by this driver.
- *
- * @param dev Structure representing the new device.
- *
- * @retval EOK if successful. 
- * @retval EREFUSED if the device is not supported.
- */
-static int usb_kbd_add_device(usb_device_t *dev)
-{
-	usb_log_debug("usb_kbd_add_device()\n");
-	
-	if (dev->interface_no < 0) {
-		usb_log_warning("Device is not a supported keyboard.\n");
-		usb_log_error("Failed to add USB KBD device: endpoint not "
-		    "found.\n");
-		return ENOTSUP;
-	}
-	
-	int rc = usb_kbd_try_add_device(dev);
-	
-	if (rc != EOK) {
-		usb_log_warning("Device is not a supported keyboard.\n");
-		usb_log_error("Failed to add KBD device: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
-	
-	usb_log_info("Keyboard `%s' ready to use.\n", dev->ddf_dev->name);
-
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
-/* Currently, the framework supports only device adding. Once the framework
- * supports unplug, more callbacks will be added. */
-static usb_driver_ops_t usb_kbd_driver_ops = {
-        .add_device = usb_kbd_add_device,
-};
-
-
-/* The driver itself. */
-static usb_driver_t usb_kbd_driver = {
-        .name = NAME,
-        .ops = &usb_kbd_driver_ops,
-        .endpoints = usb_kbd_endpoints
-};
-
-/*----------------------------------------------------------------------------*/
-
-int main(int argc, char *argv[])
-{
-	printf(NAME ": HelenOS USB KBD driver.\n");
-
-	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
-
-	return usb_driver_main(&usb_kbd_driver);
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/layout.h
===================================================================
--- uspace/drv/bus/usb/usbhid/layout.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,57 +1,0 @@
-/*
- * Copyright (c) 2009 Jiri Svoboda
- * Copyright (c) 2011 Lubos Slovak 
- * (copied from /uspace/srv/hid/kbd/include/layout.h)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbhid
- * @{
- */
-/** @file
- * Keyboard layout.
- */
-
-#ifndef USB_HID_LAYOUT_H_
-#define USB_HID_LAYOUT_H_
-
-#include <sys/types.h>
-#include <io/console.h>
-
-typedef struct {
-	void (*reset)(void);
-	wchar_t (*parse_ev)(kbd_event_t *);
-} layout_op_t;
-
-extern layout_op_t us_qwerty_op;
-extern layout_op_t us_dvorak_op;
-extern layout_op_t cz_op;
-
-#endif
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/scsi.h
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,54 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/** @file
- * SCSI related structures.
- */
-
-#ifndef USB_USBMAST_SCSI_H_
-#define USB_USBMAST_SCSI_H_
-
-#include <sys/types.h>
-#include <usb/usb.h>
-
-typedef struct {
-	uint8_t op_code;
-	uint8_t lun_evpd;
-	uint8_t page_code;
-	uint16_t alloc_length;
-	uint8_t ctrl;
-} __attribute__((packed)) scsi_cmd_inquiry_t;
-
-#endif
-
-/**
- * @}
- */
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/lib/block/libblock.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -93,5 +93,4 @@
 static int get_block_size(async_sess_t *, size_t *);
 static int get_num_blocks(async_sess_t *, aoff64_t *);
-static int read_toc(async_sess_t *, uint8_t);
 static aoff64_t ba_ltop(devcon_t *, aoff64_t);
 
@@ -896,24 +895,35 @@
  * @param service_id Service ID of the block device.
  * @param session    Starting session.
- * @param data       Buffer to read TOC into.
- *
- * @return EOK on success.
- * @return Error code on failure.
- *
- */
-int block_get_toc(service_id_t service_id, uint8_t session, void *data)
+ *
+ * @return Allocated TOC structure.
+ * @return NULL on failure.
+ *
+ */
+toc_block_t *block_get_toc(service_id_t service_id, uint8_t session)
 {
 	devcon_t *devcon = devcon_search(service_id);
 	assert(devcon);
 	
+	toc_block_t *toc = NULL;
+	
 	fibril_mutex_lock(&devcon->comm_area_lock);
 	
-	int rc = read_toc(devcon->sess, session);
-	if (rc == EOK)
-		memcpy(data, devcon->comm_area, devcon->pblock_size);
+	async_exch_t *exch = async_exchange_begin(devcon->sess);
+	int rc = async_req_1_0(exch, BD_READ_TOC, session);
+	async_exchange_end(exch);
+	
+	if (rc == EOK) {
+		toc = (toc_block_t *) malloc(sizeof(toc_block_t));
+		if (toc != NULL) {
+			memset(toc, 0, sizeof(toc_block_t));
+			memcpy(toc, devcon->comm_area,
+			    min(devcon->pblock_size, sizeof(toc_block_t)));
+		}
+	}
+	
 	
 	fibril_mutex_unlock(&devcon->comm_area_lock);
 	
-	return rc;
+	return toc;
 }
 
@@ -1008,14 +1018,4 @@
 }
 
-/** Get TOC from block device. */
-static int read_toc(async_sess_t *sess, uint8_t session)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_1_0(exch, BD_READ_TOC, session);
-	async_exchange_end(exch);
-
-	return rc;
-}
-
 /** Convert logical block address to physical block address. */
 static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba)
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/lib/block/libblock.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -97,4 +97,17 @@
 };
 
+typedef struct {
+	uint16_t size;
+	uint8_t first_session;
+	uint8_t last_session;
+	
+	uint8_t res0;
+	uint8_t adr_ctrl;
+	uint8_t first_track;
+	uint8_t res1;
+	
+	uint32_t first_lba;
+} __attribute__((packed)) toc_block_t;
+
 extern int block_init(exch_mgmt_t, service_id_t, size_t);
 extern void block_fini(service_id_t);
@@ -114,5 +127,5 @@
 extern int block_get_bsize(service_id_t, size_t *);
 extern int block_get_nblocks(service_id_t, aoff64_t *);
-extern int block_get_toc(service_id_t, uint8_t, void *);
+extern toc_block_t *block_get_toc(service_id_t, uint8_t);
 extern int block_read_direct(service_id_t, aoff64_t, size_t, void *);
 extern int block_read_bytes_direct(service_id_t, aoff64_t, size_t, void *);
@@ -123,3 +136,2 @@
 /** @}
  */
-
Index: uspace/lib/c/generic/str.c
===================================================================
--- uspace/lib/c/generic/str.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/lib/c/generic/str.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -1291,4 +1291,145 @@
 }
 
+/** Convert string to uint8_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return EOK if conversion was successful.
+ *
+ */
+int str_uint8_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint8_t *result)
+{
+	assert(result != NULL);
+	
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != EOK)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	uint8_t _res = (uint8_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return EOK;
+}
+
+/** Convert string to uint16_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return EOK if conversion was successful.
+ *
+ */
+int str_uint16_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint16_t *result)
+{
+	assert(result != NULL);
+	
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != EOK)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	uint16_t _res = (uint16_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return EOK;
+}
+
+/** Convert string to uint32_t.
+ *
+ * @param nptr   Pointer to string.
+ * @param endptr If not NULL, pointer to the first invalid character
+ *               is stored here.
+ * @param base   Zero or number between 2 and 36 inclusive.
+ * @param strict Do not allow any trailing characters.
+ * @param result Result of the conversion.
+ *
+ * @return EOK if conversion was successful.
+ *
+ */
+int str_uint32_t(const char *nptr, char **endptr, unsigned int base,
+    bool strict, uint32_t *result)
+{
+	assert(result != NULL);
+	
+	bool neg;
+	char *lendptr;
+	uint64_t res;
+	int ret = str_uint(nptr, &lendptr, base, &neg, &res);
+	
+	if (endptr != NULL)
+		*endptr = (char *) lendptr;
+	
+	if (ret != EOK)
+		return ret;
+	
+	/* Do not allow negative values */
+	if (neg)
+		return EINVAL;
+	
+	/* Check whether we are at the end of
+	   the string in strict mode */
+	if ((strict) && (*lendptr != 0))
+		return EINVAL;
+	
+	/* Check for overflow */
+	uint32_t _res = (uint32_t) res;
+	if (_res != res)
+		return EOVERFLOW;
+	
+	*result = _res;
+	
+	return EOK;
+}
+
 /** Convert string to uint64_t.
  *
Index: uspace/lib/c/include/str.h
===================================================================
--- uspace/lib/c/include/str.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/lib/c/include/str.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -97,4 +97,7 @@
 extern char *str_ndup(const char *, size_t max_size);
 
+extern int str_uint8_t(const char *, char **, unsigned int, bool, uint8_t *);
+extern int str_uint16_t(const char *, char **, unsigned int, bool, uint16_t *);
+extern int str_uint32_t(const char *, char **, unsigned int, bool, uint32_t *);
 extern int str_uint64(const char *, char **, unsigned int, bool, uint64_t *);
 extern int str_size_t(const char *, char **, unsigned int, bool, size_t *);
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/srv/devman/main.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -507,6 +507,7 @@
 	fun_node_t *fun;
 	int rc;
-
-	printf("devman_drv_fun_online()\n");
+	
+	log_msg(LVL_DEBUG, "devman_drv_fun_online()");
+	
 	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
 	if (fun == NULL) {
@@ -526,5 +527,4 @@
 	rc = online_function(fun);
 	if (rc != EOK) {
-		printf("devman_drv_fun_online() online_fun->ERROR\n");
 		fun_del_ref(fun);
 		async_answer_0(iid, (sysarg_t) rc);
@@ -533,5 +533,4 @@
 	
 	fun_del_ref(fun);
-	printf("devman_drv_fun_online() online_fun->OK\n");
 	
 	async_answer_0(iid, (sysarg_t) EOK);
Index: uspace/srv/fs/cdfs/Makefile
===================================================================
--- uspace/srv/fs/cdfs/Makefile	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
+++ uspace/srv/fs/cdfs/Makefile	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2010 Jiri Kavalik
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX)
+BINARY = cdfs
+
+SOURCES = \
+	cdfs.c \
+	cdfs_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/cdfs/cdfs.c
===================================================================
--- uspace/srv/fs/cdfs/cdfs.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
+++ uspace/srv/fs/cdfs/cdfs.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2010 Jiri Kavalik
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file cdfs.c
+ * @brief File system driver for ISO9660 file system.
+ */
+
+#include <ipc/services.h>
+#include <ns.h>
+#include <errno.h>
+#include <stdio.h>
+#include <libfs.h>
+#include "cdfs.h"
+#include "cdfs_ops.h"
+
+#define NAME  "cdfs"
+
+static vfs_info_t cdfs_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
+};
+
+int main(int argc, char **argv)
+{
+	printf("%s: HelenOS cdfs file system server\n", NAME);
+	
+	if (!cdfs_init()) {
+		printf("%s: failed to initialize cdfs\n", NAME);
+		return -1;
+	}
+	
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		printf("%s: Unable to connect to VFS\n", NAME);
+		return -1;
+	}
+	
+	int rc = fs_register(vfs_sess, &cdfs_vfs_info, &cdfs_ops,
+	    &cdfs_libfs_ops);
+	if (rc != EOK) {
+		printf("%s: Failed to register file system (%d)\n", NAME, rc);
+		return rc;
+	}
+	
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
+	async_manager();
+	
+	/* Not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/cdfs/cdfs.h
===================================================================
--- uspace/srv/fs/cdfs/cdfs.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
+++ uspace/srv/fs/cdfs/cdfs.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef CDFS_CDFS_H_
+#define CDFS_CDFS_H_
+
+#include <libfs.h>
+
+extern vfs_out_ops_t cdfs_ops;
+extern libfs_ops_t cdfs_libfs_ops;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/cdfs/cdfs_endian.h
===================================================================
--- uspace/srv/fs/cdfs/cdfs_endian.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
+++ uspace/srv/fs/cdfs/cdfs_endian.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef CDFS_CDFS_ENDIAN_H_
+#define CDFS_CDFS_ENDIAN_H_
+
+#include <sys/types.h>
+
+#if !(defined(__BE__) ^ defined(__LE__))
+	#error The architecture must be either big-endian or little-endian.
+#endif
+
+typedef struct {
+	uint16_t le;
+	uint16_t be;
+} __attribute__((packed)) uint16_t_lb;
+
+typedef struct {
+	uint32_t le;
+	uint32_t be;
+} __attribute__((packed)) uint32_t_lb;
+
+static inline uint16_t uint16_lb(uint16_t_lb val)
+{
+#ifdef __LE__
+	return val.le;
+#endif
+
+#ifdef __BE__
+	return val.be;
+#endif
+}
+
+static inline uint32_t uint32_lb(uint32_t_lb val)
+{
+#ifdef __LE__
+	return val.le;
+#endif
+
+#ifdef __BE__
+	return val.be;
+#endif
+}
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/cdfs/cdfs_ops.c
===================================================================
--- uspace/srv/fs/cdfs/cdfs_ops.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
+++ uspace/srv/fs/cdfs/cdfs_ops.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file cdfs_ops.c
+ * @brief Implementation of VFS operations for the cdfs file system
+ *        server.
+ */
+
+#include <bool.h>
+#include <adt/hash_table.h>
+#include <malloc.h>
+#include <mem.h>
+#include <loc.h>
+#include <libfs.h>
+#include <errno.h>
+#include <libblock.h>
+#include <str.h>
+#include <byteorder.h>
+#include <macros.h>
+#include "cdfs.h"
+#include "cdfs_endian.h"
+#include "cdfs_ops.h"
+
+/** Standard CD-ROM block size */
+#define BLOCK_SIZE  2048
+
+/** Implicit node cache size
+ *
+ * More nodes can be actually cached if the files remain
+ * opended.
+ *
+ */
+#define NODE_CACHE_SIZE  200
+
+#define NODES_BUCKETS  256
+
+#define NODES_KEY_SRVC   0
+#define NODES_KEY_INDEX  1
+
+/** All root nodes have index 0 */
+#define CDFS_SOME_ROOT  0
+
+#define CDFS_NODE(node)  ((node) ? (cdfs_node_t *)(node)->data : NULL)
+#define FS_NODE(node)    ((node) ? (node)->fs_node : NULL)
+
+#define CDFS_STANDARD_IDENT  "CD001"
+
+typedef enum {
+	VOL_DESC_BOOT = 0,
+	VOL_DESC_PRIMARY = 1,
+	VOL_DESC_SUPPLEMENTARY = 2,
+	VOL_DESC_VOL_PARTITION = 3,
+	VOL_DESC_SET_TERMINATOR = 255
+} vol_desc_type_t;
+
+typedef struct {
+	uint8_t system_ident[32];
+	uint8_t ident[32];
+} __attribute__((packed)) cdfs_vol_desc_boot_t;
+
+typedef struct {
+	uint8_t year[4];
+	uint8_t mon[2];
+	uint8_t day[2];
+	
+	uint8_t hour[2];
+	uint8_t min[2];
+	uint8_t sec[2];
+	uint8_t msec[2];
+	
+	uint8_t offset;
+} __attribute__((packed)) cdfs_datetime_t;
+
+typedef struct {
+	uint8_t year;  /**< Since 1900 */
+	uint8_t mon;
+	uint8_t day;
+	
+	uint8_t hour;
+	uint8_t min;
+	uint8_t sec;
+	
+	uint8_t offset;
+} __attribute__((packed)) cdfs_timestamp_t;
+
+typedef enum {
+	DIR_FLAG_DIRECTORY = 2
+} cdfs_dir_flag_t;
+
+typedef struct {
+	uint8_t length;
+	uint8_t ea_length;
+	
+	uint32_t_lb lba;
+	uint32_t_lb size;
+	
+	cdfs_timestamp_t timestamp;
+	uint8_t flags;
+	uint8_t unit_size;
+	uint8_t gap_size;
+	uint16_t_lb sequence_nr;
+	
+	uint8_t name_length;
+	uint8_t name[];
+} __attribute__((packed)) cdfs_dir_t;
+
+typedef struct {
+	uint8_t res0;
+	
+	uint8_t system_ident[32];
+	uint8_t ident[32];
+	
+	uint64_t res1;
+	uint32_t_lb lba_size;
+	
+	uint8_t res2[32];
+	uint16_t_lb set_size;
+	uint16_t_lb sequence_nr;
+	
+	uint16_t_lb block_size;
+	uint32_t_lb path_table_size;
+	
+	uint32_t path_table_lsb;
+	uint32_t opt_path_table_lsb;
+	uint32_t path_table_msb;
+	uint32_t opt_path_table_msb;
+	
+	cdfs_dir_t root_dir;
+	uint8_t pad0;
+	
+	uint8_t set_ident[128];
+	uint8_t publisher_ident[128];
+	uint8_t preparer_ident[128];
+	uint8_t app_ident[128];
+	
+	uint8_t copyright_file_ident[37];
+	uint8_t abstract_file_ident[37];
+	uint8_t biblio_file_ident[37];
+	
+	cdfs_datetime_t creation;
+	cdfs_datetime_t modification;
+	cdfs_datetime_t expiration;
+	cdfs_datetime_t effective;
+	
+	uint8_t fs_version;
+} __attribute__((packed)) cdfs_vol_desc_primary_t;
+
+typedef struct {
+	uint8_t type;
+	uint8_t standard_ident[5];
+	uint8_t version;
+	union {
+		cdfs_vol_desc_boot_t boot;
+		cdfs_vol_desc_primary_t primary;
+	} data;
+} __attribute__((packed)) cdfs_vol_desc_t;
+
+typedef enum {
+	CDFS_NONE,
+	CDFS_FILE,
+	CDFS_DIRECTORY
+} cdfs_dentry_type_t;
+
+typedef struct {
+	link_t link;       /**< Siblings list link */
+	fs_index_t index;  /**< Node index */
+	char *name;        /**< Dentry name */
+} cdfs_dentry_t;
+
+typedef uint32_t cdfs_lba_t;
+
+typedef struct {
+	fs_node_t *fs_node;       /**< FS node */
+	fs_index_t index;         /**< Node index */
+	service_id_t service_id;  /**< Service ID of block device */
+	
+	link_t nh_link;           /**< Nodes hash table link */
+	cdfs_dentry_type_t type;  /**< Dentry type */
+	
+	unsigned int lnkcnt;      /**< Link count */
+	uint32_t size;            /**< File size if type is CDFS_FILE */
+	
+	list_t cs_list;           /**< Child's siblings list */
+	cdfs_lba_t lba;           /**< LBA of data on disk */
+	bool processed;           /**< If all children have been read */
+	unsigned int opened;      /**< Opened count */
+} cdfs_node_t;
+
+/** Shared index of nodes */
+static fs_index_t cdfs_index = 1;
+
+/** Number of currently cached nodes */
+static size_t nodes_cached = 0;
+
+/** Hash table of all cdfs nodes */
+static hash_table_t nodes;
+
+static hash_index_t nodes_hash(unsigned long key[])
+{
+	return key[NODES_KEY_INDEX] % NODES_BUCKETS;
+}
+
+static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	cdfs_node_t *node =
+	    hash_table_get_instance(item, cdfs_node_t, nh_link);
+	
+	switch (keys) {
+	case 1:
+		return (node->service_id == key[NODES_KEY_SRVC]);
+	case 2:
+		return ((node->service_id == key[NODES_KEY_SRVC]) &&
+		    (node->index == key[NODES_KEY_INDEX]));
+	default:
+		assert((keys == 1) || (keys == 2));
+	}
+	
+	return 0;
+}
+
+static void nodes_remove_callback(link_t *item)
+{
+	cdfs_node_t *node =
+	    hash_table_get_instance(item, cdfs_node_t, nh_link);
+	
+	assert(node->type == CDFS_DIRECTORY);
+	
+	link_t *link;
+	while ((link = list_first(&node->cs_list)) != NULL) {
+		cdfs_dentry_t *dentry = list_get_instance(link, cdfs_dentry_t, link);
+		list_remove(&dentry->link);
+		free(dentry);
+	}
+	
+	free(node->fs_node);
+	free(node);
+}
+
+/** Nodes hash table operations */
+static hash_table_operations_t nodes_ops = {
+	.hash = nodes_hash,
+	.compare = nodes_compare,
+	.remove_callback = nodes_remove_callback
+};
+
+static int cdfs_node_get(fs_node_t **rfn, service_id_t service_id,
+    fs_index_t index)
+{
+	unsigned long key[] = {
+		[NODES_KEY_SRVC] = service_id,
+		[NODES_KEY_INDEX] = index
+	};
+	
+	link_t *link = hash_table_find(&nodes, key);
+	if (link) {
+		cdfs_node_t *node =
+		    hash_table_get_instance(link, cdfs_node_t, nh_link);
+		
+		*rfn = FS_NODE(node);
+	} else
+		*rfn = NULL;
+	
+	return EOK;
+}
+
+static int cdfs_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	return cdfs_node_get(rfn, service_id, CDFS_SOME_ROOT);
+}
+
+static void cdfs_node_initialize(cdfs_node_t *node)
+{
+	node->fs_node = NULL;
+	node->index = 0;
+	node->service_id = 0;
+	node->type = CDFS_NONE;
+	node->lnkcnt = 0;
+	node->size = 0;
+	node->lba = 0;
+	node->processed = false;
+	node->opened = 0;
+	
+	link_initialize(&node->nh_link);
+	list_initialize(&node->cs_list);
+}
+
+static int create_node(fs_node_t **rfn, service_id_t service_id, int lflag,
+    fs_index_t index)
+{
+	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
+	
+	cdfs_node_t *node = malloc(sizeof(cdfs_node_t));
+	if (!node)
+		return ENOMEM;
+	
+	cdfs_node_initialize(node);
+	
+	node->fs_node = malloc(sizeof(fs_node_t));
+	if (!node->fs_node) {
+		free(node);
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(node->fs_node);
+	node->fs_node->data = node;
+	
+	fs_node_t *rootfn;
+	int rc = cdfs_root_get(&rootfn, service_id);
+	
+	assert(rc == EOK);
+	
+	if (!rootfn)
+		node->index = CDFS_SOME_ROOT;
+	else
+		node->index = index;
+	
+	node->service_id = service_id;
+	
+	if (lflag & L_DIRECTORY)
+		node->type = CDFS_DIRECTORY;
+	else
+		node->type = CDFS_FILE;
+	
+	/* Insert the new node into the nodes hash table. */
+	unsigned long key[] = {
+		[NODES_KEY_SRVC] = node->service_id,
+		[NODES_KEY_INDEX] = node->index
+	};
+	
+	hash_table_insert(&nodes, key, &node->nh_link);
+	
+	*rfn = FS_NODE(node);
+	nodes_cached++;
+	
+	return EOK;
+}
+
+static int link_node(fs_node_t *pfn, fs_node_t *fn, const char *name)
+{
+	cdfs_node_t *parent = CDFS_NODE(pfn);
+	cdfs_node_t *node = CDFS_NODE(fn);
+	
+	assert(parent->type == CDFS_DIRECTORY);
+	
+	/* Check for duplicate entries */
+	list_foreach(parent->cs_list, link) {
+		cdfs_dentry_t *dentry =
+		    list_get_instance(link, cdfs_dentry_t, link);
+		
+		if (str_cmp(dentry->name, name) == 0)
+			return EEXIST;
+	}
+	
+	/* Allocate and initialize the dentry */
+	cdfs_dentry_t *dentry = malloc(sizeof(cdfs_dentry_t));
+	if (!dentry)
+		return ENOMEM;
+	
+	/* Populate and link the new dentry */
+	dentry->name = str_dup(name);
+	if (dentry->name == NULL) {
+		free(dentry);
+		return ENOMEM;
+	}
+	
+	link_initialize(&dentry->link);
+	dentry->index = node->index;
+	
+	node->lnkcnt++;
+	list_append(&dentry->link, &parent->cs_list);
+	
+	return EOK;
+}
+
+static bool cdfs_readdir(service_id_t service_id, fs_node_t *fs_node)
+{
+	cdfs_node_t *node = CDFS_NODE(fs_node);
+	assert(node);
+	
+	if (node->processed)
+		return true;
+	
+	uint32_t blocks = node->size / BLOCK_SIZE;
+	if ((node->size % BLOCK_SIZE) != 0)
+		blocks++;
+	
+	for (uint32_t i = 0; i < blocks; i++) {
+		block_t *block;
+		int rc = block_get(&block, service_id, node->lba + i, BLOCK_FLAGS_NONE);
+		if (rc != EOK)
+			return false;
+		
+		cdfs_dir_t *dir = (cdfs_dir_t *) block->data;
+		
+		// FIXME: skip '.' and '..'
+		
+		for (size_t offset = 0;
+		    (dir->length != 0) && (offset < BLOCK_SIZE);
+		    offset += dir->length) {
+			dir = (cdfs_dir_t *) (block->data + offset);
+			
+			cdfs_dentry_type_t dentry_type;
+			if (dir->flags & DIR_FLAG_DIRECTORY)
+				dentry_type = CDFS_DIRECTORY;
+			else
+				dentry_type = CDFS_FILE;
+			
+			// FIXME: hack - indexing by dentry byte offset on disc
+			
+			fs_node_t *fn;
+			int rc = create_node(&fn, service_id, dentry_type,
+			    (node->lba + i) * BLOCK_SIZE + offset);
+			if ((rc != EOK) || (fn == NULL))
+				return false;
+			
+			cdfs_node_t *cur = CDFS_NODE(fn);
+			cur->lba = uint32_lb(dir->lba);
+			cur->size = uint32_lb(dir->size);
+			
+			char *name = (char *) malloc(dir->name_length + 1);
+			if (name == NULL)
+				return false;
+			
+			memcpy(name, dir->name, dir->name_length);
+			name[dir->name_length] = 0;
+			
+			// FIXME: check return value
+			
+			link_node(fs_node, fn, name);
+			free(name);
+			
+			if (dentry_type == CDFS_FILE)
+				cur->processed = true;
+		}
+		
+		block_put(block);
+	}
+	
+	node->processed = true;
+	return true;
+}
+
+static fs_node_t *get_uncached_node(service_id_t service_id, fs_index_t index)
+{
+	cdfs_lba_t lba = index / BLOCK_SIZE;
+	size_t offset = index % BLOCK_SIZE;
+	
+	block_t *block;
+	int rc = block_get(&block, service_id, lba, BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return NULL;
+	
+	cdfs_dir_t *dir = (cdfs_dir_t *) (block->data + offset);
+	
+	cdfs_dentry_type_t dentry_type;
+	if (dir->flags & DIR_FLAG_DIRECTORY)
+		dentry_type = CDFS_DIRECTORY;
+	else
+		dentry_type = CDFS_FILE;
+	
+	fs_node_t *fn;
+	rc = create_node(&fn, service_id, dentry_type, index);
+	if ((rc != EOK) || (fn == NULL))
+		return NULL;
+	
+	cdfs_node_t *node = CDFS_NODE(fn);
+	node->lba = uint32_lb(dir->lba);
+	node->size = uint32_lb(dir->size);
+	node->lnkcnt = 1;
+	
+	if (dentry_type == CDFS_FILE)
+		node->processed = true;
+	
+	block_put(block);
+	return fn;
+}
+
+static fs_node_t *get_cached_node(service_id_t service_id, fs_index_t index)
+{
+	unsigned long key[] = {
+		[NODES_KEY_SRVC] = service_id,
+		[NODES_KEY_INDEX] = index
+	};
+	
+	link_t *link = hash_table_find(&nodes, key);
+	if (link) {
+		cdfs_node_t *node =
+		    hash_table_get_instance(link, cdfs_node_t, nh_link);
+		return FS_NODE(node);
+	}
+	
+	return get_uncached_node(service_id, index);
+}
+
+static int cdfs_match(fs_node_t **fn, fs_node_t *pfn, const char *component)
+{
+	cdfs_node_t *parent = CDFS_NODE(pfn);
+	
+	if (!parent->processed) {
+		int rc = cdfs_readdir(parent->service_id, pfn);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	list_foreach(parent->cs_list, link) {
+		cdfs_dentry_t *dentry =
+		    list_get_instance(link, cdfs_dentry_t, link);
+		
+		if (str_cmp(dentry->name, component) == 0) {
+			*fn = get_cached_node(parent->service_id, dentry->index);
+			return EOK;
+		}
+	}
+	
+	*fn = NULL;
+	return EOK;
+}
+
+static int cdfs_node_open(fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	
+	if (!node->processed)
+		cdfs_readdir(node->service_id, fn);
+	
+	node->opened++;
+	return EOK;
+}
+
+static int cdfs_node_put(fs_node_t *fn)
+{
+	/* Nothing to do */
+	return EOK;
+}
+
+static int cdfs_create_node(fs_node_t **fn, service_id_t service_id, int lflag)
+{
+	/* Read-only */
+	return ENOTSUP;
+}
+
+static int cdfs_destroy_node(fs_node_t *fn)
+{
+	/* Read-only */
+	return ENOTSUP;
+}
+
+static int cdfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	/* Read-only */
+	return ENOTSUP;
+}
+
+static int cdfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	/* Read-only */
+	return ENOTSUP;
+}
+
+static int cdfs_has_children(bool *has_children, fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	
+	if ((node->type == CDFS_DIRECTORY) && (!node->processed))
+		cdfs_readdir(node->service_id, fn);
+	
+	*has_children = !list_empty(&node->cs_list);
+	return EOK;
+}
+
+static fs_index_t cdfs_index_get(fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	return node->index;
+}
+
+static aoff64_t cdfs_size_get(fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	return node->size;
+}
+
+static unsigned int cdfs_lnkcnt_get(fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	return node->lnkcnt;
+}
+
+static bool cdfs_is_directory(fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	return (node->type == CDFS_DIRECTORY);
+}
+
+static bool cdfs_is_file(fs_node_t *fn)
+{
+	cdfs_node_t *node = CDFS_NODE(fn);
+	return (node->type == CDFS_FILE);
+}
+
+static service_id_t cdfs_device_get(fs_node_t *fn)
+{
+	return 0;
+}
+
+libfs_ops_t cdfs_libfs_ops = {
+	.root_get = cdfs_root_get,
+	.match = cdfs_match,
+	.node_get = cdfs_node_get,
+	.node_open = cdfs_node_open,
+	.node_put = cdfs_node_put,
+	.create = cdfs_create_node,
+	.destroy = cdfs_destroy_node,
+	.link = cdfs_link_node,
+	.unlink = cdfs_unlink_node,
+	.has_children = cdfs_has_children,
+	.index_get = cdfs_index_get,
+	.size_get = cdfs_size_get,
+	.lnkcnt_get = cdfs_lnkcnt_get,
+	.is_directory = cdfs_is_directory,
+	.is_file = cdfs_is_file,
+	.device_get = cdfs_device_get
+};
+
+static bool iso_readfs(service_id_t service_id, fs_node_t *rfn,
+    cdfs_lba_t altroot)
+{
+	/* First 16 blocks of isofs are empty */
+	block_t *block;
+	int rc = block_get(&block, service_id, altroot + 16, BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return false;
+	
+	cdfs_vol_desc_t *vol_desc = (cdfs_vol_desc_t *) block->data;
+	
+	/*
+	 * Test for primary volume descriptor
+	 * and standard compliance.
+	 */
+	if ((vol_desc->type != VOL_DESC_PRIMARY) ||
+	    (bcmp(vol_desc->standard_ident, CDFS_STANDARD_IDENT, 5) != 0) ||
+	    (vol_desc->version != 1)) {
+		block_put(block);
+		return false;
+	}
+	
+	uint16_t set_size = uint16_lb(vol_desc->data.primary.set_size);
+	if (set_size > 1) {
+		/*
+		 * Technically, we don't support multi-disc sets.
+		 * But one can encounter erroneously mastered
+		 * images in the wild and it might actually work
+		 * for the first disc in the set.
+		 */
+	}
+	
+	uint16_t sequence_nr = uint16_lb(vol_desc->data.primary.sequence_nr);
+	if (sequence_nr != 1) {
+		/*
+		 * We only support the first disc
+		 * in multi-disc sets.
+		 */
+		block_put(block);
+		return false;
+	}
+	
+	uint16_t block_size = uint16_lb(vol_desc->data.primary.block_size);
+	if (block_size != BLOCK_SIZE) {
+		block_put(block);
+		return false;
+	}
+	
+	// TODO: implement path table support
+	
+	cdfs_node_t *node = CDFS_NODE(rfn);
+	node->lba = uint32_lb(vol_desc->data.primary.root_dir.lba);
+	node->size = uint32_lb(vol_desc->data.primary.root_dir.size);
+	
+	if (!cdfs_readdir(service_id, rfn)) {
+		block_put(block);
+		return false;
+	}
+	
+	block_put(block);
+	return true;
+}
+
+/* Mount a session with session start offset
+ *
+ */
+static bool cdfs_instance_init(service_id_t service_id, cdfs_lba_t altroot)
+{
+	/* Create root node */
+	fs_node_t *rfn;
+	int rc = create_node(&rfn, service_id, L_DIRECTORY, cdfs_index++);
+	
+	if ((rc != EOK) || (!rfn))
+		return false;
+	
+	/* FS root is not linked */
+	CDFS_NODE(rfn)->lnkcnt = 0;
+	CDFS_NODE(rfn)->lba = 0;
+	CDFS_NODE(rfn)->processed = false;
+	
+	/* Check if there is cdfs in given session */
+	if (!iso_readfs(service_id, rfn, altroot)) {
+		// XXX destroy node
+		return false;
+	}
+	
+	return true;
+}
+
+static int cdfs_mounted(service_id_t service_id, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned int *lnkcnt)
+{
+	/* Initialize the block layer */
+	int rc = block_init(EXCHANGE_SERIALIZE, service_id, BLOCK_SIZE);
+	if (rc != EOK)
+		return rc;
+	
+	cdfs_lba_t altroot = 0;
+	
+	if (str_lcmp(opts, "altroot=", 8) == 0) {
+		/* User-defined alternative root on a multi-session disk */
+		if (str_uint32_t(opts + 8, NULL, 0, false, &altroot) != EOK)
+			altroot = 0;
+	} else {
+		/* Read TOC and find the last session */
+		toc_block_t *toc = block_get_toc(service_id, 1);
+		if ((toc != NULL) && (uint16_t_be2host(toc->size) == 10)) {
+			altroot = uint32_t_be2host(toc->first_lba);
+			free(toc);
+		}
+	}
+	
+	/* Initialize the block cache */
+	rc = block_cache_init(service_id, BLOCK_SIZE, 0, CACHE_MODE_WT);
+	if (rc != EOK) {
+		block_fini(service_id);
+		return rc;
+	}
+	
+	/* Check if this device is not already mounted */
+	fs_node_t *rootfn;
+	rc = cdfs_root_get(&rootfn, service_id);
+	if ((rc == EOK) && (rootfn)) {
+		cdfs_node_put(rootfn);
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		
+		return EEXIST;
+	}
+	
+	/* Initialize cdfs instance */
+	if (!cdfs_instance_init(service_id, altroot)) {
+		block_cache_fini(service_id);
+		block_fini(service_id);
+		
+		return ENOMEM;
+	}
+	
+	rc = cdfs_root_get(&rootfn, service_id);
+	assert(rc == EOK);
+	
+	cdfs_node_t *root = CDFS_NODE(rootfn);
+	*index = root->index;
+	*size = root->size;
+	*lnkcnt = root->lnkcnt;
+	
+	return EOK;
+}
+
+static void cdfs_instance_done(service_id_t service_id)
+{
+	unsigned long key[] = {
+		[NODES_KEY_SRVC] = service_id
+	};
+	
+	hash_table_remove(&nodes, key, 1);
+	block_cache_fini(service_id);
+	block_fini(service_id);
+}
+
+static int cdfs_unmounted(service_id_t service_id)
+{
+	cdfs_instance_done(service_id);
+	return EOK;
+}
+
+static int cdfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
+	unsigned long key[] = {
+		[NODES_KEY_SRVC] = service_id,
+		[NODES_KEY_INDEX] = index
+	};
+	
+	link_t *link = hash_table_find(&nodes, key);
+	if (link == NULL)
+		return ENOENT;
+	
+	cdfs_node_t *node =
+	    hash_table_get_instance(link, cdfs_node_t, nh_link);
+	
+	if (!node->processed) {
+		int rc = cdfs_readdir(service_id, FS_NODE(node));
+		if (rc != EOK)
+			return rc;
+	}
+	
+	ipc_callid_t callid;
+	size_t len;
+	if (!async_data_read_receive(&callid, &len)) {
+		async_answer_0(callid, EINVAL);
+		return EINVAL;
+	}
+	
+	if (node->type == CDFS_FILE) {
+		if (pos >= node->size) {
+			*rbytes = 0;
+			async_data_read_finalize(callid, NULL, 0);
+		} else {
+			cdfs_lba_t lba = pos / BLOCK_SIZE;
+			size_t offset = pos % BLOCK_SIZE;
+			
+			*rbytes = min(len, BLOCK_SIZE - offset);
+			*rbytes = min(*rbytes, node->size - pos);
+			
+			block_t *block;
+			int rc = block_get(&block, service_id, node->lba + lba,
+			    BLOCK_FLAGS_NONE);
+			if (rc != EOK) {
+				async_answer_0(callid, rc);
+				return rc;
+			}
+			
+			async_data_read_finalize(callid, block->data + offset,
+			    *rbytes);
+			rc = block_put(block);
+			if (rc != EOK)
+				return rc;
+		}
+	} else {
+		link_t *link = list_nth(&node->cs_list, pos);
+		if (link == NULL) {
+			async_answer_0(callid, ENOENT);
+			return ENOENT;
+		}
+		
+		cdfs_dentry_t *dentry =
+		    list_get_instance(link, cdfs_dentry_t, link);
+		
+		*rbytes = 1;
+		async_data_read_finalize(callid, dentry->name,
+		    str_size(dentry->name) + 1);
+	}
+	
+	return EOK;
+}
+
+static int cdfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	/*
+	 * As cdfs is a read-only filesystem,
+	 * the operation is not supported.
+	 */
+	
+	return ENOTSUP;
+}
+
+static int cdfs_truncate(service_id_t service_id, fs_index_t index,
+    aoff64_t size)
+{
+	/*
+	 * As cdfs is a read-only filesystem,
+	 * the operation is not supported.
+	 */
+	
+	return ENOTSUP;
+}
+
+static void cleanup_cache(service_id_t service_id)
+{
+	if (nodes_cached > NODE_CACHE_SIZE) {
+		size_t remove = nodes_cached - NODE_CACHE_SIZE;
+		
+		// FIXME: this accesses the internals of the hash table
+		//        and should be rewritten in a clean way
+		
+		for (hash_index_t chain = 0; chain < nodes.entries; chain++) {
+			for (link_t *link = nodes.entry[chain].head.next;
+			    link != &nodes.entry[chain].head;
+			    link = link->next) {
+				if (remove == 0)
+					return;
+				
+				cdfs_node_t *node =
+				    hash_table_get_instance(link, cdfs_node_t, nh_link);
+				if (node->opened == 0) {
+					link_t *tmp = link;
+					link = link->prev;
+					
+					list_remove(tmp);
+					nodes.op->remove_callback(tmp);
+					nodes_cached--;
+					remove--;
+					
+					continue;
+				}
+			}
+		}
+	}
+}
+
+static int cdfs_close(service_id_t service_id, fs_index_t index)
+{
+	/* Root node is always in memory */
+	if (index == 0)
+		return EOK;
+	
+	unsigned long key[] = {
+		[NODES_KEY_SRVC] = service_id,
+		[NODES_KEY_INDEX] = index
+	};
+	
+	link_t *link = hash_table_find(&nodes, key);
+	if (link == 0)
+		return ENOENT;
+	
+	cdfs_node_t *node =
+	    hash_table_get_instance(link, cdfs_node_t, nh_link);
+	
+	assert(node->opened > 0);
+	
+	node->opened--;
+	cleanup_cache(service_id);
+	
+	return EOK;
+}
+
+static int cdfs_destroy(service_id_t service_id, fs_index_t index)
+{
+	/*
+	 * As cdfs is a read-only filesystem,
+	 * the operation is not supported.
+	 */
+	
+	return ENOTSUP;
+}
+
+static int cdfs_sync(service_id_t service_id, fs_index_t index)
+{
+	/*
+	 * As cdfs is a read-only filesystem,
+	 * the sync operation is a no-op.
+	 */
+	
+	return EOK;
+}
+
+vfs_out_ops_t cdfs_ops = {
+	.mounted = cdfs_mounted,
+	.unmounted = cdfs_unmounted,
+	.read = cdfs_read,
+	.write = cdfs_write,
+	.truncate = cdfs_truncate,
+	.close = cdfs_close,
+	.destroy = cdfs_destroy,
+	.sync = cdfs_sync
+};
+
+/** Initialize the cdfs server
+ *
+ */
+bool cdfs_init(void)
+{
+	if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
+		return false;
+	
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/cdfs/cdfs_ops.h
===================================================================
--- uspace/srv/fs/cdfs/cdfs_ops.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
+++ uspace/srv/fs/cdfs/cdfs_ops.h	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef CDFS_CDFS_OPS_H_
+#define CDFS_CDFS_OPS_H_
+
+#include <bool.h>
+
+extern bool cdfs_init(void);
+
+#endif
+
+/**
+ * @}
+ */
Index: pace/srv/hid/input/include/sun.h
===================================================================
--- uspace/srv/hid/input/include/sun.h	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,47 +1,0 @@
-/*
- * Copyright (c) 2009 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbdgen generic
- * @brief Sun keyboard virtual port driver.
- * @ingroup kbd
- * @{
- */
-/** @file
- */
-
-#ifndef KBD_SUN_H_
-#define KBD_SUN_H_
-
-extern int ns16550_port_init(void);
-extern int z8530_port_init(void);
-
-#endif
-
-/**
- * @}
- */
Index: pace/srv/hid/input/port/dummy.c
===================================================================
--- uspace/srv/hid/input/port/dummy.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,59 +1,0 @@
-/*
- * Copyright (c) 2009 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @brief	Dummy keyboard port driver.
- * @ingroup  kbd
- * @{
- */ 
-/** @file
- */
-
-#include <kbd_port.h>
-#include <kbd.h>
-
-int kbd_port_init(void)
-{
-	return 0;
-}
-
-void kbd_port_yield(void)
-{
-}
-
-void kbd_port_reclaim(void)
-{
-}
-
-void kbd_port_write(uint8_t data)
-{
-	(void) data;
-}
-
-/** @}
-*/
Index: pace/srv/hid/input/port/sgcn.c
===================================================================
--- uspace/srv/hid/input/port/sgcn.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,188 +1,0 @@
-/*
- * Copyright (c) 2008 Pavel Rimsky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup  kbd
- * @{
- */
-/** @file
- * @brief SGCN (Serengeti Console) keyboard port driver.
- */
-
-#include <as.h>
-#include <ddi.h>
-#include <async.h>
-#include <kbd.h>
-#include <kbd_port.h>
-#include <sysinfo.h>
-#include <stdio.h>
-#include <thread.h>
-#include <bool.h>
-#include <errno.h>
-
-#define POLL_INTERVAL  10000
-
-/**
- * SGCN buffer header. It is placed at the very beginning of the SGCN
- * buffer.
- */
-typedef struct {
-	/** hard-wired to "CON" */
-	char magic[4];
-	
-	/** we don't need this */
-	char unused[8];
-	
-	/** offset within the SGCN buffer of the input buffer start */
-	uint32_t in_begin;
-	
-	/** offset within the SGCN buffer of the input buffer end */
-	uint32_t in_end;
-	
-	/** offset within the SGCN buffer of the input buffer read pointer */
-	uint32_t in_rdptr;
-	
-	/** offset within the SGCN buffer of the input buffer write pointer */
-	uint32_t in_wrptr;
-} __attribute__ ((packed)) sgcn_buffer_header_t;
-
-/*
- * Returns a pointer to the object of a given type which is placed at the given
- * offset from the console buffer beginning.
- */
-#define SGCN_BUFFER(type, offset) \
-		((type *) (sram_virt_addr + sram_buffer_offset + (offset)))
-
-/** Returns a pointer to the console buffer header. */
-#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
-
-/**
- * Virtual address mapped to SRAM.
- */
-static uintptr_t sram_virt_addr;
-
-/**
- * SGCN buffer offset within SGCN.
- */
-static uintptr_t sram_buffer_offset;
-
-/* polling thread */
-static void sgcn_thread_impl(void *arg);
-
-static volatile bool polling_disabled = false;
-
-/**
- * Initializes the SGCN driver.
- * Maps the physical memory (SRAM) and creates the polling thread. 
- */
-int kbd_port_init(void)
-{
-	sysarg_t sram_paddr;
-	if (sysinfo_get_value("sram.address.physical", &sram_paddr) != EOK)
-		return -1;
-	
-	sysarg_t sram_size;
-	if (sysinfo_get_value("sram.area.size", &sram_size) != EOK)
-		return -1;
-	
-	if (sysinfo_get_value("sram.buffer.offset", &sram_buffer_offset) != EOK)
-		sram_buffer_offset = 0;
-	
-	sram_virt_addr = (uintptr_t) as_get_mappable_page(sram_size);
-	
-	if (physmem_map((void *) sram_paddr, (void *) sram_virt_addr,
-	    sram_size / PAGE_SIZE, AS_AREA_READ | AS_AREA_WRITE) != 0) {
-		printf("SGCN: uspace driver could not map physical memory.");
-		return -1;
-	}
-	
-	thread_id_t tid;
-	int rc = thread_create(sgcn_thread_impl, NULL, "kbd_poll", &tid);
-	if (rc != 0)
-		return rc;
-	
-	return 0;
-}
-
-void kbd_port_yield(void)
-{
-	polling_disabled = true;
-}
-
-void kbd_port_reclaim(void)
-{
-	polling_disabled = false;
-}
-
-void kbd_port_write(uint8_t data)
-{
-	(void) data;
-}
-
-/**
- * Handler of the "key pressed" event. Reads codes of all the pressed keys from
- * the buffer. 
- */
-static void sgcn_key_pressed(void)
-{
-	char c;
-	
-	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
-	uint32_t end = SGCN_BUFFER_HEADER->in_end;
-	uint32_t size = end - begin;
-	
-	volatile char *buf_ptr = (volatile char *)
-		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
-	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
-	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
-	
-	while (*in_rdptr_ptr != *in_wrptr_ptr) {
-		c = *buf_ptr;
-		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
-		buf_ptr = (volatile char *)
-			SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
-		kbd_push_scancode(c);
-	}
-}
-
-/**
- * Thread to poll SGCN for keypresses.
- */
-static void sgcn_thread_impl(void *arg)
-{
-	(void) arg;
-
-	while (1) {
-		if (polling_disabled == false)
-			sgcn_key_pressed();
-		usleep(POLL_INTERVAL);
-	}
-}
-
-/** @}
- */
Index: pace/srv/hid/input/port/sun.c
===================================================================
--- uspace/srv/hid/input/port/sun.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,89 +1,0 @@
-/*
- * Copyright (c) 2009 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup  kbd
- * @{
- */
-/** @file
- * @brief Sun keyboard virtual port driver.
- */
-
-#include <kbd.h>
-#include <kbd_port.h>
-#include <sun.h>
-#include <sysinfo.h>
-#include <errno.h>
-#include <bool.h>
-
-/** Sun keyboard virtual port driver.
- *
- * This is a virtual port driver which can use
- * both ns16550_port_init and z8530_port_init
- * according to the information passed from the
- * kernel. This is just a temporal hack.
- *
- */
-int kbd_port_init(void)
-{
-	sysarg_t z8530;
-	if (sysinfo_get_value("kbd.type.z8530", &z8530) != EOK)
-		z8530 = false;
-	
-	sysarg_t ns16550;
-	if (sysinfo_get_value("kbd.type.ns16550", &ns16550) != EOK)
-		ns16550 = false;
-	
-	if (z8530) {
-		if (z8530_port_init() == 0)
-			return 0;
-	}
-	
-	if (ns16550) {
-		if (ns16550_port_init() == 0)
-			return 0;
-	}
-	
-	return -1;
-}
-
-void kbd_port_yield(void)
-{
-}
-
-void kbd_port_reclaim(void)
-{
-}
-
-void kbd_port_write(uint8_t data)
-{
-	(void) data;
-}
-
-/** @}
-*/
Index: pace/srv/hid/input/port/z8530.c
===================================================================
--- uspace/srv/hid/input/port/z8530.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ 	(revision )
@@ -1,117 +1,0 @@
-/*
- * Copyright (c) 2006 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup  kbd
- * @{
- */
-/** @file
- * @brief Z8530 keyboard port driver.
- */
-
-#include <ipc/irc.h>
-#include <async.h>
-#include <async_obsolete.h>
-#include <sysinfo.h>
-#include <kbd.h>
-#include <kbd_port.h>
-#include <sun.h>
-#include <sys/types.h>
-#include <ddi.h>
-#include <errno.h>
-
-#define CHAN_A_STATUS  4
-#define CHAN_A_DATA    6
-
-#define RR0_RCA  1
-
-static irq_cmd_t z8530_cmds[] = {
-	{
-		.cmd = CMD_PIO_READ_8,
-		.addr = (void *) 0,     /* Will be patched in run-time */
-		.dstarg = 1
-	},
-	{
-		.cmd = CMD_BTEST,
-		.value = RR0_RCA,
-		.srcarg = 1,
-		.dstarg = 3
-	},
-	{
-		.cmd = CMD_PREDICATE,
-		.value = 2,
-		.srcarg = 3
-	},
-	{
-		.cmd = CMD_PIO_READ_8,
-		.addr = (void *) 0,     /* Will be patched in run-time */
-		.dstarg = 2
-	},
-	{
-		.cmd = CMD_ACCEPT
-	}
-};
-	
-irq_code_t z8530_kbd = {
-	sizeof(z8530_cmds) / sizeof(irq_cmd_t),
-	z8530_cmds
-};
-
-static void z8530_irq_handler(ipc_callid_t iid, ipc_call_t *call);
-
-int z8530_port_init(void)
-{
-	sysarg_t kaddr;
-	if (sysinfo_get_value("kbd.address.kernel", &kaddr) != EOK)
-		return -1;
-	
-	sysarg_t inr;
-	if (sysinfo_get_value("kbd.inr", &inr) != EOK)
-		return -1;
-	
-	z8530_cmds[0].addr = (void *) kaddr + CHAN_A_STATUS;
-	z8530_cmds[3].addr = (void *) kaddr + CHAN_A_DATA;
-	
-	async_set_interrupt_received(z8530_irq_handler);
-	register_irq(inr, device_assign_devno(), inr, &z8530_kbd);
-	
-	return 0;
-}
-
-static void z8530_irq_handler(ipc_callid_t iid, ipc_call_t *call)
-{
-	int scan_code = IPC_GET_ARG2(*call);
-	kbd_push_scancode(scan_code);
-	
-	if (irc_service)
-		async_obsolete_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
-		    IPC_GET_IMETHOD(*call));
-}
-
-/** @}
- */
Index: uspace/srv/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision e03d545524b08bb45e88334bed00ae0f4a5311cc)
+++ uspace/srv/loc/loc.c	(revision 9dbf558776183a15941958e4baadf0177ae7e5d6)
@@ -1277,9 +1277,16 @@
 	categ_dir_add_cat(&cdir, cat);
 
+	cat = category_new("test3");
+	categ_dir_add_cat(&cdir, cat);
+
 	cat = category_new("usbhc");
 	categ_dir_add_cat(&cdir, cat);
 
+	cat = category_new("virt-null");
+	categ_dir_add_cat(&cdir, cat);
+
 	cat = category_new("virtual");
 	categ_dir_add_cat(&cdir, cat);
+
 
 	return true;
