Index: uspace/drv/bus/usb/ar9271/ar9271.c
===================================================================
--- uspace/drv/bus/usb/ar9271/ar9271.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/ar9271.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -101,4 +101,6 @@
 /* IEEE802.11 callbacks */
 static int ar9271_ieee80211_start(ieee80211_dev_t *ieee80211_dev);
+static int ar9271_ieee80211_tx_handler(ieee80211_dev_t *ieee80211_dev,
+	void *buffer, size_t buffer_size);
 
 static driver_ops_t ar9271_driver_ops = {
@@ -112,45 +114,94 @@
 
 static ieee80211_ops_t ar9271_ieee80211_ops = {
-	.start = ar9271_ieee80211_start
-};
-
-static int ar9271_set_rx_filter(ar9271_t *ar9271)
-{
-	uint32_t filter_bits;
-	int rc = wmi_reg_read(ar9271->htc_device, AR9271_RX_FILTER, 
-		&filter_bits);
-	if(rc != EOK) {
-		usb_log_error("Failed to read RX filter.\n");
-		return EINVAL;
-	}
-	
-	/* TODO: Do proper filtering here. */
-	
-	filter_bits |= AR9271_RX_FILTER_UNI | AR9271_RX_FILTER_MULTI | 
-		AR9271_RX_FILTER_BROAD | AR9271_RX_FILTER_PROMISCUOUS;
-	
-	rc = wmi_reg_write(ar9271->htc_device, AR9271_RX_FILTER, filter_bits);
-	if(rc != EOK) {
-		usb_log_error("Failed to write RX filter.\n");
-		return EINVAL;
-	}
-	
-	return EOK;
-}
-
-static int ar9271_rx_init(ar9271_t *ar9271)
-{
-	int rc = wmi_reg_write(ar9271->htc_device, AR9271_COMMAND, 
-		AR9271_COMMAND_RX_ENABLE);
-	if(rc != EOK) {
-		usb_log_error("Failed to send RX enable command.\n");
-		return EINVAL;
-	}
-	
-	rc = ar9271_set_rx_filter(ar9271);
-	if(rc != EOK) {
-		usb_log_error("Failed to set RX filtering.\n");
-		return EINVAL;
-	}
+	.start = ar9271_ieee80211_start,
+	.tx_handler = ar9271_ieee80211_tx_handler
+};
+
+static int ar9271_ieee80211_tx_handler(ieee80211_dev_t *ieee80211_dev,
+	void *buffer, size_t buffer_size)
+{
+	/* TODO: Process TX message properly */
+	
+	size_t complete_size, offset;
+	void *complete_buffer;
+	int endpoint;
+	
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_dev->driver_data;
+	
+	ieee80211_header_t *ieee80211_header = (ieee80211_header_t *) buffer;
+	
+	if(ieee80211_is_data_frame(ieee80211_header)) {
+		offset = sizeof(htc_frame_header_t);
+		complete_size = buffer_size + offset;
+		complete_buffer = malloc(complete_size);
+		endpoint = ar9271->htc_device->endpoints.data_be_endpoint;
+	} else {
+		offset = sizeof(htc_tx_management_header_t) +
+			sizeof(htc_frame_header_t);
+		complete_size = buffer_size + offset;
+		complete_buffer = malloc(complete_size);
+		endpoint = ar9271->htc_device->endpoints.mgmt_endpoint;
+	}
+	
+	/* Copy IEEE802.11 data to new allocated buffer with HTC headers. */
+	memcpy(complete_buffer + offset, buffer, buffer_size);
+	
+	htc_send_data_message(ar9271->htc_device, complete_buffer,
+		complete_size, endpoint);
+	
+	free(complete_buffer);
+	
+	return EOK;
+}
+
+static int ar9271_data_polling(void *arg)
+{
+	ar9271_t *ar9271 = (ar9271_t *) arg;
+	size_t buffer_size = ar9271->ath_device->data_response_length;
+	void *buffer = malloc(buffer_size);
+	
+	while(true) {
+		int rc = 
+		htc_read_data_message(ar9271->htc_device, buffer, buffer_size,
+			NULL);
+		usb_log_info("RC is %d.\n", rc);
+		
+		/* TODO: Process RX message */
+	}
+	
+	return EOK;
+}
+
+static int ar9271_diag_polling(void *arg)
+{
+	ar9271_t *ar9271 = (ar9271_t *) arg;
+	
+	while(true) {
+		uint32_t result;
+		wmi_reg_read(ar9271->htc_device, 0x80F0, &result);
+		usb_log_info("RX count: %x\n", result);
+		wmi_reg_read(ar9271->htc_device, 0x8098, &result);
+		usb_log_info("Beacon count: %x\n", result);
+		sleep(1);
+	}
+	
+	return EOK;
+}
+
+static int ar9271_register_polling_fibrils(ar9271_t *ar9271)
+{
+	/* Add data polling fibril. */
+	fid_t fibril = fibril_create(ar9271_data_polling, ar9271);
+	if (fibril == 0) {
+		return ENOMEM;
+	}
+	fibril_add_ready(fibril);
+	
+	/* Add debug polling fibril. */
+	fibril = fibril_create(ar9271_diag_polling, ar9271);
+	if (fibril == 0) {
+		return ENOMEM;
+	}
+	fibril_add_ready(fibril);
 	
 	return EOK;
@@ -165,5 +216,5 @@
 	if(rc != EOK) {
 		usb_log_error("Failed to flush receiving buffer.\n");
-		return EINVAL;
+		return rc;
 	}
 	
@@ -171,5 +222,5 @@
 	if(rc != EOK) {
 		usb_log_error("Failed to do HW reset.\n");
-		return EINVAL;
+		return rc;
 	}
 	
@@ -179,5 +230,5 @@
 	if(rc != EOK) {
 		usb_log_error("Failed to set HTC mode.\n");
-		return EINVAL;
+		return rc;
 	}
 	
@@ -186,5 +237,5 @@
 	if(rc != EOK) {
 		usb_log_error("Failed to send ath init command.\n");
-		return EINVAL;
+		return rc;
 	}
 	
@@ -193,11 +244,23 @@
 	if(rc != EOK) {
 		usb_log_error("Failed to send receiving init command.\n");
-		return EINVAL;
-	}
-	
-	rc = ar9271_rx_init(ar9271);
+		return rc;
+	}
+	
+	rc = hw_rx_init(ar9271);
 	if(rc != EOK) {
 		usb_log_error("Failed to initialize RX.\n");
-		return EINVAL;
+		return rc;
+	}
+	
+	rc = htc_init_new_vif(ar9271->htc_device);
+	if(rc != EOK) {
+		usb_log_error("Failed to initialize new VIF.\n");
+		return rc;
+	}
+	
+	rc = ar9271_register_polling_fibrils(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to register polling fibrils.\n");
+		return rc;
 	}
 	
@@ -220,5 +283,24 @@
 		free(ar9271->ath_device);
 		usb_log_error("Failed to initialize ath device.\n");
-		return EINVAL;
+		return rc;
+	}
+	
+	/* IEEE 802.11 framework structure initialization. */
+	ar9271->ieee80211_dev = calloc(1, sizeof(ieee80211_dev_t));
+	if (!ar9271->ieee80211_dev) {
+		free(ar9271->ath_device);
+		usb_log_error("Failed to allocate memory for IEEE80211 device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	rc = ieee80211_device_init(ar9271->ieee80211_dev, ar9271, 
+		ar9271->ddf_dev);
+	if(rc != EOK) {
+		free(ar9271->ieee80211_dev);
+		free(ar9271->ath_device);
+		usb_log_error("Failed to initialize IEEE80211 device structure."
+			"\n");
+		return rc;
 	}
 		
@@ -226,4 +308,5 @@
 	ar9271->htc_device = calloc(1, sizeof(htc_device_t));
 	if(!ar9271->htc_device) {
+		free(ar9271->ieee80211_dev);
 		free(ar9271->ath_device);
 		usb_log_error("Failed to allocate memory for HTC device "
@@ -232,31 +315,12 @@
 	}
 	
-	rc = htc_device_init(ar9271->ath_device, ar9271->htc_device);
+	rc = htc_device_init(ar9271->ath_device, ar9271->ieee80211_dev, 
+		ar9271->htc_device);
 	if(rc != EOK) {
 		free(ar9271->htc_device);
+		free(ar9271->ieee80211_dev);
 		free(ar9271->ath_device);
 		usb_log_error("Failed to initialize HTC device structure.\n");
-		return EINVAL;
-	}
-	
-	/* IEEE 802.11 framework structure initialization. */
-	ar9271->ieee80211_dev = calloc(1, sizeof(ieee80211_dev_t));
-	if (!ar9271->ieee80211_dev) {
-		free(ar9271->htc_device);
-		free(ar9271->ath_device);
-		usb_log_error("Failed to allocate memory for IEEE80211 device "
-		    "structure.\n");
-		return ENOMEM;
-	}
-	
-	rc = ieee80211_device_init(ar9271->ieee80211_dev, ar9271, 
-		ar9271->ddf_dev);
-	if(rc != EOK) {
-		free(ar9271->ieee80211_dev);
-		free(ar9271->htc_device);
-		free(ar9271->ath_device);
-		usb_log_error("Failed to initialize IEEE80211 device structure."
-			"\n");
-		return EINVAL;
+		return rc;
 	}
 	
Index: uspace/drv/bus/usb/ar9271/ar9271.h
===================================================================
--- uspace/drv/bus/usb/ar9271/ar9271.h	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/ar9271.h	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -40,8 +40,5 @@
 #include "htc.h"
 
-/** Max supported channel frequency. */
-#define AR9271_MAX_CHANNEL 2472
-
-/** Number of transmisson queues */
+/** Number of transmission queues */
 #define AR9271_QUEUES_COUNT 10
 
@@ -83,4 +80,5 @@
 	AR9271_RTC_RC_MAC_COLD = 0x00000002,
 	AR9271_RTC_RC_MASK = 0x00000003,
+	AR9271_RTC_PLL_CONTROL = 0x7014,
 	AR9271_RTC_RESET = 0x7040,
 	AR9271_RTC_STATUS = 0x7044,
@@ -92,4 +90,14 @@
 	AR9271_RTC_FORCE_WAKE_ON_INT = 0x00000002,
 		
+	/* MAC Registers */
+	AR9271_STATION_ID0 = 0x8000,	/**< STA Address Lower 32 Bits */
+	AR9271_STATION_ID1 = 0x8004,	/**< STA Address Upper 16 Bits */
+	AR9271_BSSID0 = 0x8008,			/**< BSSID Lower 32 Bits */
+	AR9271_BSSID1 = 0x800C,			/**< BSSID Upper 16 Bits */
+	AR9271_BSSID_MASK0 = 0x80E0,		/**< BSSID Mask Lower 32 Bits */
+	AR9271_BSSID_MASK1 = 0x80E4,		/**< BSSID Mask Upper 16 Bits */
+	AR9271_STATION_ID1_MASK = 0x0000FFFF,
+		
+	/* RX filtering register */
 	AR9271_RX_FILTER = 0x803C,
 	AR9271_RX_FILTER_UNI = 0x00000001,
@@ -100,15 +108,29 @@
 	AR9271_RX_FILTER_PROMISCUOUS = 0x00000020,
 	AR9271_RX_FILTER_PROBEREQ = 0x00000080,
-		
+	AR9271_RX_FILTER_MYBEACON = 0x00000200,
+		
+	/* Physical layer registers */
 	AR9271_PHY_BASE = 0x9800,
-	AR9271_PHY_ACTIVE = 0x981C,	
+	AR9271_PHY_ACTIVE = 0x981C,
+	AR9271_ADC_CONTROL = 0x982C,
+	AR9271_AGC_CONTROL = 0x9860,
 	AR9271_PHY_MODE = 0xA200,
+	AR9271_PHY_CCK_TX_CTRL = 0xA204,
+	AR9271_PHY_TPCRG1 = 0xA258, 
+	AR9271_CARRIER_LEAK_CONTROL = 0xA358,
+	AR9271_ADC_CONTROL_OFF_PWDADC = 0x00008000,
+	AR9271_AGC_CONTROL_CALIB = 0x00000001,
+	AR9271_AGC_CONTROL_TX_CALIB = 0x00010000,
 	AR9271_PHY_MODE_2G = 0x02,
 	AR9271_PHY_MODE_DYNAMIC = 0x04,
-	AR9271_PHY_CCK_TX_CTRL = 0xA204,
 	AR9271_PHY_CCK_TX_CTRL_JAPAN = 0x00000010,
+	AR9271_PHY_TPCRG1_PD_CALIB = 0x00400000,
+	AR9271_CARRIER_LEAK_CALIB = 0x00000002,
 		
 	AR9271_OPMODE_STATION_AP_MASK =	0x00010000,
 	AR9271_OPMODE_ADHOC_MASK = 0x00020000,
+		
+	AR9271_CLOCK_CONTROL = 0x50040,
+	AR9271_MAX_CPU_CLOCK = 0x304,
 		
 	AR9271_RESET_POWER_DOWN_CONTROL = 0x50044,
@@ -117,12 +139,6 @@
     
 	/* FW Addresses */
-	AR9271_FW_ADDRESS =	0x501000,
-	AR9271_FW_OFFSET =	0x903000,
-	
-	/* MAC Registers */
-	AR9271_STATION_ID0 = 0x8000, /**< STA Address Lower 32 Bits */
-	AR9271_STATION_ID1 = 0x8004, /**< STA Address Upper 16 Bits */
-	AR9271_STATION_BSSID0 = 0x8008, /**< BSSID Lower 32 Bits */
-	AR9271_STATION_BSSID1 = 0x800C, /**< BSSID Upper 16 Bits */
+	AR9271_FW_ADDRESS = 0x501000,
+	AR9271_FW_OFFSET = 0x903000,
 } ar9271_registers_t;
 
@@ -151,3 +167,306 @@
 } ar9271_t;
 
