Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ boot/Makefile.common	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -138,4 +138,5 @@
 	nic/e1k \
 	nic/rtl8139 \
+	nic/rtl8169 \
 	block/ahci
 
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/Makefile	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -154,5 +154,6 @@
 	drv/nic/ne2k \
 	drv/nic/e1k \
-	drv/nic/rtl8139
+	drv/nic/rtl8139 \
+	drv/nic/rtl8169
 
 ## Platform-specific hardware support
Index: uspace/app/nic/nic.c
===================================================================
--- uspace/app/nic/nic.c	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/app/nic/nic.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -45,6 +45,9 @@
 
 typedef struct {
+	nic_device_info_t device_info;
 	nic_address_t address;
 	nic_cable_state_t link_state;
+	nic_channel_mode_t duplex;
+	int speed;
 } nic_info_t;
 
@@ -52,5 +55,51 @@
 {
 	printf("syntax:\n");
-	printf("\t" NAME "\n");
+	printf("\t" NAME " [<index> <cmd> [<args...>]]\n");
+	printf("\t<index> is NIC index number reported by the tool\n");
+	printf("\t<cmd> is:\n");
+	printf("\taddr <mac_address> - set MAC address\n");
+	printf("\tspeed <10|100|1000> - set NIC speed\n");
+	printf("\tduplex <half|full|simplex> - set duplex mode\n");
+	printf("\tauto - enable autonegotiation\n");
+}
+
+static async_sess_t *get_nic_by_index(size_t i)
+{
+	int rc;
+	size_t count;
+	char *svc_name;
+	category_id_t nic_cat;
+	service_id_t *nics = NULL;
+	async_sess_t *sess;
+
+	rc = loc_category_get_id("nic", &nic_cat, 0);
+	if (rc != EOK) {
+		printf("Error resolving category 'nic'.\n");
+		goto error;
+	}
+
+	rc = loc_category_get_svcs(nic_cat, &nics, &count);
+	if (rc != EOK) {
+		printf("Error getting list of NICs.\n");
+		goto error;
+	}
+
+	rc = loc_service_get_name(nics[i], &svc_name);
+	if (rc != EOK) {
+		printf("Error getting service name.\n");
+		goto error;
+	}
+
+	printf("Using device: %s\n", svc_name);
+
+	sess = loc_service_connect(EXCHANGE_SERIALIZE, nics[i], 0);
+	if (sess == NULL) {
+		printf("Error connecting to service.\n");
+		goto error;
+	}
+
+	return sess;
+error:
+	return NULL;
 }
 
@@ -59,10 +108,10 @@
 {
 	async_sess_t *sess;
+	nic_role_t role;
 	int rc;
 
 	sess = loc_service_connect(EXCHANGE_SERIALIZE, svc_id, 0);
 	if (sess == NULL) {
-		printf("Error connecting '%s'.\n", svc_name);
-		rc = EIO;
+		printf("Error connecting to service.\n");
 		goto error;
 	}
@@ -75,4 +124,11 @@
 	}
 
+	rc = nic_get_device_info(sess, &info->device_info);
+	if (rc != EOK) {
+		printf("Error getting NIC device info.\n");
+		rc = EIO;
+		goto error;
+	}
+
 	rc = nic_get_cable_state(sess, &info->link_state);
 	if (rc != EOK) {
@@ -81,4 +137,12 @@
 		goto error;
 	}
+
+	rc = nic_get_operation_mode(sess, &info->speed, &info->duplex, &role);
+	if (rc != EOK) {
+		printf("Error getting NIC speed and duplex mode.\n");
+		rc = EIO;
+		goto error;
+	}
+
 
 	return EOK;
@@ -93,4 +157,14 @@
 	case NIC_CS_PLUGGED: return "up";
 	case NIC_CS_UNPLUGGED: return "down";
+	default: assert(false); return NULL;
+	}
+}
+
+static const char *nic_duplex_mode_str(nic_channel_mode_t mode)
+{
+	switch (mode) {
+	case NIC_CM_FULL_DUPLEX: return "full-duplex";
+	case NIC_CM_HALF_DUPLEX: return "half-duplex";
+	case NIC_CM_SIMPLEX: return "simplex";
 	default: assert(false); return NULL;
 	}
@@ -133,5 +207,5 @@
 	}
 
-	printf("[Address] [Link State] [Service Name]\n");
+	printf("[Index]: [Service Name]\n");
 	for (i = 0; i < count; i++) {
 		rc = loc_service_get_name(nics[i], &svc_name);
@@ -152,6 +226,17 @@
 		}
 
-		printf("%s %s %s\n", addr_str,
-		    nic_link_state_str(nic_info.link_state), svc_name);
+		printf("%d: %s\n", i, svc_name);
+		printf("\tMAC address: %s\n", addr_str);
+		printf("\tVendor name: %s\n",
+		    nic_info.device_info.vendor_name);
+		printf("\tModel name: %s\n",
+		    nic_info.device_info.model_name);
+		printf("\tLink state: %s\n",
+		    nic_link_state_str(nic_info.link_state));
+
+		if (nic_info.link_state == NIC_CS_PLUGGED) {
+			printf("\tSpeed: %dMbps %s\n", nic_info.speed,
+			    nic_duplex_mode_str(nic_info.duplex));
+		}
 
 		free(svc_name);
@@ -165,7 +250,129 @@
 }
 
+static int nic_set_speed(int i, char *str)
+{
+	async_sess_t *sess;
+	uint32_t speed;
+	int oldspeed;
+	nic_channel_mode_t oldduplex;
+	nic_role_t oldrole;
+	int rc;
+
+	rc = str_uint32_t(str, NULL, 10, false, &speed);
+	if (rc != EOK) {
+		printf("Speed must be a numeric value.\n");
+		return rc;
+	}
+
+	if (speed != 10 && speed != 100 && speed != 1000) {
+		printf("Speed must be one of: 10, 100, 1000.\n");
+		return EINVAL;
+	}
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	rc = nic_get_operation_mode(sess, &oldspeed, &oldduplex, &oldrole);
+	if (rc != EOK) {
+		printf("Error getting NIC speed and duplex mode.\n");
+		return EIO;
+	}
+
+	return nic_set_operation_mode(sess, speed, oldduplex, oldrole);
+}
+
+static int nic_set_duplex(int i, char *str)
+{
+	async_sess_t *sess;
+	int oldspeed;
+	nic_channel_mode_t duplex = NIC_CM_UNKNOWN;
+	nic_channel_mode_t oldduplex;
+	nic_role_t oldrole;
+	int rc;
+
+	if (!str_cmp(str, "half"))
+		duplex = NIC_CM_HALF_DUPLEX;
+
+	if (!str_cmp(str, "full"))
+		duplex = NIC_CM_FULL_DUPLEX;
+
+	if (!str_cmp(str, "simplex"))
+		duplex = NIC_CM_SIMPLEX;
+
+	if (duplex == NIC_CM_UNKNOWN) {
+		printf("Invalid duplex specification.\n");
+		return EINVAL;
+	}
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	rc = nic_get_operation_mode(sess, &oldspeed, &oldduplex, &oldrole);
+	if (rc != EOK) {
+		printf("Error getting NIC speed and duplex mode.\n");
+		return EIO;
+	}
+
+	return nic_set_operation_mode(sess, oldspeed, duplex, oldrole);
+}
+
+static int nic_set_autoneg(int i)
+{
+	async_sess_t *sess;
+	int rc;
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	rc = nic_autoneg_restart(sess);
+	if (rc != EOK) {
+		printf("Error restarting NIC autonegotiation.\n");
+		return EIO;
+	}
+
+	return EOK;
+}
+
+static int nic_set_addr(int i, char *str)
+{
+	async_sess_t *sess;
+	nic_address_t addr;
+	int rc, idx;
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	if (str_size(str) != 17) {
+		printf("Invalid MAC address specified");
+		return EINVAL;
+	}
+
+	for (idx = 0; idx < 6; idx++) {
+		rc = str_uint8_t(&str[idx * 3], NULL, 16, false, &addr.address[idx]);
+		if (rc != EOK) {
+			printf("Invalid MAC address specified");
+			return EINVAL;
+		}
+	}
+
+	return nic_set_address(sess, &addr);
+}
+
 int main(int argc, char *argv[])
 {
 	int rc;
+	uint32_t index;
 
 	if (argc == 1) {
@@ -173,4 +380,24 @@
 		if (rc != EOK)
 			return 1;
+	} else if (argc >= 3) {
+		rc = str_uint32_t(argv[1], NULL, 10, false, &index);
+		if (rc != EOK) {
+			printf(NAME ": Invalid argument.\n");
+			print_syntax();
+			return 1;
+		}
+
+		if (!str_cmp(argv[2], "addr"))
+			return nic_set_addr(index, argv[3]);
+
+		if (!str_cmp(argv[2], "speed"))
+			return nic_set_speed(index, argv[3]);
+
+		if (!str_cmp(argv[2], "duplex"))
+			return nic_set_duplex(index, argv[3]);
+
+		if (!str_cmp(argv[2], "auto"))
+			return nic_set_autoneg(index);
+
 	} else {
 		printf(NAME ": Invalid argument.\n");
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/drv/bus/isa/isa.dev	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -14,17 +14,4 @@
 	irq 12
 	io_range 060 5
-
-ne2k:
-	match 100 isa/ne2k
-	irq 5
-	io_range 300 20
-
-sb16:
-	match 100 isa/sb16
-	io_range 220 20
-	io_range 330 2
-	irq 5
-	dma 1
-	dma 5
 
 cmos-rtc:
Index: uspace/drv/nic/rtl8169/Makefile
===================================================================
--- uspace/drv/nic/rtl8169/Makefile	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
+++ uspace/drv/nic/rtl8169/Makefile	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2011 Radim Vansa
+# Copyright (c) 2014 Agnieszka Tabaka
+# 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 = $(LIBDRV_PREFIX)/libdrv.a $(LIBNIC_PREFIX)/libnic.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBNIC_PREFIX)/include
+BINARY = rtl8169
+
+SOURCES = \
+	driver.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/rtl8169/defs.h
===================================================================
--- uspace/drv/nic/rtl8169/defs.h	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
+++ uspace/drv/nic/rtl8169/defs.h	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2014 Agnieszka Tabaka
+ * Copyright (c) 2011 Jiri Michalec
+ * 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.
+ */
+
+/** @file rtl8169_defs.h
+ *
+ * Registers, bit positions and masks definition
+ * of the RTL8169 network family cards
+ */
+
+#ifndef RTL8169_DEFS_H_
+#define RTL8169_DEFS_H_
+
+#include <sys/types.h>
+#include <ddi.h>
+
+#define	PCI_VID_REALTEK		0x10ec
+#define	PCI_VID_DLINK		0x1186
+
+/** Size of RTL8169 registers address space */
+#define RTL8169_IO_SIZE  256
+
+#define	RTL8169_FRAME_MAX_LENGTH	1518
+
+/** Registers of RTL8169 family card offsets from the memory address base */
+enum rtl8169_registers {
+	IDR0 = 0x00, /**< First MAC address bit, 6 1b registres sequence */
+	MAC0 = IDR0, /**< Alias for IDR0 */
+	/* 0x06 - 0x07 reserved */
+	MAR0 = 0x08, /**< Multicast mask registers 8 1b registers sequence */
+	DTCCR = 0x10, /**< Dump Tally Counter Command Register */
+	TNPDS = 0x20, /**< Transmit Normal Priority Descriptors */
+	THPDS = 0x28, /**< Transmit High Priority Descriptors */
+	FLASH = 0x30, /**< Flash memory read/write register */
+	ERBCR = 0x34, /**< Early Receive Byte Count Register */
+	ERSR = 0x36, /**< Early Rx Status Register */
+	CR = 0x37, /**< Command register, 1b */
+	TPPOLL = 0x38, /**< Transmit Priority Polling Register */
+	CBA = 0x3a, /**< Current buffer address, 2b */
+	IMR = 0x3c, /**< Interrupt mask register, 2b */
+	ISR = 0x3e, /**< Interrupt status register, 2b */
+	TCR = 0x40, /**< Transmit (Tx) configuration register, 4b */
+	RCR = 0x44, /**< Receive (Rx) configuration register, 4b */
+	TCTR = 0x48, /**< Timer count register */
+	MPC = 0x4c, /**< Missed packet count */
+	CR9346 = 0x50, /**< 93C46 command register (locking of registers) */
+	CONFIG0 = 0x51,	/**< Configuration register 0, 1b */
+	CONFIG1 = 0x52,	/**< Configuration register 1, 1b */
+	CONFIG2 = 0x53, /**< Configuration register 2, 1b */
+	CONFIG3 = 0x54,	/**< Configuration register 3, 1b */
+	CONFIG4 = 0x55, /**< Configuration register 4, 1b */
+	CONFIG5 = 0x56,	/**< Configuration register 5, 1b */
+	/* 0x57 reserved */
+	TIMINT = 0x58, /**< Timer interrupt register, 4b */
+	MULINT = 0x58, /**< Multiple interrupt select, 4b */
+	/* 0x5e-0x5f reserved */
+	PHYAR = 0x60, /**< PHY Access Register, 4b */
+	TBICSR0 = 0x64,	/**< TBI Control and Status Register, 4b */
+	TBI_ANAR = 0x58, /**< TBI Auto-Negotiation Advertisement Register, 2b */
+	TBI_LPAR = 0x6a, /**< TBI Auto-Negotiation Link Partner Ability Register, 2b */
+	PHYSTATUS = 0x6c, /**< PHY Status Register */
+	/* 0x6d-0x83 reserved */
+	WAKEUP0	 = 0x84, /**< Power Management Wakeup frame0, 8b */
+	WAKEUP1	 = 0x8c, /**< Power Management Wakeup frame1, 8b */
+	WAKEUP2LD = 0x94, /**< Power Management Wakeup frame2 low dword, 8b */
+	WAKEUP2HD = 0x9c, /**< Power Management Wakeup frame2 high dword, 8b */
+	WAKEUP3LD = 0xa4, /**< Power Management Wakeup frame3 low dword, 8b */
+	WAKEUP3HD = 0xac, /**< Power Management Wakeup frame3 high dword, 8b */
+	WAKEUP4LD = 0xb4, /**< Power Management Wakeup frame4 low dword, 8b */
+	WAKEUP4HD = 0xbc, /**< Power Management Wakeup frame4 high dword, 8b */
+	CRC0 = 0xc4, /**< 16-bit CRC of wakeup frame 0, 2b */
+	CRC1 = 0xc6, /**< 16-bit CRC of wakeup frame 1, 2b */
+	CRC2 = 0xc8, /**< 16-bit CRC of wakeup frame 2, 2b */
+	CRC3 = 0xca, /**< 16-bit CRC of wakeup frame 3, 2b */
+	CRC4 = 0xcc, /**< 16-bit CRC of wakeup frame 4, 2b */
+	/* 0xce - 0xd9 reserved */
+	RMS = 0xda, /**< Rx packet Maximum Size, 2b */
+	/* 0xdc - 0xdf reserved */
+	CCR = 0xe0, /**< C+ Command Register */
+	/* 0xe2 - 0xe3 reserved */
+	RDSAR = 0xe4, /**< Receive Descriptor Start Address Register, 8b */
+	ETTHR = 0xec, /**< Early Transmit Threshold Register, 1b */
+	/* 0xed - 0xef reserved */
+	FER = 0xf0, /**< Function Event Register, 4b */
+	FEMR = 0xf4, /**< Function Event Mask Register, 4b */
+	FPSR = 0xf8, /**< Function Preset State Register, 4b */
+	FFER = 0xfc, /**< Function Force Event Register, 4b */
+};
+
+enum rtl8169_mii_registers {
+	MII_BMCR = 0x00,
+	MII_BMSR = 0x01,
+	MII_ANAR = 0x04,
+};
+
+/** Command register bits */
+enum rtl8169_cr {
+	CR_TE = (1 << 2), /**< Transmitter enable bit */
+	CR_RE = (1 << 3), /**< Receiver enable bit */
+	CR_RST = (1 << 4), /**< Reset -  set to 1 to force software reset */
+};
+
+/** Config1 register bits */
+enum rtl8169_config1 {
+	CONFIG1_LEDS_SHIFT = 6, /**< Shift of CONFIG1_LEDS bits */
+	CONFIG1_LEDS_SIZE = 2, /**< Size of CONFIG1_LEDS bits */
+	CONFIG1_DVRLOAD = (1 << 5), /**< Driver load */
+	CONFIG1_LWACT = (1 << 4), /**< LWAKE active mode */
+	CONFIG1_MEMMAP = (1 << 3), /**< Memory mapping  */
+	CONFIG1_IOMAP = (1 << 2), /**< I/O space mapping */
+	CONFIG1_VPD = (1 << 1), /**< Set to enable Vital Product Data */
+	CONFIG1_PMEn = (1 << 0) /**< Power management enabled */
+};
+
+enum rtl8169_config2 {
+	CONFIG2_AUXSTATUS = (1 << 4), /**< Auxiliary Power Present Status */
+	CONFIG2_PCIBUSWIDTH = (1 << 3), /**< PCI Bus Width */
+	CONFIG2_PCICLKF_SHIFT = 0,
+	CONFIG2_PCICLKF_SIZE = 2
+};
+
+enum rtl8169_config3 {
+	CONFIG3_GNT_SELECT = (1 << 7), /**< Gnt select */
+	CONFIG3_PARM_EN = (1 << 6), /**< Parameter enabled (100MBit mode) */
+	CONFIG3_MAGIC = (1 << 5), /**< WoL Magic frame enable */
+	CONFIG3_LINK_UP = (1 << 4), /**< Wakeup if link is reestablished */
+	CONFIG3_CLKRUN_EN = (1 << 2), /**< CLKRUN enabled */ /* TODO: check what does it mean */
+	CONFIG3_FBTBEN = (1 << 0), /**< Fast back to back enabled */
+};
+
+enum rtl8169_config4 {
+	CONFIG4_RxFIFOAutoClr = (1 << 7), /**< Automatic RxFIFO owerflow clear */
+	CONFIG4_AnaOff = (1 << 6), /**< Analog poweroff */
+	CONFIG4_LongWF = (1 << 5), /**< Long wakeup frame */
+	CONFIG4_LWPME = (1 << 4), /**< LWAKE and PMEB assertion  */
+	CONFIG4_LWPTN = (1 << 2), /**< LWake pattern */
+	CONFIG4_PBWakeup = (1 << 0), /**< Preboot wakeup */
+};
+
+enum rtl8169_config5 {
+	CONFIG5_BROADCAST_WAKEUP = (1 << 6), /**< Broadcast wakeup frame enable */
+	CONFIG5_MULTICAST_WAKEUP = (1 << 5), /**< Multicast wakeup frame enable */
+	CONFIG5_UNICAST_WAKEUP = (1 << 4), /**< Unicast wakeup frame enable */
+	/* Bits 3-2 reserved */
+	CONFIG5_LAN_WAKE = (1 << 1), /**< LANWake signal enabled */
+	CONFIG5_PME_STATUS = (1 << 0), /**< PMEn change: 0 = SW, 1 = SW+PCI */
+};
+
+/** Interrupt_masks
+ *
+ *  The masks are the same for both IMR and ISR
+ */
+enum rtl8169_interrupts {
+	INT_SERR = (1 << 15), /**< System error interrupt */
+	INT_TIME_OUT = (1 << 14), /**< Time out interrupt */
+	/* Bits 9 - 13 reserved */
+	INT_SW = (1 << 8), /**< Software Interrupt */
+	INT_TDU = (1 << 7), /**< Tx Descriptor Unvailable */
+	INT_FIFOOVW = (1 << 6), /**< Receiver FIFO overflow interrupt */
+	INT_PUN = (1 << 5), /**< Packet Underrun/Link Change Interrupt  */
+	INT_RXOVW = (1 << 4), /**< Receiver buffer overflow */
+	INT_TER = (1 << 3), /**< Transmit error interrupt */
+	INT_TOK = (1 << 2), /**< Transmit OK interrupt */
+	INT_RER = (1 << 1), /**< Receive error interrupt */
+	INT_ROK = (1 << 0), /**< Receive OK interrupt */
+	INT_KNOWN = (INT_SERR | INT_TIME_OUT | INT_SW | INT_TDU \
+	    | INT_FIFOOVW | INT_PUN | INT_RXOVW | INT_TER \
+	    | INT_TOK| INT_RER | INT_ROK),
+};
+
+/** Transmit status descriptor registers bits */
+enum rtl8169_tsd {
+	TSD_CRS = (1 << 31), /**< Carrier Sense Lost */
+	TSD_TABT = (1 << 30), /**< Transmit Abort */
+	TSD_OWC = (1 << 29), /**< Out of Window Collision */
+	TSD_CDH = (1 << 28), /**< CD Heart Beat */
+	TSD_NCC_SHIFT = 24, /**< Collision Count - bit shift */
+	TSD_NCC_SIZE = 4, /**< Collision Count - bit size */
+	TSD_NCC_MASK = (1 << 4)-1, /**< Collision Count - bit size */
+	TSD_ERTXTH_SHIFT = 16, /**< Early Tx Threshold - bit shift */
+	TSD_ERTXTH_SIZE = 6, /**< Early Tx  Treshold - bit size */
+	TSD_TOK = (1 << 15), /**< Transmit OK */
+	TSD_TUN = (1 << 14), /**< Transmit FIFO Underrun */
+	TSD_OWN = (1 << 13), /**< OWN */
+	TSD_SIZE_SHIFT = 0, /**< Size - bit shift */
+	TSD_SIZE_SIZE = 13, /**< Size - bit size */
+	TSD_SIZE_MASK = 0x1fff, /**< Size - bit mask */
+};
+
+/** Receiver control register values */
+enum rtl8169_rcr {
+	RCR_MulERINT = 1 << 24,    /**< Multiple early interrupt select */
+	/* Bits 23-17 reserved */
+	RCR_RER8 = 1 << 16,
+	RCR_RXFTH_SHIFT = 13, /**< Rx FIFO treshold part shitf */
+	RCR_RXFTH_SIZE = 3, /**< Rx FIFO treshold part size */
+	/* Bits 12-11 reserved */
+	RCR_MXDMA_SHIFT = 8, /**< Max DMA Burst Size part shift */
+	RCR_MXDMA_SIZE  = 3, /**< Max DMA Burst Size part size */
+	/* Bit 7 reserved */
+	RCR_ACCEPT_ERROR = 1 << 5, /**< Accept error frame */
+	RCR_ACCEPT_RUNT = 1 << 4, /**< Accept Runt (8-64 bytes) frames */
+	RCR_ACCEPT_BROADCAST = 1 << 3, /**< Accept broadcast */
+	RCR_ACCEPT_MULTICAST = 1 << 2, /**< Accept multicast */
+	RCR_ACCEPT_PHYS_MATCH = 1 << 1, /**< Accept device MAC address match */
+	RCR_ACCEPT_ALL_PHYS = 1 << 0, /**< Accept all frames with phys. desticnation */
+	RCR_ACCEPT_MASK = (1 << 6) - 1   /**< Mask of accept part */
+};
+
+enum rtl8169_cr9346 {
+	CR9346EEM1_SHIFT = 6, /**< RTL8169 operating mode shift */
+	CR9346EEM1_SIZE = 2, /**< RTL8169 operating mode mask */
+	/* Bits 5-4 reserved */
+	EECS = (1 << 3), /**< EECS pin of 93C46 */
+	EESK = (1 << 2), /**< EESK pin of 93C46 */
+	EEDI = (1 << 1), /**< EEDI pin of 93C46 */
+	EEDO = (1 << 0), /**< EEDO pin of 93C46 */
+};
+
+/** Auto-negotiation advertisement register */
+enum rtl8169_anar {
+	ANAR_NEXT_PAGE = (1 << 15), /**< Next page bit, 0 - primary capability */
+	ANAR_ACK = (1 << 14), /**< Capability reception acknowledge */
+	ANAR_REMOTE_FAULT = (1 << 13), /**< Remote fault detection capability */
+	ANAR_PAUSE = (1 << 10), /**< Symetric pause frame capability */
+	ANAR_100T4 = (1 << 9), /**< T4, not supported by the device */
+	ANAR_100TX_FD = (1 << 8), /**< 100BASE_TX full duplex */
+	ANAR_100TX_HD = (1 << 7), /**< 100BASE_TX half duplex */
+	ANAR_10_FD = (1 << 6), /**< 10BASE_T full duplex */
+	ANAR_10_HD = (1 << 5), /**< 10BASE_T half duplex */
+	ANAR_SELECTOR = 0x1, /**< Selector */
+};
+
+enum rtl8169_phystatus {
+	PHYSTATUS_TBIEN = (1 << 7), /**< TBI enabled */
+	PHYSTATUS_TXFLOW = (1 << 6), /**< TX flow control enabled */
+	PHYSTATUS_RXFLOW = (1 << 5), /**< RX flow control enabled */
+	PHYSTATUS_1000M = (1 << 4), /**< Link speed is 1000Mbit/s */
+	PHYSTATUS_100M = (1 << 3), /**< Link speed is 100Mbit/s */
+	PHYSTATUS_10M = (1 << 2), /**< Link speed is 10Mbit/s */
+	PHYSTATUS_LINK = (1 << 1), /**< Link up */
+	PHYSTATUS_FDX = (1 << 0), /**< Link is full duplex */
+};
+
+enum rtl8169_tppoll {
+	TPPOLL_HPQ = (1 << 7), /**< Start transmit on high priority queue */
+	TPPOLL_NPQ = (1 << 6), /**< Start transmit on normal queue */
+	/* Bits 5-1 reserved */
+	TPPOLL_FSWINT = (1 << 0), /** < Generate software interrupt */
+};
+
+enum rtl8169_phyar {
+	PHYAR_RW_SHIFT = 31, /**< Read (0) or write (1) command */
+	PHYAR_RW_READ = (0 << PHYAR_RW_SHIFT),
+	PHYAR_RW_WRITE = (1 << PHYAR_RW_SHIFT),
+	PHYAR_ADDR_SHIFT = 15,
+	PHYAR_ADDR_MASK = 0x1f,
+	PHYAR_DATA_MASK = 0xffff
+};
+
+enum rtl8169_bmcr {
+	BMCR_RESET = (1 << 15), /**< Software reset */
+	BMCR_SPD_100 = (1 << 13), /**< 100 MBit mode set */
+	BMCR_AN_ENABLE = (1 << 12), /**< Autonegotion enable */
+	BMCR_AN_RESTART = (1 << 9), /**< Restart autonegotion */
+	BMCR_DUPLEX = (1 << 8), /**< Duplex mode: 1=full duplex */
+	BMCR_SPD_1000 = (1 << 6), /**< 1000 Mbit mode set */
+};
+
+enum rtl8169_descr_control {
+	CONTROL_OWN = (1 << 31), /**< Descriptor ownership */
+	CONTROL_EOR = (1 << 30), /**< End Of Ring marker */
+	CONTROL_FS = (1 << 29), /**< First Segment marker */
+	CONTROL_LS = (1 << 28), /**< Last Segment marker */
+	CONTROL_LGSEN = (1 << 27), /**< Large send enable */
+	CONTROL_MSS_SHIFT = 16,
+	CONTROL_MSS_MASK = 10,
+	CONTROL_FRAMELEN_MASK = 0xffff
+};
+
+enum rtl8169_descr_txstatus {
+	TXSTATUS_UNDERRUN = (1 << 25),
+	TXSTATUS_TXERRSUM = (1 << 23),
+	TXSTATUS_OWINCOL = (1 << 22),
+	TXSTATUS_LINKFAIL = (1 << 21),
+	TXSTATUS_EXCESSCOL = (1 << 20)
+};
+
+enum rtl8169_descr_rxstatus {
+	RXSTATUS_MAR = (1 << 27),
+	RXSTATUS_PAM = (1 << 26),
+	RXSTATUS_BAR = (1 << 25),
+	RXSTATUS_BOVF = (1 << 24),
+	RXSTATUS_FOVF = (1 << 23),
+	RXSTATUS_RWT = (1 << 22),
+	RXSTATUS_RES = (1 << 21),
+	RXSTATUS_RUNT = (1 << 20),
+	RXSTATUS_CRC = (1 << 19),
+	RXSTATUS_PID1 = (1 << 18),
+	RXSTATUS_PID0 = (1 << 17),
+	RXSTATUS_IPF = (1 << 16),
+	RXSTATUS_UDPF = (1 << 15),
+	RXSTATUS_TCPF = (1 << 14)
+};
+
+typedef struct rtl8169_descr {
+	uint32_t	control;
+	uint32_t	vlan;
+	uint32_t	buf_low;
+	uint32_t	buf_high;
+} rtl8169_descr_t;
+
+#endif
Index: uspace/drv/nic/rtl8169/driver.c
===================================================================
--- uspace/drv/nic/rtl8169/driver.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
+++ uspace/drv/nic/rtl8169/driver.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 2014 Agnieszka Tabaka
+ * 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.
+ */
+
+#define	_DDF_DATA_IMPLANT
+
+#include <assert.h>
+#include <errno.h>
+#include <align.h>
+#include <byteorder.h>
+#include <irc.h>
+#include <libarch/barrier.h>
+
+#include <as.h>
+#include <ddf/log.h>
+#include <ddf/interrupt.h>
+#include <io/log.h>
+#include <nic.h>
+#include <pci_dev_iface.h>
+
+#include <ipc/irc.h>
+#include <sysinfo.h>
+#include <ipc/ns.h>
+
+#include <str.h>
+
+#include "defs.h"
+#include "driver.h"
+
+/** Global mutex for work with shared irq structure */
+FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
+
+static int rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr);
+static int rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
+static int rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
+static int rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role);
+static int rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
+    nic_channel_mode_t duplex, nic_role_t role);
+static int rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send, 
+    nic_result_t *we_receive, uint16_t *time);
+static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive, 
+    uint16_t time);
+static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
+static int rtl8169_autoneg_disable(ddf_fun_t *fun);
+static int rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
+    uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result);
+static int rtl8169_autoneg_restart(ddf_fun_t *fun);
+static int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
+static int rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
+static int rtl8169_on_activated(nic_t *nic_data);
+static int rtl8169_on_stopped(nic_t *nic_data);
+static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size);
+static void rtl8169_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall);
+static inline int rtl8169_register_int_handler(nic_t *nic_data);
+static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
+static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr);
+
+static void rtl8169_reset(rtl8169_t *rtl8169);
+static int rtl8169_get_resource_info(ddf_dev_t *dev);
+static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t *hw_resources);
+static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev);
+
+static int rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
+    const nic_address_t *, size_t);
+static int rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count);
+static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
+
+static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr);
+static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value);
+static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
+    unsigned int last);
+
+/** Network interface options for RTL8169 card driver */
+static nic_iface_t rtl8169_nic_iface = {
+	.set_address = &rtl8169_set_addr,
+	.get_device_info = &rtl8169_get_device_info,
+	.get_cable_state = &rtl8169_get_cable_state,
+	.get_operation_mode = &rtl8169_get_operation_mode,
+	.set_operation_mode = &rtl8169_set_operation_mode,
+
+	.get_pause = &rtl8169_pause_get,
+	.set_pause = &rtl8169_pause_set,
+
+	.autoneg_enable = &rtl8169_autoneg_enable,
+	.autoneg_disable = &rtl8169_autoneg_disable,
+	.autoneg_probe = &rtl8169_autoneg_probe,
+	.autoneg_restart = &rtl8169_autoneg_restart,
+
+	.defective_get_mode = &rtl8169_defective_get_mode,
+	.defective_set_mode = &rtl8169_defective_set_mode,
+};
+
+irq_pio_range_t rtl8169_irq_pio_ranges[] = {
+	{
+		.base = 0,
+		.size = RTL8169_IO_SIZE
+	}
+};
+
+irq_cmd_t rtl8169_irq_commands[] = {
+	{
+		/* Get the interrupt status */
+		.cmd = CMD_PIO_READ_16,
+		.addr = NULL,
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 3,
+		.srcarg = 2
+	},
+	{
+		/* Mark interrupts as solved */
+		.cmd = CMD_PIO_WRITE_16,
+		.addr = NULL,
+		.value = 0xFFFF
+	},
+	{
+		/* Disable interrupts until interrupt routine is finished */
+		.cmd = CMD_PIO_WRITE_16,
+		.addr = NULL,
+		.value = 0x0000
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+/** Interrupt code definition */
+irq_code_t rtl8169_irq_code = {
+	.rangecount = sizeof(rtl8169_irq_pio_ranges) / sizeof(irq_pio_range_t),
+	.ranges = rtl8169_irq_pio_ranges,
+	.cmdcount = sizeof(rtl8169_irq_commands) / sizeof(irq_cmd_t),
+	.cmds = rtl8169_irq_commands
+};
+
+/** Basic device operations for RTL8169 driver */
+static ddf_dev_ops_t rtl8169_dev_ops;
+
+static int rtl8169_dev_add(ddf_dev_t *dev);
+
+/** Basic driver operations for RTL8169 driver */
+static driver_ops_t rtl8169_driver_ops = {
+	.dev_add = &rtl8169_dev_add,
+};
+
+/** Driver structure for RTL8169 driver */
+static driver_t rtl8169_driver = {
+	.name = NAME,
+	.driver_ops = &rtl8169_driver_ops
+};
+
+static int rtl8169_get_resource_info(ddf_dev_t *dev)
+{
+	assert(dev);
+
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	assert(nic_data);
+
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+
+	/* Get hw resources form parent driver */
+	int rc = nic_get_resources(nic_data, &hw_res_parsed);
+	if (rc != EOK)
+		return rc;
+
+	/* Fill resources information to the device */
+	int ret = rtl8169_fill_resource_info(dev, &hw_res_parsed);
+	hw_res_list_parsed_clean(&hw_res_parsed);
+
+	return ret;
+}
+
+static int rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
+    *hw_resources)
+{
+	assert(dev);
+	assert(hw_resources);
+
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_dev(dev));
+	assert(rtl8169);
+
+	if (hw_resources->irqs.count != 1) {
+		ddf_msg(LVL_ERROR, "%s device: unexpected irq count", ddf_dev_get_name(dev));
+		return EINVAL;
+	};
+
+	if (hw_resources->io_ranges.count != 1) {
+		ddf_msg(LVL_ERROR, "%s device: unexpected io ranges count", ddf_dev_get_name(dev));
+		return EINVAL;
+	}
+
+	rtl8169->irq = hw_resources->irqs.irqs[0];
+	ddf_msg(LVL_DEBUG, "%s device: irq 0x%x assigned", ddf_dev_get_name(dev), rtl8169->irq);
+
+	rtl8169->regs_phys = (void *)((size_t)RNGABS(hw_resources->io_ranges.ranges[0]));
+	if (hw_resources->io_ranges.ranges[0].size < RTL8169_IO_SIZE) {
+		ddf_msg(LVL_ERROR, "I/O range assigned to the device "
+		    "%s is too small.", ddf_dev_get_name(dev));
+		return EINVAL;
+	}
+	ddf_msg(LVL_DEBUG, "%s device: i/o addr %p assigned.", ddf_dev_get_name(dev), rtl8169->regs_phys);
+
+	return EOK;
+}
+
+static int rtl8169_allocate_buffers(rtl8169_t *rtl8169)
+{
+	int rc;
+
+	ddf_msg(LVL_DEBUG, "Allocating DMA buffer rings");
+
+	/* Allocate TX ring */
+	rtl8169->tx_ring = AS_AREA_ANY;
+	rc = dmamem_map_anonymous(TX_RING_SIZE, DMAMEM_4GiB, 
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_ring_phys,
+	    (void **)&rtl8169->tx_ring);
+
+	if (rc != EOK)
+		return rc;
+
+	ddf_msg(LVL_DEBUG, "TX ring address: phys=0x%#" PRIxn ", virt=%p",
+	    rtl8169->tx_ring_phys, rtl8169->tx_ring);
+
+	memset(rtl8169->tx_ring, 0, TX_RING_SIZE);
+
+	/* Allocate RX ring */
+	rtl8169->rx_ring = AS_AREA_ANY;
+	rc = dmamem_map_anonymous(RX_RING_SIZE, DMAMEM_4GiB, 
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_ring_phys,
+	    (void **)&rtl8169->rx_ring);
+
+	if (rc != EOK)
+		return rc;
+
+	ddf_msg(LVL_DEBUG, "RX ring address: phys=0x%#" PRIxn ", virt=%p",
+	    rtl8169->rx_ring_phys, rtl8169->rx_ring);
+
+	memset(rtl8169->rx_ring, 0, RX_RING_SIZE);
+
+	/* Allocate TX buffers */
+	rtl8169->tx_buff = AS_AREA_ANY;
+	rc = dmamem_map_anonymous(TX_BUFFERS_SIZE, DMAMEM_4GiB, 
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_buff_phys,
+	    &rtl8169->tx_buff);
+
+	if (rc != EOK)
+		return rc;
+
+	ddf_msg(LVL_DEBUG, "TX buffers base address: phys=0x%#" PRIxn " virt=%p",
+	    rtl8169->tx_buff_phys, rtl8169->tx_buff);
+
+	/* Allocate RX buffers */
+	rtl8169->rx_buff = AS_AREA_ANY;
+	rc = dmamem_map_anonymous(RX_BUFFERS_SIZE, DMAMEM_4GiB, 
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_buff_phys,
+	    &rtl8169->rx_buff);
+
+	if (rc != EOK)
+		return rc;
+
+	ddf_msg(LVL_DEBUG, "RX buffers base address: phys=0x%#" PRIxn ", virt=%p",
+	    rtl8169->rx_buff_phys, rtl8169->rx_buff);
+
+	return EOK;
+}
+
+static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(!nic_get_from_ddf_dev(dev));
+
+	nic_t *nic_data = nic_create_and_bind(dev);
+	if (!nic_data)
+		return NULL;
+
+	rtl8169_t *rtl8169 = malloc(sizeof(rtl8169_t));
+	if (!rtl8169) {
+		nic_unbind_and_destroy(dev);
+		return NULL;
+	}
+
+	memset(rtl8169, 0, sizeof(rtl8169_t));
+
+	rtl8169->nic_data = nic_data;
+	nic_set_specific(nic_data, rtl8169);
+	nic_set_send_frame_handler(nic_data, rtl8169_send_frame);
+	nic_set_state_change_handlers(nic_data,
+		rtl8169_on_activated, NULL, rtl8169_on_stopped);
+	nic_set_filtering_change_handlers(nic_data,
+		rtl8169_unicast_set, rtl8169_multicast_set, rtl8169_broadcast_set,
+		NULL, NULL);
+
+	fibril_mutex_initialize(&rtl8169->rx_lock);
+	fibril_mutex_initialize(&rtl8169->tx_lock);
+
+	nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
+	nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
+	nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
+
+	return rtl8169;
+}
+
+static int rtl8169_dev_initialize(ddf_dev_t *dev)
+{
+	int ret;
+
+	rtl8169_t *rtl8169 = rtl8169_create_dev_data(dev);
+	if (rtl8169 == NULL) {
+		ddf_msg(LVL_ERROR, "Not enough memory for initializing %s.", ddf_dev_get_name(dev));
+		return ENOMEM;
+	}
+
+	ret = rtl8169_get_resource_info(dev);
+	if (ret != EOK) {
+		ddf_msg(LVL_ERROR, "Can't obtain H/W resources information");
+		goto failed;
+	}
+
+	ddf_msg(LVL_DEBUG, "The device is initialized");
+	return ret;
+	
+failed:
+	ddf_msg(LVL_ERROR, "The device initialization failed");
+//	rtl8139_dev_cleanup(dev);
+	return ret;
+
+}
+
+inline static int rtl8169_register_int_handler(nic_t *nic_data)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	rtl8169_irq_code.ranges[0].base = (uintptr_t) rtl8169->regs;
+	rtl8169_irq_code.cmds[0].addr = rtl8169->regs + ISR;
+	rtl8169_irq_code.cmds[2].addr = rtl8169->regs + ISR;
+	rtl8169_irq_code.cmds[3].addr = rtl8169->regs + IMR;
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
+	    rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code);
+
+	return rc;
+}
+
+static int rtl8169_dev_add(ddf_dev_t *dev)
+{
+	ddf_fun_t *fun;
+	nic_address_t nic_addr;
+	int rc;
+
+	assert(dev);
+	ddf_msg(LVL_NOTE, "RTL8169_dev_add %s (handle = %zu)",
+	    ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
+
+
+	/* Init structures */
+	rc = rtl8169_dev_initialize(dev);
+	if (rc != EOK)
+		return rc;
+
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	/* Get PCI VID & PID */
+	rc = pci_config_space_read_16(ddf_dev_parent_sess_get(dev),
+	    PCI_VENDOR_ID, &rtl8169->pci_vid);
+	if (rc != EOK)
+		return rc;
+
+	rc = pci_config_space_read_16(ddf_dev_parent_sess_get(dev),
+	    PCI_DEVICE_ID, &rtl8169->pci_pid);
+	if (rc != EOK)
+		return rc;
+
+	/* Map register space */
+	rc = pio_enable(rtl8169->regs_phys, RTL8169_IO_SIZE, &rtl8169->regs);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Cannot map register space for device %s.",
+		    ddf_dev_get_name(dev));
+		goto err_destroy;
+	}
+
+	/* Read MAC address and print it */
+	rtl8169_get_hwaddr(rtl8169, &nic_addr);
+	ddf_msg(LVL_NOTE, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
+	    nic_addr.address[0], nic_addr.address[1],
+	    nic_addr.address[2], nic_addr.address[3],
+	    nic_addr.address[4], nic_addr.address[5]);
+
+	rc = nic_report_address(nic_data, &nic_addr);
+	if (rc != EOK)
+		goto err_pio;
+
+	rc = rtl8169_register_int_handler(nic_data);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%d)", rc);
+		goto err_irq;
+
+	}
+
+	ddf_msg(LVL_DEBUG, "Interrupt handler installed");
+
+	uint8_t cr_value = pio_read_8(rtl8169->regs + CR);
+	pio_write_8(rtl8169->regs + CR, cr_value | CR_TE | CR_RE);
+
+	fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
+	if (fun == NULL) {
+		ddf_msg(LVL_ERROR, "Failed creating device function");
+		goto err_srv;
+	}
+
+	nic_set_ddf_fun(nic_data, fun);
+	ddf_fun_set_ops(fun, &rtl8169_dev_ops);
+//	ddf_fun_data_implant(fun, nic_data);
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding device function");
+		goto err_fun_create;
+	}
+
+	rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding function to category");
+		goto err_fun_bind;
+	}
+	
+	ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
+	    ddf_dev_get_name(dev));
+	return EOK;
+
+err_fun_bind:
+	ddf_fun_unbind(fun);
+err_fun_create:
+	ddf_fun_destroy(fun);
+err_srv:
+	/* XXX Disconnect from services */
+err_irq:
+	//unregister_interrupt_handler(dev, rtl8169->irq);
+err_pio:
+err_destroy:
+	//rtl8169_dev_cleanup(dev);
+	return rc;
+
+	return EOK;
+}
+
+static int rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
+{
+	nic_t *nic_data = nic_get_from_ddf_fun(fun);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+	int rc;
+
+	fibril_mutex_lock(&rtl8169->rx_lock);
+	fibril_mutex_lock(&rtl8169->tx_lock);
+
+	rc = nic_report_address(nic_data, addr);
+	if (rc != EOK)
+		return rc;
+
+	rtl8169_set_hwaddr(rtl8169, addr);
+
+	fibril_mutex_unlock(&rtl8169->rx_lock);
+	fibril_mutex_unlock(&rtl8169->tx_lock);
+
+	return EOK;
+}
+
+static int rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
+{
+	nic_t *nic_data = nic_get_from_ddf_fun(fun);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Unknown");
+	str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "Unknown");
+
+	if (rtl8169->pci_vid == PCI_VID_REALTEK)
+		str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Realtek");
+	
+	if (rtl8169->pci_vid == PCI_VID_DLINK)
+		str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "D-Link");
+	
+	if (rtl8169->pci_pid == 0x8168)
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8168");
+	
+	if (rtl8169->pci_pid == 0x8169)
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8169");
+
+	if (rtl8169->pci_pid == 0x8110)
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8110");
+
+	return EOK;
+}
+
+static int rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
+
+	if (phystatus & PHYSTATUS_LINK)
+		*state = NIC_CS_PLUGGED;
+	else
+		*state = NIC_CS_UNPLUGGED;
+
+	return EOK;
+}
+
+static int rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
+
+	*duplex = phystatus & PHYSTATUS_FDX
+	    ? NIC_CM_FULL_DUPLEX : NIC_CM_HALF_DUPLEX;
+
+	if (phystatus & PHYSTATUS_10M)
+		*speed = 10;
+
+	if (phystatus & PHYSTATUS_100M)
+		*speed = 100;
+
+	if (phystatus & PHYSTATUS_1000M)
+		*speed = 1000;
+
+	*role = NIC_ROLE_UNKNOWN;
+	return EOK;
+}
+
+static int rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr;
+
+	if (speed != 10 && speed != 100 && speed != 1000)
+		return EINVAL;
+
+ 	if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
+		return EINVAL;
+
+	bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+	bmcr &= ~(BMCR_DUPLEX | BMCR_SPD_100 | BMCR_SPD_1000);
+	
+	/* Disable autonegotiation */
+	bmcr &= ~BMCR_AN_ENABLE;
+
+	if (duplex == NIC_CM_FULL_DUPLEX)
+		bmcr |= BMCR_DUPLEX;
+
+	if (speed == 100)
+		bmcr |= BMCR_SPD_100;
+
+	if (speed == 1000)
+		bmcr |= BMCR_SPD_1000;
+
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
+	return EOK;
+}
+
+static int rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send, 
+    nic_result_t *we_receive, uint16_t *time)
+{
+	return EOK;
+}
+
+static int rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive, 
+    uint16_t time)
+{
+	return EOK;
+}
+
+static int rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+	uint16_t anar = ANAR_SELECTOR;
+
+	if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
+		anar |= ANAR_10_FD;
+	if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
+		anar |= ANAR_10_HD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
+		anar |= ANAR_100TX_FD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
+		anar |= ANAR_100TX_HD;
+	if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
+		anar |= ANAR_PAUSE;
+
+	bmcr |= BMCR_AN_ENABLE;
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
+	rtl8169_mii_write(rtl8169, MII_ANAR, anar);
+
+	return EOK;
+}
+
+static int rtl8169_autoneg_disable(ddf_fun_t *fun)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+
+	bmcr &= ~BMCR_AN_ENABLE;
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
+
+	return EOK;
+}
+
+static int rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
+    uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result)
+{
+	return EOK;
+}
+
+static int rtl8169_autoneg_restart(ddf_fun_t *fun)
+{
+	rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
+
+	bmcr |= BMCR_AN_ENABLE;
+	rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
+	return EOK;
+}
+
+static int rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
+{
+	return EOK;
+}
+
+static int rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode)
+{
+	return EOK;
+}
+
+static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
+    unsigned int last)
+{
+	rtl8169_descr_t *descr;
+	uint64_t buff_phys;
+	unsigned int i = first;
+
+	for (;;) {
+		descr = &rtl8169->rx_ring[i];
+		buff_phys = rtl8169->rx_buff_phys + (BUFFER_SIZE * i);
+		descr->control = BUFFER_SIZE | CONTROL_OWN;
+		descr->buf_low = buff_phys & 0xffffffff;
+		descr->buf_high = (buff_phys >> 32) & 0xffffffff;
+
+		if (i == RX_BUFFERS_COUNT - 1)
+			descr->control |= CONTROL_EOR;
+
+		if (i == last)
+			break;
+
+		i = (i + 1) % RX_BUFFERS_COUNT;
+	}
+}
+
+static int rtl8169_on_activated(nic_t *nic_data)
+{
+	int rc;
+	uint64_t tmp;
+
+	ddf_msg(LVL_NOTE, "Activating device");
+
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	/* Reset card */
+	pio_write_8(rtl8169->regs + CONFIG0, 0);
+	rtl8169_reset(rtl8169);
+
+	/* Allocate buffers */
+	rc = rtl8169_allocate_buffers(rtl8169);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error allocating buffers: %d", rc);
+		return 0;
+	}
+
+	/* Initialize RX ring */
+	rtl8169_rx_ring_refill(rtl8169, 0, RX_BUFFERS_COUNT - 1);
+
+	/* Write address of descriptor as start of TX ring */
+	tmp = rtl8169->tx_ring_phys;
+	pio_write_32(rtl8169->regs + TNPDS, tmp & 0xffffffff);
+	pio_write_32(rtl8169->regs + TNPDS + 4, (tmp >> 32) & 0xffffffff);
+	rtl8169->tx_head = 0;
+	rtl8169->tx_tail = 0;
+	rtl8169->tx_ring[15].control = CONTROL_EOR;
+
+	/* Write RX ring address */
+	tmp = rtl8169->rx_ring_phys;
+	pio_write_32(rtl8169->regs + RDSAR, tmp & 0xffffffff);
+	pio_write_32(rtl8169->regs + RDSAR + 4, (tmp >> 32) & 0xffffffff);
+	rtl8169->rx_head = 0;
+	rtl8169->rx_tail = 0;
+
+	/* Clear pending interrupts */
+	pio_write_16(rtl8169->regs + ISR, 0xffff);
+
+	/* Enable TX and RX */
+	uint8_t cr = pio_read_8(rtl8169->regs + CR);
+	cr |= CR_TE | CR_RE;
+	pio_write_8(rtl8169->regs + CR, cr);
+	pio_write_32(rtl8169->regs + MAR0, 0xffffffff);
+	pio_write_32(rtl8169->regs + MAR0 + 4, 0xffffffff);
+
+	/* Configure Receive Control Register */
+	uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
+	rcr |= RCR_ACCEPT_ALL_PHYS | RCR_ACCEPT_PHYS_MATCH \
+	    | RCR_ACCEPT_BROADCAST | RCR_ACCEPT_ERROR \
+	    | RCR_ACCEPT_RUNT;
+	pio_write_32(rtl8169->regs + RCR, rcr);
+	pio_write_16(rtl8169->regs + RMS, BUFFER_SIZE);
+
+	ddf_msg(LVL_NOTE, "RCR: 0x%08x", pio_read_32(rtl8169->regs + RCR));
+
+
+	pio_write_16(rtl8169->regs + IMR, 0xffff);
+	irc_enable_interrupt(rtl8169->irq);
+
+	return EOK;
+}
+
+static int rtl8169_on_stopped(nic_t *nic_data)
+{
+	ddf_msg(LVL_NOTE, "Stopping device");
+	return EOK;
+}
+
+inline static void rtl8169_reset(rtl8169_t *rtl8169)
+{
+	pio_write_8(rtl8169->regs + CR, CR_RST);
+	memory_barrier();
+	while (pio_read_8(rtl8169->regs + CR) & CR_RST) {
+		usleep(1);
+		read_barrier();
+	}
+}
+
+static void rtl8169_link_change(ddf_dev_t *dev)
+{
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
+
+	if (phystatus & PHYSTATUS_LINK) {
+		ddf_msg(LVL_NOTE, "%s: Link up", ddf_dev_get_name(dev));
+
+		int speed;
+		const char *fdx = phystatus & PHYSTATUS_FDX ? "full duplex" : "half duplex";
+
+		if (phystatus & PHYSTATUS_10M)
+			speed = 10;
+
+		if (phystatus & PHYSTATUS_100M)
+			speed = 100;
+
+		if (phystatus & PHYSTATUS_1000M)
+			speed = 1000;
+
+		ddf_msg(LVL_NOTE, "%s: Speed %dMbit/s, %s", ddf_dev_get_name(dev), speed, fdx);
+	} else {
+		ddf_msg(LVL_NOTE, "%s: Link down", ddf_dev_get_name(dev));
+	}
+
+}
+
+static int rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count)
+{
+	return EOK;
+}
+
+static int rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count)
+{
+	return EOK;
+}
+
+static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
+{
+	return EOK;
+}
+
+static void rtl8169_transmit_done(ddf_dev_t *dev)
+{
+	unsigned int tail, head;
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+	rtl8169_descr_t *descr;
+
+	ddf_msg(LVL_NOTE, "rtl8169_transmit_done()");
+
+	fibril_mutex_lock(&rtl8169->tx_lock);
+
+	head = rtl8169->tx_head;
+	tail = rtl8169->tx_tail;
+
+	while (tail != head) {
+		descr = &rtl8169->tx_ring[tail];
+		descr->control &= (~CONTROL_OWN);
+		write_barrier();
+		ddf_msg(LVL_NOTE, "TX status for descr %d: 0x%08x", tail, descr->control);
+	
+		tail = (tail + 1) % TX_BUFFERS_COUNT;
+	}
+
+	rtl8169->tx_tail = tail;
+
+	fibril_mutex_unlock(&rtl8169->tx_lock);
+}
+
+static void rtl8169_receive_done(ddf_dev_t *dev)
+{
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+	rtl8169_descr_t *descr;
+	nic_frame_list_t *frames = nic_alloc_frame_list();
+	nic_frame_t *frame;
+	void *buffer;
+	unsigned int tail, fsidx = 0;
+	int frame_size;
+
+	ddf_msg(LVL_NOTE, "rtl8169_receive_done()");
+
+	fibril_mutex_lock(&rtl8169->rx_lock);
+
+	tail = rtl8169->rx_tail;
+
+	for (;;) {
+		descr = &rtl8169->rx_ring[tail];
+
+		if (descr->control & CONTROL_OWN)
+			break;
+
+		if (descr->control & RXSTATUS_RES) {
+			ddf_msg(LVL_NOTE, "error at slot %d: 0x%08x\n", tail, descr->control);
+			tail = (tail + 1) % RX_BUFFERS_COUNT;
+			continue;
+		}
+
+		if (descr->control & CONTROL_FS)
+			fsidx = tail;
+		
+		if (descr->control & CONTROL_LS) {
+
+			ddf_msg(LVL_NOTE, "received message at slot %d, control 0x%08x", tail, descr->control);
+
+			if (fsidx != tail)
+				ddf_msg(LVL_WARN, "single frame spanning multiple descriptors");
+
+			frame_size = descr->control & 0x1fff;
+			buffer = rtl8169->rx_buff + (BUFFER_SIZE * tail);
+			frame = nic_alloc_frame(nic_data, frame_size);
+			memcpy(frame->data, buffer, frame_size);
+			nic_frame_list_append(frames, frame);
+		}
+
+		tail = (tail + 1) % RX_BUFFERS_COUNT;
+	}
+
+	rtl8169_rx_ring_refill(rtl8169, rtl8169->rx_tail, tail);
+
+	rtl8169->rx_tail = tail;
+
+	fibril_mutex_unlock(&rtl8169->rx_lock);
+
+	nic_received_frame_list(nic_data, frames);
+
+}
+
+static void rtl8169_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	assert(dev);
+	assert(icall);
+
+	uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall) & INT_KNOWN;
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	ddf_msg(LVL_NOTE, "rtl8169_irq_handler(): isr=0x%04x", isr);
+	pio_write_16(rtl8169->regs + IMR, 0xffff);
+
+	while (isr != 0) {
+		ddf_msg(LVL_DEBUG, "irq handler: remaining isr=0x%04x", isr);
+
+		/* Packet underrun or link change */
+		if (isr & INT_PUN) {
+			rtl8169_link_change(dev);
+			pio_write_16(rtl8169->regs + ISR, INT_PUN);
+		}
+
+		/* Transmit notification */
+		if (isr & (INT_TER | INT_TOK | INT_TDU)) {
+			rtl8169_transmit_done(dev);
+			pio_write_16(rtl8169->regs + ISR, (INT_TER | INT_TOK | INT_TDU));
+		}
+
+		/* Receive underrun */
+		if (isr & INT_RXOVW) {
+			/* just ack.. */
+			pio_write_16(rtl8169->regs + ISR, INT_RXOVW);
+		}
+
+		if (isr & INT_SERR) {
+			ddf_msg(LVL_ERROR, "System error interrupt");
+			pio_write_16(rtl8169->regs + ISR, INT_SERR);
+		}
+
+		if (isr & (INT_RER | INT_ROK)) {
+			rtl8169_receive_done(dev);
+			pio_write_16(rtl8169->regs + ISR, (INT_RER | INT_ROK));
+		}
+
+		isr = pio_read_16(rtl8169->regs + ISR) & INT_KNOWN;
+	}
+
+	pio_write_16(rtl8169->regs + ISR, 0xffff);
+}
+
+static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size)
+{
+	rtl8169_descr_t *descr, *prev;
+	unsigned int head, tail;
+	void *buff;
+	uint64_t buff_phys;
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+
+	if (size > RTL8169_FRAME_MAX_LENGTH) {
+		ddf_msg(LVL_ERROR, "Send frame: frame too long, %zu bytes",
+		    size);
+		nic_report_send_error(nic_data, NIC_SEC_OTHER, 1);
+	}
+
+	fibril_mutex_lock(&rtl8169->tx_lock);
+
+	ddf_msg(LVL_NOTE, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
+	    size, rtl8169->tx_head, rtl8169->tx_tail);
+
+	head = rtl8169->tx_head;
+	tail = rtl8169->tx_tail;
+
+	if ((head + 1) % TX_BUFFERS_COUNT == tail) {
+		/* Queue is full */
+		ddf_msg(LVL_WARN, "TX queue full!");
+		nic_set_tx_busy(nic_data, 1);
+	}
+
+	/* Calculate address of next free buffer and descriptor */
+	buff = rtl8169->tx_buff + (BUFFER_SIZE * head);
+	buff_phys = rtl8169->tx_buff_phys + (BUFFER_SIZE * head);
+
+	/* Copy frame */
+	memcpy(buff, data, size);
+
+	/* Setup descriptor */
+	descr = &rtl8169->tx_ring[head];
+	prev = &rtl8169->tx_ring[(head - 1) % TX_BUFFERS_COUNT];
+
+	ddf_msg(LVL_NOTE, "current_descr=%p, prev_descr=%p", descr, prev);
+
+	descr->control = CONTROL_OWN | CONTROL_FS | CONTROL_LS;
+	descr->control |= size & 0xffff;
+	descr->vlan = 0;
+	descr->buf_low = buff_phys & 0xffffffff;
+	descr->buf_high = (buff_phys >> 32) & 0xffffffff;
+
+	if (head == TX_BUFFERS_COUNT - 1)
+		descr->control |= CONTROL_EOR;
+
+	rtl8169->tx_head = (head + 1) % TX_BUFFERS_COUNT;
+
+	ddf_msg(LVL_DEBUG, "control: 0x%08x", descr->control);
+
+	write_barrier();
+
+	/* Notify NIC of pending packets */
+	pio_write_8(rtl8169->regs + TPPOLL, TPPOLL_NPQ);
+	write_barrier();
+
+	fibril_mutex_unlock(&rtl8169->tx_lock);
+}
+
+static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
+{
+	int i;
+
+	assert(rtl8169);
+	assert(addr);
+
+	for (i = 0; i < 6; i++)
+		addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
+}
+
+static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr)
+{
+	int i;
+
+	assert(rtl8169);
+	assert(addr);
+
+	for (i = 0; i < 6; i++)
+		pio_write_8(rtl8169->regs + MAC0 + i, addr->address[i]);
+}
+
+static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr)
+{
+	uint32_t phyar;
+
+	phyar = PHYAR_RW_READ
+	    | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
+
+	pio_write_32(rtl8169->regs + PHYAR, phyar);
+
+	do {
+		phyar = pio_read_32(rtl8169->regs + PHYAR);
+		usleep(20);
+	} while ((phyar & PHYAR_RW_WRITE) == 0);
+
+	return phyar & PHYAR_DATA_MASK;
+}
+
+static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value)
+{
+	uint32_t phyar;
+
+	phyar = PHYAR_RW_WRITE
+	    | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT)
+	    | (value & PHYAR_DATA_MASK);
+
+	pio_write_32(rtl8169->regs + PHYAR, phyar);
+
+	do {
+		phyar = pio_read_32(rtl8169->regs + PHYAR);
+		usleep(20);
+	} while ((phyar & PHYAR_RW_WRITE) != 0);
+
+	usleep(20);
+}
+
+/** Main function of RTL8169 driver
+*
+ *  Just initialize the driver structures and
+ *  put it into the device drivers interface
+ */
+int main(void)
+{
+	int rc = nic_driver_init(NAME);
+	if (rc != EOK)
+		return rc;
+	nic_driver_implement(
+		&rtl8169_driver_ops, &rtl8169_dev_ops, &rtl8169_nic_iface);
+
+	ddf_log_init(NAME);
+	ddf_msg(LVL_NOTE, "HelenOS RTL8169 driver started");
+	return ddf_driver_main(&rtl8169_driver);
+}
Index: uspace/drv/nic/rtl8169/driver.h
===================================================================
--- uspace/drv/nic/rtl8169/driver.h	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
+++ uspace/drv/nic/rtl8169/driver.h	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * Copyright (c) 2014 Agnieszka Tabaka
+ * 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.
+ */
+
+#ifndef RTL8169_DRIVER_H_
+#define RTL8169_DRIVER_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+#include "defs.h"
+
+/** The driver name */
+#define NAME  "rtl8169"
+
+#define	TX_BUFFERS_COUNT	16
+#define	RX_BUFFERS_COUNT	16
+#define	BUFFER_SIZE		2048
+
+#define	TX_RING_SIZE		(sizeof(rtl8169_descr_t) * TX_BUFFERS_COUNT)
+#define	RX_RING_SIZE		(sizeof(rtl8169_descr_t) * RX_BUFFERS_COUNT)
+#define	TX_BUFFERS_SIZE		(BUFFER_SIZE * TX_BUFFERS_COUNT)
+#define	RX_BUFFERS_SIZE		(BUFFER_SIZE * RX_BUFFERS_COUNT)
+
+/** RTL8139 device data */
+typedef struct rtl8169_data {
+	/** I/O address of the device */
+	void *regs_phys;
+	/** Mapped I/O port */
+	void *regs;
+	/** The irq assigned */
+	int irq;
+	/** PCI Vendor and Product ids */
+	uint16_t pci_vid;
+	uint16_t pci_pid;
+	/** Mask of the turned interupts (IMR value) */
+	uint16_t int_mask;
+	/** TX ring */
+	uintptr_t tx_ring_phys;
+	rtl8169_descr_t *tx_ring;
+	unsigned int tx_head;
+	unsigned int tx_tail;
+	/** RX ring */
+	uintptr_t rx_ring_phys;
+	rtl8169_descr_t *rx_ring;
+	unsigned int rx_head;
+	unsigned int rx_tail;
+	/** TX buffers */
+	uintptr_t tx_buff_phys;
+	void *tx_buff;
+	/** RX buffers */
+	uintptr_t rx_buff_phys;
+	void *rx_buff;
+	/** The nubmer of the next buffer to use, index = tx_next % TX_BUFF_COUNT */
+	size_t tx_next;
+	/** The number of the first used buffer in the row
+	 *
+	 *  tx_used is in the interval tx_next - TX_BUFF_COUNT and tx_next:
+	 *  	tx_next - TX_BUFF_COUNT: there is no useable Tx descriptor
+	 *  	tx_next: all Tx descriptors are can be used
+	 */
+	size_t tx_used;
+
+	/** Lock for receiver */
+	fibril_mutex_t rx_lock;
+	/** Lock for transmitter */
+	fibril_mutex_t tx_lock;
+
+	/** Backward pointer to nic_data */
+	nic_t *nic_data;
+
+} rtl8169_t;
+
+#endif
Index: uspace/drv/nic/rtl8169/rtl8169.ma
===================================================================
--- uspace/drv/nic/rtl8169/rtl8169.ma	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
+++ uspace/drv/nic/rtl8169/rtl8169.ma	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -0,0 +1,5 @@
+10 pci/ven=10ec&dev=8169
+10 pci/ven=10ec&dev=8168
+10 pci/ven=10ec&dev=8167
+10 pci/ven=10ec&dev=8110
+10 pci/ven=1186&dev=4300
Index: uspace/lib/drv/generic/remote_nic.c
===================================================================
--- uspace/lib/drv/generic/remote_nic.c	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/lib/drv/generic/remote_nic.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -288,16 +288,16 @@
 	async_exch_t *exch = async_exchange_begin(dev_sess);
 	