+/**
+ * AR9271 hardware init values.
+ * 
+ * Taken from Linux sources, some values omitted.
+ */
+static const uint32_t ar9271_init_array[][2] = {
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020045},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00004024, 0x0000001f},
+	{0x00004060, 0x00000000},
+	{0x00004064, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000000},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 0x00000000},
+	{0x000080c0, 0x2a80001a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008120, 0x08f04810},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081d0, 0x0000320a},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000040},
+	{0x00008314, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000001},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x00010380},
+	{0x00008344, 0x00581043},
+	{0x00007010, 0x00000030},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafe68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009940, 0x14750604},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x0108ecff},
+	{0x00009968, 0x000003ce},
+	{0x00009970, 0x192bb514},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x2def0400},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x0000a208, 0x803e68c8},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x00206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a244, 0x00000000},
+	{0x0000a248, 0xfffffffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0ccb5380},
+	{0x0000a25c, 0x15151501},
+	{0x0000a260, 0xdfa90f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0ebae9e6},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x0000a3f0, 0x01036a2f},
+	{0x0000a3f4, 0x00000000},
+	{0x0000d270, 0x0d820820},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0}
+};
+
 #endif
Index: uspace/drv/bus/usb/ar9271/ath.h
===================================================================
--- uspace/drv/bus/usb/ar9271/ath.h	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/ath.h	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -48,4 +48,10 @@
 /** Atheros wifi device structure */
 typedef struct ath {
+	/** Maximum length of data response message. */
+	size_t data_response_length;
+	
+	/** Maximum length of control response message. */
+	size_t ctrl_response_length;
+	
 	/** Implementation specific data. */
 	void *specific_data;
Index: uspace/drv/bus/usb/ar9271/ath_usb.c
===================================================================
--- uspace/drv/bus/usb/ar9271/ath_usb.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/ath_usb.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -82,4 +82,7 @@
 	ath_usb->input_ctrl_pipe_number = 2;
 	ath_usb->output_ctrl_pipe_number = 3;
+	
+	ath->ctrl_response_length = 64;
+	ath->data_response_length = 512;
 	
 	ath->specific_data = ath_usb;
Index: uspace/drv/bus/usb/ar9271/htc.c
===================================================================
--- uspace/drv/bus/usb/ar9271/htc.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/htc.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -39,4 +39,6 @@
 #include "wmi.h"
 #include "htc.h"
+#include "nic/nic.h"
+#include "ar9271.h"
 
 /**
@@ -64,6 +66,97 @@
 }
 
-/**
- * Send HTC message to USB device.
+int htc_init_new_vif(htc_device_t *htc_device)
+{
+	htc_vif_msg_t vif_msg;
+	htc_sta_msg_t sta_msg;
+	
+	nic_address_t addr;
+	nic_t *nic = nic_get_from_ddf_dev(htc_device->ieee80211_dev->ddf_dev);
+	nic_query_address(nic, &addr);
+	
+	memcpy(&vif_msg.addr, &addr.address, ETH_ADDR);
+	memcpy(&sta_msg.addr, &addr.address, ETH_ADDR);
+	
+	ieee80211_operating_mode_t op_mode = 
+		htc_device->ieee80211_dev->current_op_mode;
+	
+	switch(op_mode) {
+		case IEEE80211_OPMODE_ADHOC:
+			vif_msg.op_mode = HTC_OPMODE_ADHOC;
+			break;
+		case IEEE80211_OPMODE_AP:
+			vif_msg.op_mode = HTC_OPMODE_AP;
+			break;
+		case IEEE80211_OPMODE_MESH:
+			vif_msg.op_mode = HTC_OPMODE_MESH;
+			break;
+		case IEEE80211_OPMODE_STATION:
+			vif_msg.op_mode = HTC_OPMODE_STATION;
+			break;
+	}
+	
+	vif_msg.index = 0;
+	vif_msg.rts_thres = host2uint16_t_be(HTC_RTS_THRESHOLD);
+	
+	int rc = wmi_send_command(htc_device, WMI_VAP_CREATE, 
+		(uint8_t *) &vif_msg, sizeof(vif_msg), NULL);
+	if(rc != EOK) {
+		usb_log_error("Failed to send VAP create command.\n");
+		return rc;
+	}
+	
+	sta_msg.is_vif_sta = 1;
+	sta_msg.max_ampdu = host2uint16_t_be(HTC_MAX_AMPDU);
+	sta_msg.sta_index = 0;
+	sta_msg.vif_index = 0;
+	
+	rc = wmi_send_command(htc_device, WMI_NODE_CREATE, 
+		(uint8_t *) &sta_msg, sizeof(sta_msg), NULL);
+	if(rc != EOK) {
+		usb_log_error("Failed to send NODE create command.\n");
+		return rc;
+	}
+	
+	/* Write first 4 bytes of MAC address. */
+	uint32_t id0;
+	memcpy(&id0, &addr.address, 4);
+	id0 = host2uint32_t_le(id0);
+	rc = wmi_reg_write(htc_device, AR9271_STATION_ID0, id0);
+	if(rc != EOK)
+		return rc;
+	
+	/* Write last 2 bytes of MAC address (and preserve existing data). */
+	uint32_t id1;
+	rc = wmi_reg_read(htc_device, AR9271_STATION_ID1, &id1);
+	if(rc != EOK)
+		return rc;
+	uint16_t id1_addr;
+	memcpy(&id1_addr, &addr.address[4], 2);
+	id1 = (id1 & ~AR9271_STATION_ID1_MASK) | host2uint16_t_le(id1_addr);
+	rc = wmi_reg_write(htc_device, AR9271_STATION_ID1, id1);
+	if(rc != EOK)
+		return rc;
+	
+	/* TODO: Set BSSID mask for AP mode. */
+	
+	return EOK;
+}
+
+static void htc_config_frame_header(htc_frame_header_t *header, 
+	size_t buffer_size, uint8_t endpoint_id)
+{
+	header->endpoint_id = endpoint_id;
+	header->flags = 0;
+	header->payload_length = 
+		host2uint16_t_be(buffer_size - sizeof(htc_frame_header_t));
+	
+	header->control_bytes[0] = 0x02;
+	header->control_bytes[1] = 0x88;
+	header->control_bytes[2] = 0xFF;
+	header->control_bytes[3] = 0xFF;
+}
+
+/**
+ * Send control HTC message to USB device.
  * 
  * @param htc_device HTC device structure.
@@ -75,17 +168,9 @@
  * @return EOK if succeed, negative error code otherwise.
  */