-	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
-	    NIC_GET_DEVICE_INFO);
-	if (rc != EOK) {
-		async_exchange_end(exch);
+	aid_t aid = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_DEVICE_INFO, NULL);
+	int rc = async_data_read_start(exch, device_info, sizeof(nic_device_info_t));
+	async_exchange_end(exch);
+
+	sysarg_t res;
+	async_wait_for(aid, &res);
+	
+	if (rc != EOK)
 		return rc;
-	}
-	
-	rc = async_data_read_start(exch, device_info, sizeof(nic_device_info_t));
-	
-	async_exchange_end(exch);
-	
-	return rc;
+	
+	return (int) res;
 }
 
Index: uspace/lib/drv/include/pci_dev_iface.h
===================================================================
--- uspace/lib/drv/include/pci_dev_iface.h	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/lib/drv/include/pci_dev_iface.h	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -40,4 +40,5 @@
 #include "ddf/driver.h"
 
+#define PCI_VENDOR_ID  0x00
 #define PCI_DEVICE_ID  0x02
 
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/lib/nic/src/nic_driver.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -47,4 +47,6 @@
 #include <ops/nic.h>
 #include <errno.h>
+
+#include <io/log.h>
 
 #include "nic_driver.h"
@@ -436,4 +438,6 @@
 		int rc = nic_ev_addr_changed(nic_data->client_session,
 		    address);
+		log_msg(LOG_DEFAULT, LVL_WARN, "rc=%d", rc);
+
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&nic_data->main_lock);
Index: uspace/lib/nic/src/nic_impl.c
===================================================================
--- uspace/lib/nic/src/nic_impl.c	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/lib/nic/src/nic_impl.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -179,4 +179,5 @@
 
 	nic_data->send_frame(nic_data, data, size);
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
 	return EOK;
 }
Index: uspace/srv/net/ethip/ethip_nic.c
===================================================================
--- uspace/srv/net/ethip/ethip_nic.c	(revision 7eb6c96392769a3bab70af54ff262130f072c967)
+++ uspace/srv/net/ethip/ethip_nic.c	(revision 1f1fa6420a71dbef5d82ed476f6f5411487e7144)
@@ -231,6 +231,20 @@
     ipc_call_t *call)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_changed()");
-	async_answer_0(callid, ENOTSUP);
+	uint8_t *addr;
+	size_t size;
+	int rc;
+
+	rc = async_data_write_accept((void **)&addr, false, 0, 0, 0, &size);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "data_write_accept() failed");
+		return;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_nic_addr_changed(): "
+	    "new addr=%02x:%02x:%02x:%02x:%02x:%02x",
+	    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+	free(addr);
+	async_answer_0(callid, EOK);
 }
 
@@ -295,4 +309,5 @@
 			break;
 		default:
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "unknown IPC method: %d", IPC_GET_IMETHOD(call));
 			async_answer_0(callid, ENOTSUP);
 		}