-int htc_send_message(htc_device_t *htc_device, void *buffer, 
+int htc_send_control_message(htc_device_t *htc_device, void *buffer, 
 	size_t buffer_size, uint8_t endpoint_id)
 {
-	htc_frame_header_t *htc_header = (htc_frame_header_t *) buffer;
-	htc_header->endpoint_id = endpoint_id;
-	htc_header->flags = 0;
-	htc_header->payload_length = 
-		host2uint16_t_be(buffer_size - sizeof(htc_frame_header_t));
-	
-	htc_header->control_bytes[0] = 0x02;
-	htc_header->control_bytes[1] = 0x88;
-	htc_header->control_bytes[2] = 0xFF;
-	htc_header->control_bytes[3] = 0xFF;
+	htc_config_frame_header((htc_frame_header_t *) buffer, buffer_size,
+		endpoint_id);
 	
 	ath_t *ath_device = htc_device->ath_device;
@@ -96,5 +181,28 @@
 
 /**
- * Read HTC message from USB device.
+ * Send data HTC message to USB device.
+ * 
+ * @param htc_device HTC device structure.
+ * @param buffer Buffer with data to be sent to USB device (without HTC frame
+ *              header).
+ * @param buffer_size Size of buffer (including HTC frame header).
+ * @param endpoint_id Destination endpoint.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int htc_send_data_message(htc_device_t *htc_device, void *buffer, 
+	size_t buffer_size, uint8_t endpoint_id)
+{
+	htc_config_frame_header((htc_frame_header_t *) buffer, buffer_size,
+		endpoint_id);
+	
+	ath_t *ath_device = htc_device->ath_device;
+	
+	return ath_device->ops->send_data_message(ath_device, buffer, 
+		buffer_size);
+}
+
+/**
+ * Read HTC data message from USB device.
  * 
  * @param htc_device HTC device structure.
@@ -105,5 +213,24 @@
  * @return EOK if succeed, negative error code otherwise.
  */
-int htc_read_message(htc_device_t *htc_device, void *buffer, 
+int htc_read_data_message(htc_device_t *htc_device, void *buffer, 
+	size_t buffer_size, size_t *transferred_size)
+{
+	ath_t *ath_device = htc_device->ath_device;
+	
+	return ath_device->ops->read_data_message(ath_device, buffer, 
+		buffer_size, transferred_size);
+}
+
+/**
+ * Read HTC control message from USB device.
+ * 
+ * @param htc_device HTC device structure.
+ * @param buffer Buffer where data from USB device will be stored.
+ * @param buffer_size Size of buffer.
+ * @param transferred_size Real size of read data.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int htc_read_control_message(htc_device_t *htc_device, void *buffer, 
 	size_t buffer_size, size_t *transferred_size)
 {
@@ -145,5 +272,5 @@
 	
 	/* Send HTC message. */
-	int rc = htc_send_message(htc_device, buffer, buffer_size,
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size,
 		htc_device->endpoints.ctrl_endpoint);
 	if(rc != EOK) {
@@ -155,9 +282,9 @@
 	free(buffer);
 	
-	buffer_size = MAX_RESPONSE_LENGTH;
+	buffer_size = htc_device->ath_device->ctrl_response_length;
 	buffer = malloc(buffer_size);
 	
 	/* Read response from device. */
-	rc = htc_read_message(htc_device, buffer, buffer_size, NULL);
+	rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
 	if(rc != EOK) {
 		free(buffer);
@@ -208,5 +335,5 @@
 
 	/* Send HTC message. */
-	int rc = htc_send_message(htc_device, buffer, buffer_size,
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size,
 		htc_device->endpoints.ctrl_endpoint);
 	if(rc != EOK) {
@@ -219,9 +346,9 @@
 	free(buffer);
 	
-	buffer_size = MAX_RESPONSE_LENGTH;
+	buffer_size = htc_device->ath_device->ctrl_response_length;
 	buffer = malloc(buffer_size);
 
 	/* Check response from device. */
-	rc = htc_read_message(htc_device, buffer, buffer_size, NULL);
+	rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
 	if(rc != EOK) {
 		usb_log_error("Failed to receive HTC config response message. "
@@ -254,5 +381,5 @@
 
 	/* Send HTC message. */
-	int rc = htc_send_message(htc_device, buffer, buffer_size, 
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size, 
 		htc_device->endpoints.ctrl_endpoint);
 	if(rc != EOK) {
@@ -277,9 +404,10 @@
 static int htc_check_ready(htc_device_t *htc_device)
 {
-	size_t buffer_size = MAX_RESPONSE_LENGTH;
+	size_t buffer_size = htc_device->ath_device->ctrl_response_length;
 	void *buffer = malloc(buffer_size);
 
 	/* Read response from device. */
-	int rc = htc_read_message(htc_device, buffer, buffer_size, NULL);
+	int rc = htc_read_control_message(htc_device, buffer, buffer_size, 
+		NULL);
 	if(rc != EOK) {
 		free(buffer);
@@ -310,10 +438,7 @@
  * @return EOK if succeed, negative error code otherwise.
  */
-int htc_device_init(ath_t *ath_device, htc_device_t *htc_device)
-{
-	if(ath_device == NULL || htc_device == NULL) {
-		return EINVAL;
-	}
-	
+int htc_device_init(ath_t *ath_device, ieee80211_dev_t *ieee80211_dev, 
+	htc_device_t *htc_device)
+{
 	fibril_mutex_initialize(&htc_device->rx_lock);
 	fibril_mutex_initialize(&htc_device->tx_lock);
@@ -322,4 +447,5 @@
 	
 	htc_device->ath_device = ath_device;
+	htc_device->ieee80211_dev = ieee80211_dev;
 	
 	return EOK;
Index: uspace/drv/bus/usb/ar9271/htc.h
===================================================================
--- uspace/drv/bus/usb/ar9271/htc.h	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/htc.h	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -37,10 +37,13 @@
 #define	ATHEROS_HTC_H
 
+#include <ieee80211.h>
 #include <usb/dev/driver.h>
 #include <sys/types.h>
+#include <nic.h>
 
 #include "ath.h"
 
-#define MAX_RESPONSE_LENGTH 64
+#define HTC_RTS_THRESHOLD 2304
+#define HTC_MAX_AMPDU 0xFFFF
 
 /**
@@ -65,4 +68,14 @@
         HTC_SERVICE_NO_MORE_EP
 } htc_response_status_code_t;
+
+/**
+ * HTC operating mode definition
+ */
+typedef enum {
+	HTC_OPMODE_ADHOC = 0,
+	HTC_OPMODE_STATION = 1,
+	HTC_OPMODE_MESH = 2,
+	HTC_OPMODE_AP = 6
+} htc_operating_mode_t;
 
 /**
@@ -98,4 +111,7 @@
 	fibril_mutex_t tx_lock;
 	
+	/** Pointer to related IEEE 802.11 device */
+	ieee80211_dev_t *ieee80211_dev;
+	
 	/** Pointer to Atheros WiFi device structure */
 	ath_t *ath_device;
@@ -113,4 +129,18 @@
 	/* Message payload starts after the header. */
 } __attribute__((packed)) htc_frame_header_t;
+
+/** 
+ * HTC management TX frame header structure 
+ */
+typedef struct {
+	uint8_t node_idx;
+	uint8_t vif_idx;
+	uint8_t tidno;
+	uint8_t flags;
+	uint8_t key_type;
+	uint8_t keyix;
+	uint8_t cookie;
+	uint8_t pad;
+} __attribute__((packed)) htc_tx_management_header_t;
 
 /** 
@@ -163,4 +193,33 @@
 
 /**
+ * HTC new virtual interface message
+ */
+typedef struct {
+        uint8_t index;
+	uint8_t op_mode;
+	uint8_t addr[ETH_ADDR];
+	uint8_t ath_cap;
+	uint16_t rts_thres;		/**< Big Endian value! */
+	uint8_t pad;
+} __attribute__((packed)) htc_vif_msg_t;
+
+/**
+ * HTC new station message
+ */
+typedef struct {
+	uint8_t addr[ETH_ADDR];
+	uint8_t bssid[ETH_ADDR];
+        uint8_t sta_index;
+	uint8_t vif_index;
+	uint8_t is_vif_sta;
+		
+	uint16_t flags;		/**< Big Endian value! */
+	uint16_t ht_cap;	/**< Big Endian value! */
+	uint16_t max_ampdu;	/**< Big Endian value! */
+	
+	uint8_t pad;
+} __attribute__((packed)) htc_sta_msg_t;
+
+/**
  * HTC setup complete message structure
  */
@@ -169,10 +228,16 @@
 } __attribute__((packed)) htc_setup_complete_msg_t;
 
-extern int htc_device_init(ath_t *ath_device, htc_device_t *htc_device);
+extern int htc_device_init(ath_t *ath_device, ieee80211_dev_t *ieee80211_dev, 
+	htc_device_t *htc_device);
 extern int htc_init(htc_device_t *htc_device);
-extern int htc_read_message(htc_device_t *htc_device, void *buffer, 
+extern int htc_init_new_vif(htc_device_t *htc_device);
+extern int htc_read_control_message(htc_device_t *htc_device, void *buffer, 
 	size_t buffer_size, size_t *transferred_size);
-extern int htc_send_message(htc_device_t *htc_device, void *buffer, 
+extern int htc_read_data_message(htc_device_t *htc_device, void *buffer, 
+	size_t buffer_size, size_t *transferred_size);
+extern int htc_send_control_message(htc_device_t *htc_device, void *buffer, 
 	size_t buffer_size, uint8_t endpoint_id);
+extern int htc_send_data_message(htc_device_t *htc_device, void *buffer, 
+	size_t buffer_size, uint8_t endpoint_id);
 
 #endif	/* ATHEROS_HTC_H */
Index: uspace/drv/bus/usb/ar9271/hw.c
===================================================================
--- uspace/drv/bus/usb/ar9271/hw.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/hw.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -245,5 +245,5 @@
 	gpio_shift = 2 * gpio;
 	
-	rc = wmi_reg_clear_set_bit(ar9271->htc_device, AR9271_GPIO_OE_OUT,
+	rc = wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_GPIO_OE_OUT,
 		AR9271_GPIO_OE_OUT_ALWAYS << gpio_shift, 
 		AR9271_GPIO_OE_OUT_ALWAYS << gpio_shift);
@@ -258,5 +258,5 @@
 static int hw_gpio_set_value(ar9271_t *ar9271, uint32_t gpio, uint32_t value)
 {
-	int rc = wmi_reg_clear_set_bit(ar9271->htc_device, AR9271_GPIO_IN_OUT,
+	int rc = wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_GPIO_IN_OUT,
 		(~value & 1) << gpio, 1 << gpio);
 	if(rc != EOK) {
@@ -317,10 +317,10 @@
 
 static int hw_set_operating_mode(ar9271_t *ar9271, 
-	ieee80211_operating_mode_t opmode)
+	ieee80211_operating_mode_t op_mode)
 {
 	uint32_t set_bit = 0x10000000;
 	
 	/* NOTICE: Fall-through switch statement! */
-	switch(opmode) {
+	switch(op_mode) {
 		case IEEE80211_OPMODE_ADHOC:
 			set_bit |= AR9271_OPMODE_ADHOC_MASK;
@@ -333,7 +333,9 @@
 	}
 	
-	wmi_reg_clear_set_bit(ar9271->htc_device, AR9271_STATION_ID1,
+	wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_STATION_ID1,
 		set_bit, 
 		AR9271_OPMODE_STATION_AP_MASK | AR9271_OPMODE_ADHOC_MASK);
+	
+	ar9271->ieee80211_dev->current_op_mode = op_mode;
 	
 	return EOK;
@@ -352,20 +354,20 @@
 }
 
-static int hw_set_channel(ar9271_t *ar9271, uint16_t freq)
+static int hw_set_freq(ar9271_t *ar9271, uint16_t freq)
 {
 	/* Not supported channel frequency. */
-	if(freq < IEEE80211_FIRST_CHANNEL || freq > IEEE80211_MAX_CHANNEL) {
+	if(freq < IEEE80211_FIRST_FREQ || freq > IEEE80211_MAX_FREQ) {
 		return EINVAL;
 	}
 	
 	/* Not supported channel frequency. */
-	if((freq - IEEE80211_FIRST_CHANNEL) % IEEE80211_CHANNEL_GAP != 0) {
+	if((freq - IEEE80211_FIRST_FREQ) % IEEE80211_CHANNEL_GAP != 0) {
 		return EINVAL;
 	}
 	
-	uint32_t result;
-	wmi_reg_read(ar9271->htc_device, AR9271_PHY_CCK_TX_CTRL, &result);
+	uint32_t tx_control;
+	wmi_reg_read(ar9271->htc_device, AR9271_PHY_CCK_TX_CTRL, &tx_control);
 	wmi_reg_write(ar9271->htc_device, AR9271_PHY_CCK_TX_CTRL,
-		result & ~AR9271_PHY_CCK_TX_CTRL_JAPAN);
+		tx_control & ~AR9271_PHY_CCK_TX_CTRL_JAPAN);
 	
 	/* Some magic here. */
@@ -377,4 +379,117 @@
 		to_write);
 	
+	ar9271->ieee80211_dev->current_freq = freq;
+	
+	return EOK;
+}
+
+static int hw_set_rx_filter(ar9271_t *ar9271)
+{
+	uint32_t filter_bits;
+	int rc = wmi_reg_read(ar9271->htc_device, AR9271_RX_FILTER, 
+		&filter_bits);
+	if(rc != EOK) {
+		usb_log_error("Failed to read RX filter.\n");
+		return EINVAL;
+	}
+	
+	/* TODO: Do proper filtering here. */
+	
+	filter_bits |= AR9271_RX_FILTER_UNI | AR9271_RX_FILTER_MULTI | 
+		AR9271_RX_FILTER_BROAD | AR9271_RX_FILTER_BEACON | 
+		AR9271_RX_FILTER_MYBEACON | AR9271_RX_FILTER_PROMISCUOUS;
+	
+	rc = wmi_reg_write(ar9271->htc_device, AR9271_RX_FILTER, filter_bits);
+	if(rc != EOK) {
+		usb_log_error("Failed to write RX filter.\n");
+		return EINVAL;
+	}
+	
+	return EOK;
+}
+
+int hw_rx_init(ar9271_t *ar9271)
+{
+	int rc = wmi_reg_write(ar9271->htc_device, AR9271_COMMAND, 
+		AR9271_COMMAND_RX_ENABLE);
+	if(rc != EOK) {
+		usb_log_error("Failed to send RX enable command.\n");
+		return EINVAL;
+	}
+	
+	rc = hw_set_rx_filter(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to set RX filtering.\n");
+		return EINVAL;
+	}
+	
+	return EOK;
+}
+
+static int hw_activate_phy(ar9271_t *ar9271)
+{
+	int rc = wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
+	if(rc != EOK) {
+		usb_log_error("Failed to activate set PHY active.\n");
+		return rc;
+	}
+	
+	udelay(1000);
+	
+	return EOK;
+}
+
+static int hw_init_pll(ar9271_t *ar9271)
+{
+	uint32_t pll;
+	
+	/* Some magic here. */
+	pll = (0x5 << 10) & 0x00003C00;
+	pll |= (0x2 << 14) & 0x0000C000; /**< 0x2 ~ quarter rate (0x1 half) */
+	pll |= 0x58 & 0x000003FF;
+	
+	return wmi_reg_write(ar9271->htc_device, AR9271_RTC_PLL_CONTROL, pll);
+}
+
+static int hw_calibrate(ar9271_t *ar9271)
+{
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_CARRIER_LEAK_CONTROL,
+		AR9271_CARRIER_LEAK_CALIB);
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_ADC_CONTROL,
+		AR9271_ADC_CONTROL_OFF_PWDADC);
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
+		AR9271_AGC_CONTROL_TX_CALIB);
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_PHY_TPCRG1,
+		AR9271_PHY_TPCRG1_PD_CALIB);
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
+		AR9271_AGC_CONTROL_CALIB);
+	
+	int rc = hw_read_wait(ar9271, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_CALIB, 0);
+	if(rc != EOK) {
+		usb_log_error("Failed to wait on calibrate completion.\n");
+		return rc;
+	}
+	
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_ADC_CONTROL,
+		AR9271_ADC_CONTROL_OFF_PWDADC);
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_CARRIER_LEAK_CONTROL,
+		AR9271_CARRIER_LEAK_CALIB);
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL,
+		AR9271_AGC_CONTROL_TX_CALIB);
+	
+	return EOK;
+}
+
+static int hw_set_init_values(ar9271_t *ar9271)
+{
+	int size = sizeof(ar9271_init_array) / sizeof(ar9271_init_array[0]);
+	
+	for(int i = 0; i < size; i++) {
+		uint32_t reg_offset = ar9271_init_array[i][0];
+		uint32_t reg_value = ar9271_init_array[i][1];
+		wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
+	}
+	
 	return EOK;
 }
@@ -382,5 +497,12 @@
 int hw_reset(ar9271_t *ar9271) 
 {
-	int rc = wmi_reg_write(ar9271->htc_device, 
+	/* Set physical layer as deactivated. */
+	int rc = wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 0);
+	if(rc != EOK) {
+		usb_log_error("Failed to set PHY deactivated.\n");
+		return rc;
+	}
+	
+	rc = wmi_reg_write(ar9271->htc_device, 
 		AR9271_RESET_POWER_DOWN_CONTROL,
 		AR9271_RADIO_RF_RESET);
@@ -391,4 +513,24 @@
 	
 	udelay(50);
+	
+	/* TODO: There should be cold reset only if RX or TX is enabled. */
+	
+	rc = hw_init_pll(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to init PLL.\n");
+		return rc;
+	}
+	
+	udelay(500);
+	
+	rc = wmi_reg_write(ar9271->htc_device, 
+		AR9271_CLOCK_CONTROL,
+		AR9271_MAX_CPU_CLOCK);
+	if(rc != EOK) {
+		usb_log_error("Failed to set CPU clock.\n");
+		return rc;
+	}
+	
+	udelay(100);
 	
 	rc = wmi_reg_write(ar9271->htc_device, 
@@ -403,10 +545,11 @@
 	udelay(50);
 	
-	/* Perform cold reset of device. */
-	rc = hw_set_reset(ar9271, true);
-	if(rc != EOK) {
-		usb_log_error("Failed to HW cold reset.\n");
-		return rc;
-	}
+	rc = hw_set_init_values(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to set device init values.\n");
+		return rc;
+	}
+	
+	/* TODO: There should probably be TX power settings. */
 	
 	/* Set physical layer mode. */
@@ -418,4 +561,6 @@
 	}
 	
+	/* TODO: Init EEPROM here. */
+	
 	/* Set device operating mode. */
 	rc = hw_set_operating_mode(ar9271, IEEE80211_OPMODE_STATION);
@@ -425,6 +570,6 @@
 	}
 	
-	/* Set channel. */
-	rc = hw_set_channel(ar9271, IEEE80211_FIRST_CHANNEL);
+	/* Set channel frequency. */
+	rc = hw_set_freq(ar9271, IEEE80211_FIRST_FREQ);
 	if(rc != EOK) {
 		usb_log_error("Failed to set channel.\n");
@@ -444,10 +589,23 @@
 	}
 	
+	/* TODO: Maybe resetting TX queues will be necessary afterwards here. */
+	
+	/* TODO: Setting RX, TX timeouts and others may be necessary here. */
+	
 	/* Activate physical layer. */
-	rc = wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
+	rc = hw_activate_phy(ar9271);
 	if(rc != EOK) {
 		usb_log_error("Failed to activate physical layer.\n");
 		return rc;
 	}
+	
+	/* Calibration. */
+	rc = hw_calibrate(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to calibrate device.\n");
+		return rc;
+	}
+	
+	usb_log_info("HW reset done.\n");
 	
 	return EOK;
Index: uspace/drv/bus/usb/ar9271/hw.h
===================================================================
--- uspace/drv/bus/usb/ar9271/hw.h	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/hw.h	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -38,8 +38,9 @@
 #include "ar9271.h"
 
-#define HW_WAIT_LOOPS 100
+#define HW_WAIT_LOOPS 1000
 #define HW_WAIT_TIME_US 10
 
 extern int hw_init(ar9271_t *ar9271);
+extern int hw_rx_init(ar9271_t *ar9271);
 extern int hw_reset(ar9271_t *ar9271);
 
Index: uspace/drv/bus/usb/ar9271/wmi.c
===================================================================
--- uspace/drv/bus/usb/ar9271/wmi.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/wmi.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -54,6 +54,6 @@
 	uint32_t cmd_value = host2uint32_t_be(reg_offset);
 	
-	size_t buffer_size = MAX_RESPONSE_LENGTH;
-	void *resp_buffer = malloc(buffer_size);
+	void *resp_buffer = 
+		malloc(htc_device->ath_device->ctrl_response_length);
 	
 	int rc = wmi_send_command(htc_device, WMI_REG_READ, 
@@ -90,5 +90,6 @@
 	};
 	
-	void *resp_buffer = malloc(MAX_RESPONSE_LENGTH);
+	void *resp_buffer = 
+		malloc(htc_device->ath_device->ctrl_response_length);
 	
 	int rc = wmi_send_command(htc_device, WMI_REG_WRITE, 
@@ -115,5 +116,5 @@
  * @return EOK if succeed, negative error code otherwise.
  */
-int wmi_reg_clear_set_bit(htc_device_t *htc_device, uint32_t reg_offset, 
+int wmi_reg_set_clear_bit(htc_device_t *htc_device, uint32_t reg_offset, 
 	uint32_t set_bit, uint32_t clear_bit)
 {
@@ -152,5 +153,5 @@
 	uint32_t set_bit)
 {
-	return wmi_reg_clear_set_bit(htc_device, reg_offset, set_bit, 0);
+	return wmi_reg_set_clear_bit(htc_device, reg_offset, set_bit, 0);
 }
 
@@ -167,5 +168,5 @@
 	uint32_t clear_bit)
 {
-	return wmi_reg_clear_set_bit(htc_device, reg_offset, 0, clear_bit);
+	return wmi_reg_set_clear_bit(htc_device, reg_offset, 0, clear_bit);
 }
 
@@ -184,5 +185,6 @@
 	size_t buffer_size = sizeof(wmi_reg_t) * elements;
 	void *buffer = malloc(buffer_size);
-	void *resp_buffer = malloc(MAX_RESPONSE_LENGTH);
+	void *resp_buffer = 
+		malloc(htc_device->ath_device->ctrl_response_length);
 	
 	/* Convert values to correct endianness. */
@@ -240,5 +242,5 @@
 	
 	/* Send message. */
-	int rc = htc_send_message(htc_device, buffer, buffer_size,
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size,
 		htc_device->endpoints.wmi_endpoint);
 	if(rc != EOK) {
@@ -251,12 +253,14 @@
 	
 	bool clean_resp_buffer = false;
+	size_t response_buffer_size = 
+		htc_device->ath_device->ctrl_response_length;
 	if(response_buffer == NULL) {
-		response_buffer = malloc(MAX_RESPONSE_LENGTH);
+		response_buffer = malloc(response_buffer_size);
 		clean_resp_buffer = true;
 	}
 	
 	/* Read response. */
-	rc = htc_read_message(htc_device, response_buffer, MAX_RESPONSE_LENGTH, 
-		NULL);
+	rc = htc_read_control_message(htc_device, response_buffer, 
+		response_buffer_size, NULL);
 	if(rc != EOK) {
 		free(buffer);
Index: uspace/drv/bus/usb/ar9271/wmi.h
===================================================================
--- uspace/drv/bus/usb/ar9271/wmi.h	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/drv/bus/usb/ar9271/wmi.h	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -49,5 +49,5 @@
     uint16_t command_id;		/**< Big Endian value! */
     uint16_t sequence_number;           /**< Big Endian value! */
-} __attribute__((packed)) wmi_command_header_t; 
+} __attribute__((packed)) wmi_command_header_t;
 
 /**
@@ -117,5 +117,5 @@
 extern int wmi_reg_write(htc_device_t *htc_device, uint32_t reg_offset, 
 	uint32_t val);
-extern int wmi_reg_clear_set_bit(htc_device_t *htc_device, uint32_t reg_offset, 
+extern int wmi_reg_set_clear_bit(htc_device_t *htc_device, uint32_t reg_offset, 
 	uint32_t set_bit, uint32_t clear_bit);
 extern int wmi_reg_set_bit(htc_device_t *htc_device, uint32_t reg_offset, 
Index: uspace/lib/net/ieee80211/ieee80211.c
===================================================================
--- uspace/lib/net/ieee80211/ieee80211.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/lib/net/ieee80211/ieee80211.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -37,5 +37,5 @@
 
 #include <errno.h>
-#include <nic.h>
+#include <byteorder.h>
 
 #include <ieee80211_impl.h>
@@ -48,4 +48,11 @@
 static driver_ops_t ieee80211_nic_driver_ops;
 
+bool ieee80211_is_data_frame(ieee80211_header_t *header)
+{
+	return (header->frame_ctrl & 
+		host2uint16_t_le(IEEE80211_FRAME_CTRL_FRAME_TYPE)) ==
+		host2uint16_t_le(IEEE80211_FRAME_CTRL_DATA_FRAME);
+}
+
 static int ieee80211_open(ddf_fun_t *fun)
 {
@@ -53,7 +60,19 @@
 	ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
 	
+	if(ieee80211_dev->started) {
+		return EOK;
+	} else {
+		ieee80211_dev->started = true;
+	}
+	
 	int rc = ieee80211_dev->ops->start(ieee80211_dev);
 	if(rc != EOK)
 		return rc;
+	
+	/*
+	rc = ieee80211_dev->ops->scan(ieee80211_dev);
+	if(rc != EOK)
+		return rc;
+	 */
 	
 	return EOK;
@@ -70,4 +89,8 @@
 	/* IEEE802.11 start operation must be implemented. */
 	if(!ieee80211_ops->start)
+		return EINVAL;
+	
+	/* IEEE802.11 TX handler must be implemented. */
+	if(!ieee80211_ops->tx_handler)
 		return EINVAL;
 	
@@ -93,4 +116,6 @@
 	ieee80211_dev->ddf_dev = ddf_dev;
 	ieee80211_dev->driver_data = driver_data;
+	ieee80211_dev->started = false;
+	ieee80211_dev->current_op_mode = IEEE80211_OPMODE_STATION;
 	
 	/* Bind NIC to device */
Index: uspace/lib/net/ieee80211/ieee80211_impl.c
===================================================================
--- uspace/lib/net/ieee80211/ieee80211_impl.c	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/lib/net/ieee80211/ieee80211_impl.c	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -40,4 +40,25 @@
 #include <ieee80211_impl.h>
 
+static int ieee80211_freq_to_channel(uint16_t freq)
+{
+	return (freq - IEEE80211_FIRST_FREQ) / IEEE80211_CHANNEL_GAP + 1;
+}
+
+static int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev)
+{
+	size_t buffer_size = sizeof(ieee80211_header_t);
+	void *buffer = malloc(buffer_size);
+	
+	/* TODO */
+	
+	ieee80211_freq_to_channel(ieee80211_dev->current_freq);
+	
+	ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
+	
+	free(buffer);
+	
+	return EOK;
+}
+
 /**
  * Default implementation of IEEE802.11 scan function.
@@ -49,5 +70,8 @@
 int ieee80211_scan_impl(ieee80211_dev_t *ieee80211_dev)
 {
-	/** TODO */
+	/* TODO */
+	int rc = ieee80211_probe_request(ieee80211_dev);
+	if(rc != EOK)
+		return rc;
 	
 	return EOK;
Index: uspace/lib/net/include/ieee80211.h
===================================================================
--- uspace/lib/net/include/ieee80211.h	(revision ab365c4b5641c1da9913b8fda70916c9a2a5a7c0)
+++ uspace/lib/net/include/ieee80211.h	(revision 56c0930934f3eb8763355d11f38eb65b6896d53e)
@@ -41,13 +41,17 @@
 #include <ddf/driver.h>
 #include <sys/types.h>
+#include <nic.h>
 
 /** Initial channel frequency. */
-#define IEEE80211_FIRST_CHANNEL 2412
+#define IEEE80211_FIRST_FREQ 2412
 
 /** Max supported channel frequency. */
-#define IEEE80211_MAX_CHANNEL 2472
+#define IEEE80211_MAX_FREQ 2472
 
 /* Gap between IEEE80211 channels in MHz. */
 #define IEEE80211_CHANNEL_GAP 5
+
+#define IEEE80211_FRAME_CTRL_FRAME_TYPE 0x000C
+#define IEEE80211_FRAME_CTRL_DATA_FRAME 0x0008
 
 struct ieee80211_dev;
@@ -65,4 +69,5 @@
 	int (*start)(struct ieee80211_dev *);
 	int (*scan)(struct ieee80211_dev *);
+	int (*tx_handler)(struct ieee80211_dev *, void *, size_t);
 } ieee80211_ops_t;
 
@@ -77,6 +82,30 @@
 	/** Pointer to driver specific data. */
 	void *driver_data;
+	
+	/** Current operating frequency. */
+	uint16_t current_freq;
+	
+	/** Current operating mode. */
+	ieee80211_operating_mode_t current_op_mode;
+	
+	/* TODO: Probably to be removed later - nic.open function is now 
+	 * executed multiple times, have to find out reason and fix it. 
+	 */
+	/** Indicates whether driver has already started. */
+	bool started;
 } ieee80211_dev_t;
 
+/** IEEE 802.11 header structure. */
+typedef struct {
+	uint16_t frame_ctrl;		/**< Little Endian value! */
+	uint16_t duration_id;		/**< Little Endian value! */
+	uint8_t address1[ETH_ADDR];
+	uint8_t address2[ETH_ADDR];
+	uint8_t address3[ETH_ADDR];
+	uint16_t seq_ctrl;		/**< Little Endian value! */
+	uint8_t address4[ETH_ADDR];
+} __attribute__((packed)) __attribute__ ((aligned(2))) ieee80211_header_t;
+
+extern bool ieee80211_is_data_frame(ieee80211_header_t *header);
 extern int ieee80211_device_init(ieee80211_dev_t *ieee80211_dev, 
 	void *driver_data, ddf_dev_t *ddf_dev);
