Index: uspace/drv/nic/ar9271/Makefile
===================================================================
--- uspace/drv/nic/ar9271/Makefile	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/Makefile	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2014 Jan Kolarik
+# 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 = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a \
+	$(LIBNIC_PREFIX)/libnic.a \
+	$(LIBIEEE80211_PREFIX)/libieee80211.a
+	
+EXTRA_CFLAGS += \
+	-I. \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include \
+	-I$(LIBNIC_PREFIX)/include \
+	-I$(LIBIEEE80211_PREFIX)/include \
+	
+BINARY = ar9271
+
+SOURCES = \
+	ath_usb.c \
+	hw.c \
+	wmi.c \
+	htc.c \
+	ar9271.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/ar9271/ar9271.c
===================================================================
--- uspace/drv/nic/ar9271/ar9271.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ar9271.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,721 @@
+/*
+ * Copyright (c) 2014 Jan Kolarik
+ * 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 ar9271.c
+ *
+ * Driver for AR9271 USB WiFi dongle.
+ *
+ */
+
+#include <ieee80211.h>
+#include <usb/classes/classes.h>
+#include <usb/dev/request.h>
+#include <usb/dev/poll.h>
+#include <usb/debug.h>
+#include <stdio.h>
+#include <ddf/interrupt.h>
+#include <nic.h>
+#include <macros.h>
+
+#include "ath_usb.h"
+#include "wmi.h"
+#include "hw.h"
+#include "ar9271.h"
+
+#define NAME "ar9271"
+#define FIRMWARE_FILENAME "/drv/ar9271/ar9271.fw"
+
+const usb_endpoint_description_t usb_ar9271_out_bulk_endpoint_description = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_OUT,
+	.interface_class = USB_CLASS_VENDOR_SPECIFIC,
+	.interface_subclass = 0x0,
+	.interface_protocol = 0x0,
+	.flags = 0
+};
+
+const usb_endpoint_description_t usb_ar9271_in_bulk_endpoint_description = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_VENDOR_SPECIFIC,
+	.interface_subclass = 0x0,
+	.interface_protocol = 0x0,
+	.flags = 0
+};
+
+const usb_endpoint_description_t usb_ar9271_in_int_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_VENDOR_SPECIFIC,
+	.interface_subclass = 0x0,
+	.interface_protocol = 0x0,
+	.flags = 0
+};
+
+const usb_endpoint_description_t usb_ar9271_out_int_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_OUT,
+	.interface_class = USB_CLASS_VENDOR_SPECIFIC,
+	.interface_subclass = 0x0,
+	.interface_protocol = 0x0,
+	.flags = 0
+};
+
+/* Array of endpoints expected on the device, NULL terminated. */
+const usb_endpoint_description_t *endpoints[] = {
+	&usb_ar9271_out_bulk_endpoint_description,
+	&usb_ar9271_in_bulk_endpoint_description,
+        &usb_ar9271_in_int_endpoint_description,
+        &usb_ar9271_out_int_endpoint_description,
+	NULL
+};
+
+/* Callback when new device is to be controlled by this driver. */
+static int ar9271_add_device(ddf_dev_t *);
+
+/* IEEE 802.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 int ar9271_ieee80211_set_freq(ieee80211_dev_t *ieee80211_dev,
+	uint16_t freq);
+
+static driver_ops_t ar9271_driver_ops = {
+	.dev_add = ar9271_add_device
+};
+
+static driver_t ar9271_driver = {
+	.name = NAME,
+	.driver_ops = &ar9271_driver_ops
+};
+
+static ieee80211_ops_t ar9271_ieee80211_ops = {
+	.start = ar9271_ieee80211_start,
+	.tx_handler = ar9271_ieee80211_tx_handler,
+	.set_freq = ar9271_ieee80211_set_freq
+};
+
+static ieee80211_iface_t ar9271_ieee80211_iface;
+
+static int ar9271_get_device_info(ddf_fun_t *dev, nic_device_info_t *info);
+static int ar9271_get_cable_state(ddf_fun_t *, nic_cable_state_t *);
+static int ar9271_get_operation_mode(ddf_fun_t *, int *, 
+	nic_channel_mode_t *, nic_role_t *);
+
+static nic_iface_t ar9271_ieee80211_nic_iface = {
+	.get_device_info = &ar9271_get_device_info,
+	.get_cable_state = &ar9271_get_cable_state,
+	.get_operation_mode = &ar9271_get_operation_mode
+};
+
+static ddf_dev_ops_t ar9271_ieee80211_dev_ops;
+
+/** 
+ * Get device information.
+ *
+ */
+static int ar9271_get_device_info(ddf_fun_t *dev, nic_device_info_t *info)
+{
+	assert(dev);
+	assert(info);
+	
+	memset(info, 0, sizeof(nic_device_info_t));
+	
+	info->vendor_id = 0x0CF3;
+	info->device_id = 0x9271;
+	str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH,
+	    "Atheros Communications, Inc.");
+	str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH,
+	    "AR9271");
+	
+	return EOK;
+}
+
+/** 
+ * Get cable state.
+ *
+ */
+static int ar9271_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
+{
+	*state = NIC_CS_PLUGGED;
+	
+	return EOK;
+}
+
+/** 
+ * Get operation mode of the device.
+ *
+ */
+static int ar9271_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	*duplex = NIC_CM_FULL_DUPLEX;
+	*speed = 10;
+	*role = NIC_ROLE_UNKNOWN;
+	
+	return EOK;
+}
+
+/** 
+ * Set multicast frames acceptance mode.
+ *
+ */
+static int ar9271_on_multicast_mode_change(nic_t *nic, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	/*
+	ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *) 
+		nic_get_specific(nic);
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	 */
+	
+	switch (mode) {
+		case NIC_MULTICAST_BLOCKED:
+			/* TODO */
+			break;
+		case NIC_MULTICAST_LIST:
+			/* TODO */
+			break;
+		case NIC_MULTICAST_PROMISC:
+			/* TODO */
+			break;
+		default:
+			return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+/** 
+ * Set unicast frames acceptance mode.
+ *
+ */
+static int ar9271_on_unicast_mode_change(nic_t *nic, nic_unicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	/*
+	ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *) 
+		nic_get_specific(nic);
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	 */
+	
+	switch (mode) {
+		case NIC_UNICAST_BLOCKED:
+			/* TODO */
+			break;
+		case NIC_UNICAST_DEFAULT:
+			/* TODO */
+			break;
+		case NIC_UNICAST_LIST:
+			/* TODO */
+			break;
+		case NIC_UNICAST_PROMISC:
+			/* TODO */
+			break;
+		default:
+			return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+/** 
+ * Set broadcast frames acceptance mode.
+ *
+ */
+static int ar9271_on_broadcast_mode_change(nic_t *nic, nic_broadcast_mode_t mode)
+{
+	/*
+	ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *) 
+		nic_get_specific(nic);
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	 */
+	
+	switch (mode) {
+		case NIC_BROADCAST_BLOCKED:
+			/* TODO */
+			break;
+		case NIC_BROADCAST_ACCEPTED:
+			/* TODO */
+			break;
+		default:
+			return ENOTSUP;
+	}
+	
+	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) {
+		size_t transferred_size;
+		if(htc_read_data_message(ar9271->htc_device, 
+			buffer, buffer_size, &transferred_size) == EOK) {
+			ath_usb_data_header_t *data_header = 
+				(ath_usb_data_header_t *) buffer;
+
+			/* Invalid packet. */
+			if(data_header->tag != uint16_t_le2host(RX_TAG)) {
+				continue;
+			}
+			
+			size_t strip_length = 
+				sizeof(ath_usb_data_header_t) +
+				sizeof(htc_frame_header_t) + 
+				HTC_RX_HEADER_LENGTH;
+			
+			/* TODO: RX header inspection. */
+			void *strip_buffer = buffer + strip_length;
+			
+			ieee80211_rx_handler(ar9271->ieee80211_dev,
+				strip_buffer,
+				transferred_size - strip_length);
+		}
+	}
+	
+	free(buffer);
+	
+	return EOK;
+}
+
+/** 
+ * IEEE 802.11 handlers. 
+ */
+
+static int ar9271_ieee80211_set_freq(ieee80211_dev_t *ieee80211_dev,
+	uint16_t freq)
+{
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	
+	wmi_send_command(ar9271->htc_device, WMI_DISABLE_INTR, NULL, 0, NULL);
+	wmi_send_command(ar9271->htc_device, WMI_DRAIN_TXQ_ALL, NULL, 0, NULL);
+	wmi_send_command(ar9271->htc_device, WMI_STOP_RECV, NULL, 0, NULL);
+	
+	int rc = hw_freq_switch(ar9271, freq);
+	if(rc != EOK) {
+		usb_log_error("Failed to HW switch frequency.\n");
+		return rc;
+	}
+	
+	wmi_send_command(ar9271->htc_device, WMI_START_RECV, NULL, 0, NULL);
+	
+	rc = hw_rx_init(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to initialize RX.\n");
+		return rc;
+	}
+	
+	uint16_t htc_mode = host2uint16_t_be(1);
+	wmi_send_command(ar9271->htc_device, WMI_SET_MODE, 
+		(uint8_t *) &htc_mode, sizeof(htc_mode), NULL);
+	wmi_send_command(ar9271->htc_device, WMI_ENABLE_INTR, NULL, 0, NULL);
+	
+	return EOK;
+}
+
+static int ar9271_ieee80211_tx_handler(ieee80211_dev_t *ieee80211_dev,
+	void *buffer, size_t buffer_size)
+{
+	size_t complete_size, offset;
+	void *complete_buffer;
+	int endpoint;
+	
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	
+	uint16_t frame_ctrl = *((uint16_t *) buffer);
+	if(ieee80211_is_data_frame(frame_ctrl)) {
+		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);
+		memset(complete_buffer, 0, complete_size);
+		
+		htc_tx_management_header_t *mgmt_header =
+			(htc_tx_management_header_t *) 
+			(complete_buffer + sizeof(htc_frame_header_t));
+		mgmt_header->keyix = 0xFF;
+		
+		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_ieee80211_start(ieee80211_dev_t *ieee80211_dev)
+{
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	
+	wmi_send_command(ar9271->htc_device, WMI_FLUSH_RECV, NULL, 0, NULL);
+	
+	int rc = hw_reset(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to do HW reset.\n");
+		return rc;
+	}
+	
+	uint16_t htc_mode = host2uint16_t_be(1);
+	wmi_send_command(ar9271->htc_device, WMI_SET_MODE, 
+		(uint8_t *) &htc_mode, sizeof(htc_mode), NULL);
+	wmi_send_command(ar9271->htc_device, WMI_ATH_INIT, NULL, 0, NULL);
+	wmi_send_command(ar9271->htc_device, WMI_START_RECV, NULL, 0, NULL);
+	wmi_send_command(ar9271->htc_device, WMI_ENABLE_INTR, NULL, 0, NULL);
+	
+	rc = hw_rx_init(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to initialize RX.\n");
+		return rc;
+	}
+	
+	/* Send capability message to target. */
+	htc_cap_msg_t cap_msg;
+	cap_msg.ampdu_limit = host2uint32_t_be(0xFFFF);
+	cap_msg.ampdu_subframes = 0xFF;
+	cap_msg.enable_coex = 0;
+	cap_msg.tx_chainmask = 0x1;
+	
+	wmi_send_command(ar9271->htc_device, WMI_TARGET_IC_UPDATE,
+		(uint8_t *) &cap_msg, sizeof(cap_msg), NULL);
+	
+	rc = htc_init_new_vif(ar9271->htc_device);
+	if(rc != EOK) {
+		usb_log_error("Failed to initialize new VIF.\n");
+		return rc;
+	}
+	
+	/* Add data polling fibril. */
+	fid_t fibril = fibril_create(ar9271_data_polling, ar9271);
+	if (fibril == 0) {
+		return ENOMEM;
+	}
+	fibril_add_ready(fibril);
+	
+	ar9271->starting_up = false;
+	
+	return EOK;
+}
+
+static int ar9271_init(ar9271_t *ar9271, usb_device_t *usb_device)
+{
+	ar9271->starting_up = true;
+	ar9271->usb_device = usb_device;
+	
+	fibril_mutex_initialize(&ar9271->ar9271_lock);
+	
+	ar9271->ath_device = calloc(1, sizeof(ath_t));
+	if (!ar9271->ath_device) {
+		usb_log_error("Failed to allocate memory for ath device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	int rc = ath_usb_init(ar9271->ath_device, usb_device);
+	if(rc != EOK) {
+		free(ar9271->ath_device);
+		usb_log_error("Failed to initialize ath device.\n");
+		return rc;
+	}
+	
+	/* IEEE 802.11 framework structure initialization. */
+	ar9271->ieee80211_dev = ieee80211_device_create();
+	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->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;
+	}
+	
+	ieee80211_set_specific(ar9271->ieee80211_dev, ar9271);
+		
+	/* HTC device structure initialization. */
+	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 "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	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 rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Upload firmware to WiFi device.
+ * 
+ * @param ar9271 AR9271 device structure
+ * 
+ * @return EOK if succeed, negative error code otherwise
+ */
+static int ar9271_upload_fw(ar9271_t *ar9271)
+{
+	int rc;
+	
+	usb_device_t *usb_device = ar9271->usb_device;
+        
+        /* TODO: Set by maximum packet size in pipe. */
+	static const size_t MAX_TRANSFER_SIZE = 512;
+	
+	/* Load FW from file. */
+	FILE *fw_file = fopen(FIRMWARE_FILENAME, "rb");
+	if (fw_file == NULL) {
+		usb_log_error("Failed opening file with firmware.\n");
+		return ENOENT;
+	}
+	
+	fseek(fw_file, 0, SEEK_END);
+	uint64_t file_size = ftell(fw_file);
+	fseek(fw_file, 0, SEEK_SET);
+	
+	void *fw_data = malloc(file_size);
+	if(fw_data == NULL) {
+		fclose(fw_file);
+		usb_log_error("Failed allocating memory for firmware.\n");
+		return ENOMEM;
+	}
+
+	fread(fw_data, file_size, 1, fw_file);
+	fclose(fw_file);
+	
+	/* Upload FW to device. */
+	uint64_t remain_size = file_size;
+	uint32_t current_addr = AR9271_FW_ADDRESS;
+	uint8_t *current_data = fw_data;
+	uint8_t *buffer = malloc(MAX_TRANSFER_SIZE);
+	while(remain_size > 0) {
+		size_t chunk_size = min(remain_size, MAX_TRANSFER_SIZE);
+		memcpy(buffer, current_data, chunk_size);
+		rc = usb_control_request_set(&usb_device->ctrl_pipe,
+		    USB_REQUEST_TYPE_VENDOR,
+		    USB_REQUEST_RECIPIENT_DEVICE,
+		    AR9271_FW_DOWNLOAD,
+		    uint16_host2usb(current_addr >> 8),
+		    0, buffer, chunk_size);
+		if(rc != EOK) {
+			free(fw_data);
+			free(buffer);
+			usb_log_error("Error while uploading firmware. "
+			    "Error: %d\n", rc);
+			return rc;
+		}
+		
+		remain_size -= chunk_size;
+		current_addr += chunk_size;
+		current_data += chunk_size;
+	}
+	
+	free(fw_data);
+	free(buffer);
+	
+	/* Send command that firmware is successfully uploaded. 
+         * This should initiate creating confirmation message in
+         * device side buffer which we will check in htc_check_ready function.
+         */
+	rc = usb_control_request_set(&usb_device->ctrl_pipe,
+	    USB_REQUEST_TYPE_VENDOR,
+	    USB_REQUEST_RECIPIENT_DEVICE,
+	    AR9271_FW_DOWNLOAD_COMP,
+	    uint16_host2usb(AR9271_FW_OFFSET >> 8),
+	    0, NULL, 0);
+	
+	if(rc != EOK) {
+		usb_log_error("IO error when sending fw upload confirmation "
+                        "message.\n");
+		return rc;
+	}
+	
+	usb_log_info("Firmware uploaded successfully.\n");
+	
+	/* Wait until firmware is ready - wait for 1 second to be sure. */
+	sleep(1);
+	
+	return rc;
+}
+
+/** Create driver data structure.
+ * 
+ *  @param dev The device structure
+ * 
+ *  @return Intialized device data structure or NULL if error occured
+ */
+static ar9271_t *ar9271_create_dev_data(ddf_dev_t *dev)
+{
+	/* USB framework initialization. */
+	usb_device_t *usb_device = calloc(1, sizeof(usb_device_t));
+	if (usb_device == NULL) {
+		usb_log_error("USB device structure allocation failed.\n");
+		return NULL;
+	}
+	
+	const char *err_msg = NULL;
+	int rc = usb_device_init(usb_device, dev, endpoints, &err_msg);
+	if(rc != EOK) {
+		free(usb_device);
+		usb_log_error("Failed to create USB device: %s, "
+		    "ERR_NUM = %d\n", err_msg, rc);
+		return NULL;
+	}
+	
+	/* AR9271 structure initialization. */
+	ar9271_t *ar9271 = calloc(1, sizeof(ar9271_t));
+	if (!ar9271) {
+		free(usb_device);
+		usb_log_error("Failed to allocate memory for device "
+		    "structure.\n");
+		return NULL;
+	}
+	
+	ar9271->ddf_dev = dev;
+	
+	rc = ar9271_init(ar9271, usb_device);
+	if(rc != EOK) {
+		free(ar9271);
+		free(usb_device);
+		usb_log_error("Failed to initialize AR9271 structure: %d\n", 
+			rc);
+		return NULL;
+	}
+	
+	return ar9271;
+}
+
+/** Clean up the ar9271 device structure.
+ *
+ * @param dev  The device structure.
+ */
+static void ar9271_delete_dev_data(ar9271_t *ar9271)
+{
+	assert(ar9271);
+	
+	// TODO
+}
+
+/** Probe and initialize the newly added device.
+ *
+ * @param dev The device structure.
+ *
+ * @return EOK if succeed, negative error code otherwise
+ */
+static int ar9271_add_device(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	/* Allocate driver data for the device. */
+	ar9271_t *ar9271 = ar9271_create_dev_data(dev);
+	if (ar9271 == NULL) {
+		usb_log_error("Unable to allocate device softstate.\n");
+		return ENOMEM;
+	}
+	
+	usb_log_info("HelenOS AR9271 device initialized.\n");
+	
+	/* Upload AR9271 firmware. */
+	ar9271_upload_fw(ar9271);
+	
+	/* Initialize AR9271 HTC services. */
+	int rc = htc_init(ar9271->htc_device);
+	if(rc != EOK) {
+		ar9271_delete_dev_data(ar9271);
+		usb_log_error("HTC initialization failed.\n");
+		return rc;
+	}
+	
+	/* Initialize AR9271 HW. */
+	rc = hw_init(ar9271);
+	if(rc != EOK) {
+		ar9271_delete_dev_data(ar9271);
+		usb_log_error("HW initialization failed.\n");
+		return rc;
+	}
+	
+	/* Initialize AR9271 IEEE 802.11 framework. */
+	rc = ieee80211_init(ar9271->ieee80211_dev, &ar9271_ieee80211_ops,
+		&ar9271_ieee80211_iface, &ar9271_ieee80211_nic_iface,
+		&ar9271_ieee80211_dev_ops);
+	if(rc != EOK) {
+		ar9271_delete_dev_data(ar9271);
+		usb_log_error("Failed to initialize IEEE80211 framework.\n");
+		return rc;
+	}
+	
+	nic_set_filtering_change_handlers(nic_get_from_ddf_dev(dev),
+		ar9271_on_unicast_mode_change, ar9271_on_multicast_mode_change,
+		ar9271_on_broadcast_mode_change, NULL, NULL);
+	
+	usb_log_info("HelenOS AR9271 added device.\n");
+	
+	return EOK;
+}
+
+int main(void)
+{
+	log_init(NAME);
+	
+	if (nic_driver_init(NAME) != EOK)
+		return 1;
+	
+	usb_log_info("HelenOS AR9271 driver started.\n");
+
+	return ddf_driver_main(&ar9271_driver);
+}
Index: uspace/drv/nic/ar9271/ar9271.h
===================================================================
--- uspace/drv/nic/ar9271/ar9271.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ar9271.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2014 Jan Kolarik
+ * 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 ar9271.h
+ *
+ * Header file for AR9271 USB WiFi dongle.
+ *
+ */
+
+#ifndef AR9271_H_
+#define AR9271_H_
+
+#include <usb/dev/driver.h>
+
+#include "htc.h"
+
+/** Number of transmission queues */
+#define AR9271_QUEUES_COUNT 10
+
+/** Number of GPIO pin used for handling led light */
+#define AR9271_LED_PIN 15
+
+/** AR9271 Registers */
+typedef enum {
+	/* ATH command register */
+	AR9271_COMMAND = 0x0008,
+	AR9271_COMMAND_RX_ENABLE = 0x00000004,
+	
+	/* ATH config register */
+	AR9271_CONFIG = 0x0014,
+	AR9271_CONFIG_ADHOC = 0x00000020,
+	
+	AR9271_QUEUE_BASE_MASK = 0x1000,
+	
+	/* EEPROM Addresses */
+	AR9271_EEPROM_BASE = 0x2100,
+	AR9271_EEPROM_MAC_ADDR_START = 0x2118,
+	
+	/* Reset MAC interface */
+	AR9271_RC = 0x4000,
+	AR9271_RC_AHB = 0x00000001,
+		
+	/* GPIO registers */
+	AR9271_GPIO_IN_OUT = 0x4048,		/**< GPIO value read/set  */
+	AR9271_GPIO_OE_OUT = 0x404C,		/**< GPIO set to output  */
+	AR9271_GPIO_OE_OUT_ALWAYS = 0x3,	/**< GPIO always drive output */
+	AR9271_GPIO_OUT_MUX1 = 0x4060,
+	AR9271_GPIO_OUT_MUX2 = 0x4064,
+	AR9271_GPIO_OUT_MUX3 = 0x4068,
+	AR9271_GPIO_OUT_MUX_AS_OUT = 0x0,	/**< GPIO set mux as output */
+    
+	/* Wakeup related registers */
+	AR9271_RTC_RC = 0x7000,
+	AR9271_RTC_RC_MAC_WARM = 0x00000001,
+	AR9271_RTC_RC_MAC_COLD = 0x00000002,
+	AR9271_RTC_RC_MASK = 0x00000003,
+	AR9271_RTC_PLL_CONTROL = 0x7014,
+	AR9271_RTC_RESET = 0x7040,
+	AR9271_RTC_STATUS = 0x7044,
+	AR9271_RTC_STATUS_MASK = 0x0000000F,
+	AR9271_RTC_STATUS_SHUTDOWN = 0x00000001,
+	AR9271_RTC_STATUS_ON = 0x00000002,
+	AR9271_RTC_FORCE_WAKE = 0x704C,
+	AR9271_RTC_FORCE_WAKE_ENABLE = 0x00000001,
+	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,
+	AR9271_STATION_ID1_POWER_SAVING = 0x00040000,
+		
+	/* RX filtering register */
+	AR9271_RX_FILTER = 0x803C,
+	AR9271_RX_FILTER_UNI = 0x00000001,
+	AR9271_RX_FILTER_MULTI = 0x00000002,
+	AR9271_RX_FILTER_BROAD = 0x00000004,
+	AR9271_RX_FILTER_CONTROL = 0x00000008,
+	AR9271_RX_FILTER_BEACON = 0x00000010,
+	AR9271_RX_FILTER_PROMISCUOUS = 0x00000020,
+	AR9271_RX_FILTER_PROBEREQ = 0x00000080,
+	AR9271_RX_FILTER_MYBEACON = 0x00000200,
+	AR9271_MULTICAST_FILTER1 = 0x8040,
+	AR9271_MULTICAST_FILTER2 = 0x8044,	
+	AR9271_DIAG = 0x8048,
+		
+	/* Physical layer registers */
+	AR9271_PHY_ACTIVE = 0x981C,
+	AR9271_ADC_CONTROL = 0x982C,
+	AR9271_AGC_CONTROL = 0x9860,
+	AR9271_PHY_SYNTH_CONTROL = 0x9874, 
+	AR9271_PHY_SPECTRAL_SCAN = 0x9910,
+	AR9271_PHY_RADAR0 = 0x9954,
+	AR9271_PHY_RADAR0_FFT_ENABLED = 0x80000000,
+	AR9271_PHY_RFBUS_KILL = 0x997C,
+	AR9271_PHY_RFBUS_GRANT = 0x9C20,
+	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_NF_CALIB = 0x00000002,
+	AR9271_AGC_CONTROL_NF_CALIB_EN = 0x00008000, 
+	AR9271_AGC_CONTROL_TX_CALIB = 0x00010000,
+	AR9271_AGC_CONTROL_NF_NOT_UPDATE = 0x00020000,
+	AR9271_PHY_MODE_DYNAMIC = 0x04,
+	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,
+	AR9271_RADIO_RF_RESET = 0x20,
+	AR9271_GATE_MAC_CONTROL = 0x4000,
+    
+	/* FW Addresses */
+	AR9271_FW_ADDRESS = 0x501000,
+	AR9271_FW_OFFSET = 0x903000,
+} ar9271_registers_t;
+
+/** AR9271 Requests */
+typedef enum {
+	AR9271_FW_DOWNLOAD = 0x30,
+	AR9271_FW_DOWNLOAD_COMP = 0x31,
+} ar9271_requests_t;
+
+/** AR9271 device data */
+typedef struct {
+	/** Lock for access. */
+	fibril_mutex_t ar9271_lock;
+	
+	/** Whether device is starting up. */
+	bool starting_up;
+	
+	/** Backing DDF device */
+	ddf_dev_t *ddf_dev;
+	
+	/** USB device data */
+	usb_device_t *usb_device;
+	
+	/** IEEE 802.11 device data */
+	ieee80211_dev_t *ieee80211_dev;
+	
+	/** ATH device data */
+	ath_t *ath_device;
+	
+	/** HTC device data */
+	htc_device_t *htc_device;
+} ar9271_t;
+
+/**
+ * AR9271 init values for 2GHz mode operation.
+ * 
+ * Including settings of noise floor limits.
+ * 
+ * Taken from Linux sources.
+ */
+static const uint32_t ar9271_2g_mode_array[][2] = {
+	{0x00001030, 0x00000160},
+	{0x00001070, 0x0000018c},
+	{0x000010b0, 0x00003e38},
+	{0x000010f0, 0x00000000},
+	{0x00008014, 0x08400b00},
+	{0x0000801c, 0x12e0002b},
+	{0x00008318, 0x00003440},
+	{0x00009804, 0x000003c0},/*< note: overridden */
+	{0x00009820, 0x02020200},
+	{0x00009824, 0x01000e0e},
+	{0x00009828, 0x0a020001},/*< note: overridden */
+	{0x00009834, 0x00000e0e},
+	{0x00009838, 0x00000007},
+	{0x00009840, 0x206a012e},
+	{0x00009844, 0x03721620},
+	{0x00009848, 0x00001053},
+	{0x0000a848, 0x00001053},
+	{0x00009850, 0x6d4000e2},
+	{0x00009858, 0x7ec84d2e},
+	{0x0000985c, 0x3137605e},
+	{0x00009860, 0x00058d18},
+	{0x00009864, 0x0001ce00},
+	{0x00009868, 0x5ac640d0},
+	{0x0000986c, 0x06903881},
+	{0x00009910, 0x30002310},
+	{0x00009914, 0x00000898},
+	{0x00009918, 0x0000000b},
+	{0x00009924, 0xd00a800d},
+	{0x00009944, 0xffbc1020},
+	{0x00009960, 0x00000000},
+	{0x00009964, 0x00000000},
+	{0x000099b8, 0x0000421c},
+	{0x000099bc, 0x00000c00},
+	{0x000099c0, 0x05eea6d4},
+	{0x000099c4, 0x06336f77},
+	{0x000099c8, 0x6af6532f},
+	{0x000099cc, 0x08f186c8},
+	{0x000099d0, 0x00046384},
+	{0x000099d4, 0x00000000},
+	{0x000099d8, 0x00000000},
+	{0x00009a00, 0x00058084},
+	{0x00009a04, 0x00058088},
+	{0x00009a08, 0x0005808c},
+	{0x00009a0c, 0x00058100},
+	{0x00009a10, 0x00058104},
+	{0x00009a14, 0x00058108},
+	{0x00009a18, 0x0005810c},
+	{0x00009a1c, 0x00058110},
+	{0x00009a20, 0x00058114},
+	{0x00009a24, 0x00058180},
+	{0x00009a28, 0x00058184},
+	{0x00009a2c, 0x00058188},
+	{0x00009a30, 0x0005818c},
+	{0x00009a34, 0x00058190},
+	{0x00009a38, 0x00058194},
+	{0x00009a3c, 0x000581a0},
+	{0x00009a40, 0x0005820c},
+	{0x00009a44, 0x000581a8},
+	{0x00009a48, 0x00058284},
+	{0x00009a4c, 0x00058288},
+	{0x00009a50, 0x00058224},
+	{0x00009a54, 0x00058290},
+	{0x00009a58, 0x00058300},
+	{0x00009a5c, 0x00058304},
+	{0x00009a60, 0x00058308},
+	{0x00009a64, 0x0005830c},
+	{0x00009a68, 0x00058380},
+	{0x00009a6c, 0x00058384},
+	{0x00009a70, 0x00068700},
+	{0x00009a74, 0x00068704},
+	{0x00009a78, 0x00068708},
+	{0x00009a7c, 0x0006870c},
+	{0x00009a80, 0x00068780},
+	{0x00009a84, 0x00068784},
+	{0x00009a88, 0x00078b00},
+	{0x00009a8c, 0x00078b04},
+	{0x00009a90, 0x00078b08},
+	{0x00009a94, 0x00078b0c},
+	{0x00009a98, 0x00078b80},
+	{0x00009a9c, 0x00078b84},
+	{0x00009aa0, 0x00078b88},
+	{0x00009aa4, 0x00078b8c},
+	{0x00009aa8, 0x00078b90},
+	{0x00009aac, 0x000caf80},
+	{0x00009ab0, 0x000caf84},
+	{0x00009ab4, 0x000caf88},
+	{0x00009ab8, 0x000caf8c},
+	{0x00009abc, 0x000caf90},
+	{0x00009ac0, 0x000db30c},
+	{0x00009ac4, 0x000db310},
+	{0x00009ac8, 0x000db384},
+	{0x00009acc, 0x000db388},
+	{0x00009ad0, 0x000db324},
+	{0x00009ad4, 0x000eb704},
+	{0x00009ad8, 0x000eb6a4},
+	{0x00009adc, 0x000eb6a8},
+	{0x00009ae0, 0x000eb710},
+	{0x00009ae4, 0x000eb714},
+	{0x00009ae8, 0x000eb720},
+	{0x00009aec, 0x000eb724},
+	{0x00009af0, 0x000eb728},
+	{0x00009af4, 0x000eb72c},
+	{0x00009af8, 0x000eb7a0},
+	{0x00009afc, 0x000eb7a4},
+	{0x00009b00, 0x000eb7a8},
+	{0x00009b04, 0x000eb7b0},
+	{0x00009b08, 0x000eb7b4},
+	{0x00009b0c, 0x000eb7b8},
+	{0x00009b10, 0x000eb7a5},
+	{0x00009b14, 0x000eb7a9},
+	{0x00009b18, 0x000eb7ad},
+	{0x00009b1c, 0x000eb7b1},
+	{0x00009b20, 0x000eb7b5},
+	{0x00009b24, 0x000eb7b9},
+	{0x00009b28, 0x000eb7c5},
+	{0x00009b2c, 0x000eb7c9},
+	{0x00009b30, 0x000eb7d1},
+	{0x00009b34, 0x000eb7d5},
+	{0x00009b38, 0x000eb7d9},
+	{0x00009b3c, 0x000eb7c6},
+	{0x00009b40, 0x000eb7ca},
+	{0x00009b44, 0x000eb7ce},
+	{0x00009b48, 0x000eb7d2},
+	{0x00009b4c, 0x000eb7d6},
+	{0x00009b50, 0x000eb7c3},
+	{0x00009b54, 0x000eb7c7},
+	{0x00009b58, 0x000eb7cb},
+	{0x00009b5c, 0x000eb7cf},
+	{0x00009b60, 0x000eb7d7},
+	{0x00009b64, 0x000eb7db},
+	{0x00009b68, 0x000eb7db},
+	{0x00009b6c, 0x000eb7db},
+	{0x00009b70, 0x000eb7db},
+	{0x00009b74, 0x000eb7db},
+	{0x00009b78, 0x000eb7db},
+	{0x00009b7c, 0x000eb7db},
+	{0x00009b80, 0x000eb7db},
+	{0x00009b84, 0x000eb7db},
+	{0x00009b88, 0x000eb7db},
+	{0x00009b8c, 0x000eb7db},
+	{0x00009b90, 0x000eb7db},
+	{0x00009b94, 0x000eb7db},
+	{0x00009b98, 0x000eb7db},
+	{0x00009b9c, 0x000eb7db},
+	{0x00009ba0, 0x000eb7db},
+	{0x00009ba4, 0x000eb7db},
+	{0x00009ba8, 0x000eb7db},
+	{0x00009bac, 0x000eb7db},
+	{0x00009bb0, 0x000eb7db},
+	{0x00009bb4, 0x000eb7db},
+	{0x00009bb8, 0x000eb7db},
+	{0x00009bbc, 0x000eb7db},
+	{0x00009bc0, 0x000eb7db},
+	{0x00009bc4, 0x000eb7db},
+	{0x00009bc8, 0x000eb7db},
+	{0x00009bcc, 0x000eb7db},
+	{0x00009bd0, 0x000eb7db},
+	{0x00009bd4, 0x000eb7db},
+	{0x00009bd8, 0x000eb7db},
+	{0x00009bdc, 0x000eb7db},
+	{0x00009be0, 0x000eb7db},
+	{0x00009be4, 0x000eb7db},
+	{0x00009be8, 0x000eb7db},
+	{0x00009bec, 0x000eb7db},
+	{0x00009bf0, 0x000eb7db},
+	{0x00009bf4, 0x000eb7db},
+	{0x00009bf8, 0x000eb7db},
+	{0x00009bfc, 0x000eb7db},
+	{0x0000aa00, 0x00058084},
+	{0x0000aa04, 0x00058088},
+	{0x0000aa08, 0x0005808c},
+	{0x0000aa0c, 0x00058100},
+	{0x0000aa10, 0x00058104},
+	{0x0000aa14, 0x00058108},
+	{0x0000aa18, 0x0005810c},
+	{0x0000aa1c, 0x00058110},
+	{0x0000aa20, 0x00058114},
+	{0x0000aa24, 0x00058180},
+	{0x0000aa28, 0x00058184},
+	{0x0000aa2c, 0x00058188},
+	{0x0000aa30, 0x0005818c},
+	{0x0000aa34, 0x00058190},
+	{0x0000aa38, 0x00058194},
+	{0x0000aa3c, 0x000581a0},
+	{0x0000aa40, 0x0005820c},
+	{0x0000aa44, 0x000581a8},
+	{0x0000aa48, 0x00058284},
+	{0x0000aa4c, 0x00058288},
+	{0x0000aa50, 0x00058224},
+	{0x0000aa54, 0x00058290},
+	{0x0000aa58, 0x00058300},
+	{0x0000aa5c, 0x00058304},
+	{0x0000aa60, 0x00058308},
+	{0x0000aa64, 0x0005830c},
+	{0x0000aa68, 0x00058380},
+	{0x0000aa6c, 0x00058384},
+	{0x0000aa70, 0x00068700},
+	{0x0000aa74, 0x00068704},
+	{0x0000aa78, 0x00068708},
+	{0x0000aa7c, 0x0006870c},
+	{0x0000aa80, 0x00068780},
+	{0x0000aa84, 0x00068784},
+	{0x0000aa88, 0x00078b00},
+	{0x0000aa8c, 0x00078b04},
+	{0x0000aa90, 0x00078b08},
+	{0x0000aa94, 0x00078b0c},
+	{0x0000aa98, 0x00078b80},
+	{0x0000aa9c, 0x00078b84},
+	{0x0000aaa0, 0x00078b88},
+	{0x0000aaa4, 0x00078b8c},
+	{0x0000aaa8, 0x00078b90},
+	{0x0000aaac, 0x000caf80},
+	{0x0000aab0, 0x000caf84},
+	{0x0000aab4, 0x000caf88},
+	{0x0000aab8, 0x000caf8c},
+	{0x0000aabc, 0x000caf90},
+	{0x0000aac0, 0x000db30c},
+	{0x0000aac4, 0x000db310},
+	{0x0000aac8, 0x000db384},
+	{0x0000aacc, 0x000db388},
+	{0x0000aad0, 0x000db324},
+	{0x0000aad4, 0x000eb704},
+	{0x0000aad8, 0x000eb6a4},
+	{0x0000aadc, 0x000eb6a8},
+	{0x0000aae0, 0x000eb710},
+	{0x0000aae4, 0x000eb714},
+	{0x0000aae8, 0x000eb720},
+	{0x0000aaec, 0x000eb724},
+	{0x0000aaf0, 0x000eb728},
+	{0x0000aaf4, 0x000eb72c},
+	{0x0000aaf8, 0x000eb7a0},
+	{0x0000aafc, 0x000eb7a4},
+	{0x0000ab00, 0x000eb7a8},
+	{0x0000ab04, 0x000eb7b0},
+	{0x0000ab08, 0x000eb7b4},
+	{0x0000ab0c, 0x000eb7b8},
+	{0x0000ab10, 0x000eb7a5},
+	{0x0000ab14, 0x000eb7a9},
+	{0x0000ab18, 0x000eb7ad},
+	{0x0000ab1c, 0x000eb7b1},
+	{0x0000ab20, 0x000eb7b5},
+	{0x0000ab24, 0x000eb7b9},
+	{0x0000ab28, 0x000eb7c5},
+	{0x0000ab2c, 0x000eb7c9},
+	{0x0000ab30, 0x000eb7d1},
+	{0x0000ab34, 0x000eb7d5},
+	{0x0000ab38, 0x000eb7d9},
+	{0x0000ab3c, 0x000eb7c6},
+	{0x0000ab40, 0x000eb7ca},
+	{0x0000ab44, 0x000eb7ce},
+	{0x0000ab48, 0x000eb7d2},
+	{0x0000ab4c, 0x000eb7d6},
+	{0x0000ab50, 0x000eb7c3},
+	{0x0000ab54, 0x000eb7c7},
+	{0x0000ab58, 0x000eb7cb},
+	{0x0000ab5c, 0x000eb7cf},
+	{0x0000ab60, 0x000eb7d7},
+	{0x0000ab64, 0x000eb7db},
+	{0x0000ab68, 0x000eb7db},
+	{0x0000ab6c, 0x000eb7db},
+	{0x0000ab70, 0x000eb7db},
+	{0x0000ab74, 0x000eb7db},
+	{0x0000ab78, 0x000eb7db},
+	{0x0000ab7c, 0x000eb7db},
+	{0x0000ab80, 0x000eb7db},
+	{0x0000ab84, 0x000eb7db},
+	{0x0000ab88, 0x000eb7db},
+	{0x0000ab8c, 0x000eb7db},
+	{0x0000ab90, 0x000eb7db},
+	{0x0000ab94, 0x000eb7db},
+	{0x0000ab98, 0x000eb7db},
+	{0x0000ab9c, 0x000eb7db},
+	{0x0000aba0, 0x000eb7db},
+	{0x0000aba4, 0x000eb7db},
+	{0x0000aba8, 0x000eb7db},
+	{0x0000abac, 0x000eb7db},
+	{0x0000abb0, 0x000eb7db},
+	{0x0000abb4, 0x000eb7db},
+	{0x0000abb8, 0x000eb7db},
+	{0x0000abbc, 0x000eb7db},
+	{0x0000abc0, 0x000eb7db},
+	{0x0000abc4, 0x000eb7db},
+	{0x0000abc8, 0x000eb7db},
+	{0x0000abcc, 0x000eb7db},
+	{0x0000abd0, 0x000eb7db},
+	{0x0000abd4, 0x000eb7db},
+	{0x0000abd8, 0x000eb7db},
+	{0x0000abdc, 0x000eb7db},
+	{0x0000abe0, 0x000eb7db},
+	{0x0000abe4, 0x000eb7db},
+	{0x0000abe8, 0x000eb7db},
+	{0x0000abec, 0x000eb7db},
+	{0x0000abf0, 0x000eb7db},
+	{0x0000abf4, 0x000eb7db},
+	{0x0000abf8, 0x000eb7db},
+	{0x0000abfc, 0x000eb7db},
+	{0x0000a204, 0x00000004},
+	{0x0000a20c, 0x0001f000},
+	{0x0000b20c, 0x0001f000},
+	{0x0000a21c, 0x1883800a},
+	{0x0000a230, 0x00000108},
+	{0x0000a250, 0x0004a000},
+	{0x0000a358, 0x7999aa0e}
+};
+
+/**
+ * AR9271 TX init values for 2GHz mode operation.
+ * 
+ * Taken from Linux sources.
+ */
+static const uint32_t ar9271_2g_tx_array[][2] = {
+	{0x0000a300, 0x00010000},
+	{0x0000a304, 0x00016200},
+	{0x0000a308, 0x00018201},
+	{0x0000a30c, 0x0001b240},
+	{0x0000a310, 0x0001d241},
+	{0x0000a314, 0x0001f600},
+	{0x0000a318, 0x00022800},
+	{0x0000a31c, 0x00026802},
+	{0x0000a320, 0x0002b805},
+	{0x0000a324, 0x0002ea41},
+	{0x0000a328, 0x00038b00},
+	{0x0000a32c, 0x0003ab40},
+	{0x0000a330, 0x0003cd80},
+	{0x0000a334, 0x000368de},
+	{0x0000a338, 0x0003891e},
+	{0x0000a33c, 0x0003a95e},
+	{0x0000a340, 0x0003e9df},
+	{0x0000a344, 0x0003e9df},
+	{0x0000a348, 0x0003e9df},
+	{0x0000a34c, 0x0003e9df},
+	{0x0000a350, 0x0003e9df},
+	{0x0000a354, 0x0003e9df},
+	{0x00007838, 0x0000002b},
+	{0x00007824, 0x00d8a7ff},
+	{0x0000786c, 0x08609eba},
+	{0x00007820, 0x00000c00},
+	{0x0000a274, 0x0a214652},
+	{0x0000a278, 0x0e739ce7},
+	{0x0000a27c, 0x05018063},
+	{0x0000a394, 0x06318c63},
+	{0x0000a398, 0x00000063},
+	{0x0000a3dc, 0x06318c63},
+	{0x0000a3e0, 0x00000063}
+};
+
+/**
+ * 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, 0xc7ff000f},
+	{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, 0x00481083},/*< note: disabled ADHOC_MCAST_KEYID feature */
+	{0x00007010, 0x00000030},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00007800, 0x00140000},
+	{0x00007804, 0x0e4548d8},
+	{0x00007808, 0x54214514},
+	{0x0000780c, 0x02025820},
+	{0x00007810, 0x71c0d388},
+	{0x00007814, 0x924934a8},
+	{0x0000781c, 0x00000000},
+	{0x00007828, 0x66964300},
+	{0x0000782c, 0x8db6d961},
+	{0x00007830, 0x8db6d96c},
+	{0x00007834, 0x6140008b},
+	{0x0000783c, 0x72ee0a72},
+	{0x00007840, 0xbbfffffc},
+	{0x00007844, 0x000c0db6},
+	{0x00007848, 0x6db6246f},
+	{0x0000784c, 0x6d9b66db},
+	{0x00007850, 0x6d8c6dba},
+	{0x00007854, 0x00040000},
+	{0x00007858, 0xdb003012},
+	{0x0000785c, 0x04924914},
+	{0x00007860, 0x21084210},
+	{0x00007864, 0xf7d7ffde},
+	{0x00007868, 0xc2034080},
+	{0x00007870, 0x10142c00},
+	{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/nic/ar9271/ar9271.ma
===================================================================
--- uspace/drv/nic/ar9271/ar9271.ma	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ar9271.ma	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,1 @@
+90 usb&vendor=0x0cf3&product=0x9271
Index: uspace/drv/nic/ar9271/ath.h
===================================================================
--- uspace/drv/nic/ar9271/ath.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ath.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015 Jan Kolarik
+ * 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 ath.h
+ *
+ * Atheros generic wifi device functions definitions.
+ *
+ */
+
+#ifndef ATHEROS_ATH_H
+#define	ATHEROS_ATH_H
+
+struct ath;
+
+/** Atheros wifi operations. */
+typedef struct {
+	int (*send_ctrl_message)(struct ath *, void *, size_t);
+	int (*read_ctrl_message)(struct ath *, void *, size_t, size_t *);
+	int (*send_data_message)(struct ath *, void *, size_t);
+	int (*read_data_message)(struct ath *, void *, size_t, size_t *);
+} ath_ops_t;
+
+/** 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;
+	
+	/** Generic Atheros wifi operations. */
+	const ath_ops_t *ops;
+} ath_t;
+
+#endif	/* ATHEROS_ATH_H */
Index: uspace/drv/nic/ar9271/ath_usb.c
===================================================================
--- uspace/drv/nic/ar9271/ath_usb.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ath_usb.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2015 Jan Kolarik
+ * 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 ath_usb.c
+ *
+ * Implementation of Atheros USB wifi device functions.
+ *
+ */
+
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <malloc.h>
+
+#include "ath_usb.h"
+
+static int ath_usb_send_ctrl_message(ath_t *ath, void *buffer, 
+	size_t buffer_size);
+
+static int ath_usb_read_ctrl_message(ath_t *ath, void *buffer, 
+	size_t buffer_size, size_t *transferred_size);
+
+static int ath_usb_send_data_message(ath_t *ath, void *buffer, 
+	size_t buffer_size);
+
+static int ath_usb_read_data_message(ath_t *ath, void *buffer, 
+	size_t buffer_size, size_t *transferred_size);
+
+static ath_ops_t ath_usb_ops = {
+	.send_ctrl_message = ath_usb_send_ctrl_message,
+	.read_ctrl_message = ath_usb_read_ctrl_message,
+	.send_data_message = ath_usb_send_data_message,
+	.read_data_message = ath_usb_read_data_message
+};
+
+/**
+ * Initialize Atheros WiFi USB device.
+ * 
+ * @param ath Generic Atheros WiFi device structure.
+ * @param usb_device Connected USB device.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int ath_usb_init(ath_t *ath, usb_device_t *usb_device)
+{
+	ath_usb_t *ath_usb = malloc(sizeof(ath_usb_t));
+	if (!ath_usb) {
+		usb_log_error("Failed to allocate memory for ath usb device "
+		    "structure.\n");
+		return ENOMEM;
+	}
+	
+	ath_usb->usb_device = usb_device;
+	
+	/* TODO: Assign by iterating over pipes. */
+	ath_usb->output_data_pipe_number = 0;
+	ath_usb->input_data_pipe_number = 1;
+	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;
+	ath->ops = &ath_usb_ops;
+	
+	return EOK;
+}
+
+/**
+ * Send control message.
+ * 
+ * @param ath Generic Atheros WiFi device structure. 
+ * @param buffer Buffer with data to send.
+ * @param buffer_size Buffer size.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int ath_usb_send_ctrl_message(ath_t *ath, void *buffer, 
+	size_t buffer_size)
+{
+	ath_usb_t *ath_usb = (ath_usb_t *) ath->specific_data;
+	usb_pipe_t *pipe = 
+		&ath_usb->usb_device->pipes[ath_usb->output_ctrl_pipe_number].
+		pipe;
+	
+	return usb_pipe_write(pipe, buffer, buffer_size);
+}
+
+/**
+ * Read control message.
+ * 
+ * @param ath Generic Atheros WiFi device structure. 
+ * @param buffer Buffer with data to send.
+ * @param buffer_size Buffer size.
+ * @param transferred_size Real size of read data.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int ath_usb_read_ctrl_message(ath_t *ath, void *buffer, 
+	size_t buffer_size, size_t *transferred_size)
+{
+	ath_usb_t *ath_usb = (ath_usb_t *) ath->specific_data;
+	usb_pipe_t *pipe = 
+		&ath_usb->usb_device->pipes[ath_usb->input_ctrl_pipe_number].
+		pipe;
+	
+	return usb_pipe_read(pipe, buffer, buffer_size, transferred_size);
+}
+
+/**
+ * Send data message.
+ * 
+ * @param ath Generic Atheros WiFi device structure. 
+ * @param buffer Buffer with data to send.
+ * @param buffer_size Buffer size.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int ath_usb_send_data_message(ath_t *ath, void *buffer, 
+	size_t buffer_size)
+{
+	size_t complete_buffer_size = buffer_size + 
+		sizeof(ath_usb_data_header_t);
+	void *complete_buffer = malloc(complete_buffer_size);
+	memcpy(complete_buffer + sizeof(ath_usb_data_header_t), 
+		buffer, buffer_size);
+	
+	ath_usb_data_header_t *data_header = 
+		(ath_usb_data_header_t *) complete_buffer;
+	data_header->length = host2uint16_t_le(buffer_size);
+	data_header->tag = host2uint16_t_le(TX_TAG);
+	
+	ath_usb_t *ath_usb = (ath_usb_t *) ath->specific_data;
+	usb_pipe_t *pipe = 
+		&ath_usb->usb_device->pipes[ath_usb->output_data_pipe_number].
+		pipe;
+	
+	int ret_val = usb_pipe_write(pipe, complete_buffer, 
+		complete_buffer_size);
+	
+	free(complete_buffer);
+	
+	return ret_val;
+}
+
+/**
+ * Read data message.
+ * 
+ * @param ath Generic Atheros WiFi device structure. 
+ * @param buffer Buffer with data to send.
+ * @param buffer_size Buffer size.
+ * @param transferred_size Real size of read data.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int ath_usb_read_data_message(ath_t *ath, void *buffer, 
+	size_t buffer_size, size_t *transferred_size)
+{
+	ath_usb_t *ath_usb = (ath_usb_t *) ath->specific_data;
+	usb_pipe_t *pipe = 
+		&ath_usb->usb_device->pipes[ath_usb->input_data_pipe_number].
+		pipe;
+	
+	return usb_pipe_read(pipe, buffer, buffer_size, 
+		transferred_size);
+}
Index: uspace/drv/nic/ar9271/ath_usb.h
===================================================================
--- uspace/drv/nic/ar9271/ath_usb.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ath_usb.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015 Jan Kolarik
+ * 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 ath_usb.h
+ *
+ * Definitions of Atheros USB wifi device functions.
+ *
+ */
+
+#ifndef ATHEROS_ATH_USB_H
+#define	ATHEROS_ATH_USB_H
+
+#include <usb/dev/driver.h>
+
+#include "ath.h"
+
+#define RX_TAG 0x4e00
+#define TX_TAG 0x697e
+
+/** Atheros USB wifi device structure */
+typedef struct {
+	/** USB pipes indexes */
+	int input_ctrl_pipe_number;
+	int output_ctrl_pipe_number;
+	int input_data_pipe_number;
+	int output_data_pipe_number;
+	
+	/** Pointer to connected USB device. */
+	usb_device_t *usb_device;
+} ath_usb_t;
+
+typedef struct {
+	uint16_t length;		/**< Little Endian value! */
+	uint16_t tag;		/**< Little Endian value! */
+} ath_usb_data_header_t;
+
+extern int ath_usb_init(ath_t *ath, usb_device_t *usb_device);
+
+#endif	/* ATHEROS_ATH_USB_H */
Index: uspace/drv/nic/ar9271/htc.c
===================================================================
--- uspace/drv/nic/ar9271/htc.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/htc.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2014 Jan Kolarik
+ * 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 htc.c
+ *
+ * Implementation of Atheros HTC communication.
+ *
+ */
+
+#include <usb/debug.h>
+#include <byteorder.h>
+#include <errno.h>
+
+#include "wmi.h"
+#include "htc.h"
+#include "nic/nic.h"
+#include "ar9271.h"
+
+/**
+ * HTC download pipes mapping.
+ * 
+ * @param service_id Identification of WMI service.
+ * 
+ * @return Number of pipe used for this service.
+ */
+static inline uint8_t wmi_service_to_download_pipe(wmi_services_t service_id)
+{
+	return (service_id == WMI_CONTROL_SERVICE) ? 3 : 2;
+}
+
+/**
+ * HTC upload pipes mapping.
+ * 
+ * @param service_id Identification of WMI service.
+ * 
+ * @return Number of pipe used for this service.
+ */
+static inline uint8_t wmi_service_to_upload_pipe(wmi_services_t service_id)
+{
+	return (service_id == WMI_CONTROL_SERVICE) ? 4 : 1;
+}
+
+int htc_init_new_vif(htc_device_t *htc_device)
+{
+	htc_vif_msg_t vif_msg;
+	htc_sta_msg_t sta_msg;
+	
+	memset(&vif_msg, 0, sizeof(htc_vif_msg_t));
+	memset(&sta_msg, 0, sizeof(htc_sta_msg_t));
+	
+	nic_address_t addr;
+	nic_t *nic = nic_get_from_ddf_dev(ieee80211_get_ddf_dev(htc_device->ieee80211_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 = 
+		ieee80211_query_current_op_mode(htc_device->ieee80211_dev);
+	
+	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);
+	
+	wmi_send_command(htc_device, WMI_VAP_CREATE, (uint8_t *) &vif_msg, 
+		sizeof(vif_msg), NULL);
+	
+	sta_msg.is_vif_sta = 1;
+	sta_msg.max_ampdu = host2uint16_t_be(0xFFFF);
+	sta_msg.sta_index = 0;
+	sta_msg.vif_index = 0;
+	
+	wmi_send_command(htc_device, WMI_NODE_CREATE, (uint8_t *) &sta_msg, 
+		sizeof(sta_msg), NULL);
+	
+	/* Write first 4 bytes of MAC address. */
+	uint32_t id0;
+	memcpy(&id0, &addr.address, 4);
+	id0 = host2uint32_t_le(id0);
+	wmi_reg_write(htc_device, AR9271_STATION_ID0, id0);
+
+	/* Write last 2 bytes of MAC address (and preserve existing data). */
+	uint32_t id1;
+	wmi_reg_read(htc_device, AR9271_STATION_ID1, &id1);
+
+	uint16_t id1_addr;
+	memcpy(&id1_addr, &addr.address[4], 2);
+	id1 = (id1 & ~AR9271_STATION_ID1_MASK) | host2uint16_t_le(id1_addr);
+	wmi_reg_write(htc_device, AR9271_STATION_ID1, id1);
+	
+	/* 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)
+{
+	memset(header, 0, sizeof(htc_frame_header_t));
+	
+	header->endpoint_id = endpoint_id;
+	header->payload_length = 
+		host2uint16_t_be(buffer_size - sizeof(htc_frame_header_t));
+}
+
+/**
+ * Send control 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_control_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_ctrl_message(ath_device, buffer, 
+		buffer_size);
+}
+
+/**
+ * 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.
+ * @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_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)
+{
+	ath_t *ath_device = htc_device->ath_device;
+	
+	return ath_device->ops->read_ctrl_message(ath_device, buffer, 
+		buffer_size, transferred_size);
+}
+
+/**
+ * Initialize HTC service.
+ * 
+ * @param htc_device HTC device structure.
+ * @param service_id Identification of WMI service.
+ * @param response_endpoint_no HTC endpoint to be used for this service.
+ * 
+ * @return EOK if succeed, EINVAL when failed to connect service, 
+ * negative error code otherwise.
+ */
+static int htc_connect_service(htc_device_t *htc_device, 
+    wmi_services_t service_id, int *response_endpoint_no)
+{
+	size_t buffer_size = sizeof(htc_frame_header_t) + 
+		sizeof(htc_service_msg_t);
+	void *buffer = malloc(buffer_size);
+	memset(buffer, 0, buffer_size);
+	
+	/* Fill service message structure. */
+	htc_service_msg_t *service_message = (htc_service_msg_t *)
+		((void *) buffer + sizeof(htc_frame_header_t));
+	service_message->service_id = 
+		host2uint16_t_be(service_id);
+	service_message->message_id = 
+		host2uint16_t_be(HTC_MESSAGE_CONNECT_SERVICE);
+	service_message->download_pipe_id = 
+		wmi_service_to_download_pipe(service_id);
+	service_message->upload_pipe_id = 
+		wmi_service_to_upload_pipe(service_id);
+	service_message->connection_flags = 0;
+	
+	/* Send HTC message. */
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size,
+		htc_device->endpoints.ctrl_endpoint);
+	if(rc != EOK) {
+		free(buffer);
+		usb_log_error("Failed to send HTC message. Error: %d\n", rc);
+		return rc;
+	}
+	
+	free(buffer);
+	
+	buffer_size = htc_device->ath_device->ctrl_response_length;
+	buffer = malloc(buffer_size);
+	
+	/* Read response from device. */
+	rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
+	if(rc != EOK) {
+		free(buffer);
+		usb_log_error("Failed to receive HTC service connect response. "
+			"Error: %d\n", rc);
+		return rc;
+	}
+	
+	htc_service_resp_msg_t *response_message = (htc_service_resp_msg_t *)
+		((void *) buffer + sizeof(htc_frame_header_t));
+
+	/* If service was successfully connected, write down HTC endpoint number
+	 * that will be used for communication. */
+	if(response_message->status == HTC_SERVICE_SUCCESS) {
+		*response_endpoint_no = response_message->endpoint_id;
+		rc = EOK;
+	} else {
+		usb_log_error("Failed to connect HTC service. "
+			"Message status: %d\n", response_message->status);
+		rc = EINVAL;
+        }
+	
+	free(buffer);
+	
+	return rc;
+}
+
+/**
+ * HTC credits initialization message.
+ * 
+ * @param htc_device HTC device structure.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int htc_config_credits(htc_device_t *htc_device)
+{
+	size_t buffer_size = sizeof(htc_frame_header_t) + 
+		sizeof(htc_config_msg_t);
+	void *buffer = malloc(buffer_size);
+	htc_config_msg_t *config_message = (htc_config_msg_t *)
+		((void *) buffer + sizeof(htc_frame_header_t));
+	
+	config_message->message_id = 
+		host2uint16_t_be(HTC_MESSAGE_CONFIG);
+	/* Magic number to initialize device. */
+	config_message->credits = 33;
+	config_message->pipe_id = 1;
+
+	/* Send HTC message. */
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size,
+		htc_device->endpoints.ctrl_endpoint);
+	if(rc != EOK) {
+		free(buffer);
+		usb_log_error("Failed to send HTC config message. "
+			"Error: %d\n", rc);
+		return rc;
+	}
+	
+	free(buffer);
+	
+	buffer_size = htc_device->ath_device->ctrl_response_length;
+	buffer = malloc(buffer_size);
+
+	/* Check response from device. */
+	rc = htc_read_control_message(htc_device, buffer, buffer_size, NULL);
+	if(rc != EOK) {
+		usb_log_error("Failed to receive HTC config response message. "
+			"Error: %d\n", rc);
+	}
+	
+	free(buffer);
+
+	return rc;
+}
+
+/**
+ * HTC setup complete confirmation message.
+ * 
+ * @param htc_device HTC device structure.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int htc_complete_setup(htc_device_t *htc_device)
+{
+	size_t buffer_size = sizeof(htc_frame_header_t) + 
+		sizeof(htc_setup_complete_msg_t);
+	void *buffer = malloc(buffer_size);
+	htc_setup_complete_msg_t *complete_message = 
+		(htc_setup_complete_msg_t *)
+		((void *) buffer + sizeof(htc_frame_header_t));
+	
+	complete_message->message_id = 
+		host2uint16_t_be(HTC_MESSAGE_SETUP_COMPLETE);
+
+	/* Send HTC message. */
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size, 
+		htc_device->endpoints.ctrl_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Failed to send HTC setup complete message. "
+			"Error: %d\n", rc);
+	}
+	
+	free(buffer);
+
+	return rc;
+}
+
+/**
+ * Try to fetch ready message from device.
+ * Checks that firmware was successfully loaded on device side.
+ * 
+ * @param htc_device HTC device structure.
+ * 
+ * @return EOK if succeed, EINVAL if response error, negative error code 
+ * otherwise.
+ */
+static int htc_check_ready(htc_device_t *htc_device)
+{
+	size_t buffer_size = htc_device->ath_device->ctrl_response_length;
+	void *buffer = malloc(buffer_size);
+
+	/* Read response from device. */
+	int rc = htc_read_control_message(htc_device, buffer, buffer_size, 
+		NULL);
+	if(rc != EOK) {
+		free(buffer);
+		usb_log_error("Failed to receive HTC check ready message. "
+			"Error: %d\n", rc);
+		return rc;
+	}
+
+	uint16_t *message_id = (uint16_t *) ((void *) buffer + 
+		sizeof(htc_frame_header_t));
+	if(uint16_t_be2host(*message_id) == HTC_MESSAGE_READY) {
+		rc = EOK;
+	} else {
+		rc = EINVAL;
+	}
+	
+	free(buffer);
+	
+	return rc;
+}
+
+/**
+ * Initialize HTC device structure.
+ * 
+ * @param ath_device Atheros WiFi device connected with this HTC device.
+ * @param htc_device HTC device structure to be initialized.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+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);
+	
+	htc_device->endpoints.ctrl_endpoint = 0;
+	
+	htc_device->ath_device = ath_device;
+	htc_device->ieee80211_dev = ieee80211_dev;
+	
+	return EOK;
+}
+
+/**
+ * HTC communication initalization.
+ * 
+ * @param htc_device HTC device structure.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int htc_init(htc_device_t *htc_device)
+{
+	/* First check ready message in device. */
+	int rc = htc_check_ready(htc_device);
+	if(rc != EOK) {
+		usb_log_error("Device is not in ready state after loading "
+			"firmware.\n");
+		return rc;
+	}
+
+	/* 
+	 * HTC services initialization start.
+	 * 
+	 */
+	
+	rc = htc_connect_service(htc_device, WMI_CONTROL_SERVICE,
+	    &htc_device->endpoints.wmi_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing WMI service.\n");
+		return rc;
+	}
+
+	rc = htc_connect_service(htc_device, WMI_BEACON_SERVICE,
+	    &htc_device->endpoints.beacon_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing beacon service.\n");
+		return rc;
+	}
+
+	rc = htc_connect_service(htc_device, WMI_CAB_SERVICE,
+	    &htc_device->endpoints.cab_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing CAB service.\n");
+		return rc;
+	}
+
+	rc = htc_connect_service(htc_device, WMI_UAPSD_SERVICE,
+	    &htc_device->endpoints.uapsd_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing UAPSD service.\n");
+		return rc;
+	}
+
+	rc = htc_connect_service(htc_device, WMI_MGMT_SERVICE,
+	    &htc_device->endpoints.mgmt_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing MGMT service.\n");
+		return rc;
+	}
+	
+	rc = htc_connect_service(htc_device, WMI_DATA_BE_SERVICE,
+	    &htc_device->endpoints.data_be_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing data best effort "
+		    "service.\n");
+		return rc;
+	}
+
+	rc = htc_connect_service(htc_device, WMI_DATA_BK_SERVICE,
+	    &htc_device->endpoints.data_bk_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing data background "
+		    "service.\n");
+		return rc;
+	}
+
+	rc = htc_connect_service(htc_device, WMI_DATA_VIDEO_SERVICE,
+	    &htc_device->endpoints.data_video_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing data video service.\n");
+		return rc;
+	}
+	
+	rc = htc_connect_service(htc_device, WMI_DATA_VOICE_SERVICE,
+	    &htc_device->endpoints.data_voice_endpoint);
+	if(rc != EOK) {
+		usb_log_error("Error while initalizing data voice service.\n");
+		return rc;
+	}
+
+	/* 
+	 * HTC services initialization end.
+	 * 
+	 */
+
+	/* Credits initialization message. */
+	rc = htc_config_credits(htc_device);
+	if(rc != EOK) {
+		usb_log_error("Failed to send HTC config message.\n");
+		return rc;
+	}
+
+	/* HTC setup complete confirmation message. */
+	rc = htc_complete_setup(htc_device);
+	if(rc != EOK) {
+		usb_log_error("Failed to send HTC complete setup message.\n");
+		return rc;
+	}
+
+	usb_log_info("HTC services initialization finished successfully.\n");
+	
+	return EOK;
+}
Index: uspace/drv/nic/ar9271/htc.h
===================================================================
--- uspace/drv/nic/ar9271/htc.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/htc.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2014 Jan Kolarik
+ * 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 htc.h
+ *
+ * Definitions of the Atheros HTC (Host Target Communication) technology 
+ * for communication between host (PC) and target (device firmware).
+ *
+ */
+
+#ifndef ATHEROS_HTC_H
+#define	ATHEROS_HTC_H
+
+#include <ieee80211.h>
+#include <usb/dev/driver.h>
+#include <sys/types.h>
+#include <nic.h>
+
+#include "ath.h"
+
+#define HTC_RTS_THRESHOLD 2304
+#define HTC_RX_HEADER_LENGTH 40
+
+/**
+ * HTC message IDs
+ */
+typedef enum {
+	HTC_MESSAGE_READY = 1,
+	HTC_MESSAGE_CONNECT_SERVICE,
+        HTC_MESSAGE_CONNECT_SERVICE_RESPONSE,
+        HTC_MESSAGE_SETUP_COMPLETE,
+        HTC_MESSAGE_CONFIG
+} htc_message_id_t;
+
+/**
+ * HTC response message status codes
+ */
+typedef enum {
+        HTC_SERVICE_SUCCESS = 0,
+        HTC_SERVICE_NOT_FOUND,
+        HTC_SERVICE_FAILED,
+        HTC_SERVICE_NO_RESOURCES,
+        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;
+
+/**
+ * HTC endpoint numbers
+ */
+typedef struct {
+        int ctrl_endpoint;
+	int wmi_endpoint;
+	int beacon_endpoint;
+	int cab_endpoint;
+	int uapsd_endpoint;
+	int mgmt_endpoint;
+	int data_be_endpoint;
+	int data_bk_endpoint;
+	int data_video_endpoint;
+	int data_voice_endpoint;
+} htc_pipes_t;
+
+/**
+ * HTC device data
+ */
+typedef struct {
+        /** WMI message sequence number */
+        uint16_t sequence_number;
+    
+	/** HTC endpoints numbers */
+	htc_pipes_t endpoints;
+	
+	/** Lock for receiver */
+	fibril_mutex_t rx_lock;
+	
+	/** Lock for transmitter */
+	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;
+} htc_device_t;
+
+/** 
+ * HTC frame header structure 
+ */
+typedef struct {
+	uint8_t   endpoint_id;
+	uint8_t   flags;
+	uint16_t  payload_length;	/**< Big Endian value! */
+	uint8_t   control_bytes[4];
+    
+	/* 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;
+
+/** 
+ * HTC ready message structure 
+ */
+typedef struct {
+        uint16_t message_id;		/**< Big Endian value! */
+        uint16_t credits;		/**< Big Endian value! */
+        uint16_t credit_size;		/**< Big Endian value! */
+        
+        uint8_t max_endpoints;
+	uint8_t pad;
+} __attribute__((packed)) htc_ready_msg_t;
+
+/** 
+ * HTC service message structure 
+ */
+typedef struct {
+	uint16_t message_id;		/**< Big Endian value! */
+	uint16_t service_id;		/**< Big Endian value! */
+	uint16_t connection_flags;	/**< Big Endian value! */
+	
+	uint8_t download_pipe_id;
+	uint8_t upload_pipe_id;
+	uint8_t service_meta_length;
+	uint8_t pad;
+} __attribute__((packed)) htc_service_msg_t;
+
+/** 
+ * HTC service response message structure 
+ */
+typedef struct {
+        uint16_t message_id;            /**< Big Endian value! */
+        uint16_t service_id;            /**< Big Endian value! */
+        uint8_t status;
+        uint8_t endpoint_id;
+        uint16_t max_message_length;    /**< Big Endian value! */
+        uint8_t service_meta_length;
+        uint8_t pad;
+} __attribute__((packed)) htc_service_resp_msg_t;
+
+/**
+ * HTC credits config message structure
+ */
+typedef struct {
+        uint16_t message_id;            /**< Big Endian value! */
+        uint8_t pipe_id;
+        uint8_t credits;
+} __attribute__((packed)) htc_config_msg_t;
+
+/**
+ * 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 message to inform target about available capabilities.
+ */
+typedef struct {
+	uint32_t ampdu_limit;	/**< Big Endian value! */
+	uint8_t ampdu_subframes;
+	uint8_t enable_coex;
+	uint8_t tx_chainmask;
+	uint8_t pad;
+} __attribute__((packed)) htc_cap_msg_t;
+
+/**
+ * HTC setup complete message structure
+ */
+typedef struct {
+        uint16_t message_id;            /**< Big Endian value! */
+} __attribute__((packed)) htc_setup_complete_msg_t;
+
+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_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_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/nic/ar9271/hw.c
===================================================================
--- uspace/drv/nic/ar9271/hw.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/hw.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2015 Jan Kolarik
+ * 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 hw.c
+ *
+ * AR9271 hardware related functions implementation.
+ *
+ */
+
+#include <macros.h>
+#include <usb/debug.h>
+#include <unistd.h>
+#include <nic.h>
+#include <ieee80211.h>
+
+#include "hw.h"
+#include "wmi.h"
+
+/**
+ * Try to wait for register value repeatedly until timeout defined by device 
+ * is reached.
+ * 
+ * @param ar9271 Device structure.
+ * @param offset Registry offset (address) to be read.
+ * @param mask Mask to apply on read result.
+ * @param value Required value we are waiting for.
+ * 
+ * @return EOK if succeed, ETIMEOUT on timeout, negative error code otherwise.
+ */
+static int hw_read_wait(ar9271_t *ar9271, uint32_t offset, uint32_t mask,
+	uint32_t value)
+{
+	uint32_t result;
+	
+	for(size_t i = 0; i < HW_WAIT_LOOPS; i++) {
+		udelay(HW_WAIT_TIME_US);
+
+		wmi_reg_read(ar9271->htc_device, offset, &result);
+		if((result & mask) == value) {
+			return EOK;
+		}
+	}
+	
+	return ETIMEOUT;
+}
+
+static int hw_reset_power_on(ar9271_t *ar9271)
+{
+	wmi_reg_t buffer[] = {
+		{
+			.offset = AR9271_RTC_FORCE_WAKE,
+			.value = AR9271_RTC_FORCE_WAKE_ENABLE | 
+				AR9271_RTC_FORCE_WAKE_ON_INT
+		},
+		{
+			.offset = AR9271_RC,
+			.value = AR9271_RC_AHB
+		},
+		{
+			.offset = AR9271_RTC_RESET,
+			.value = 0
+		}
+	};
+	
+	wmi_reg_buffer_write(ar9271->htc_device, buffer,
+		sizeof(buffer) / sizeof(wmi_reg_t));
+	
+	udelay(2);
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_RC, 0);
+	wmi_reg_write(ar9271->htc_device, AR9271_RTC_RESET, 1);
+	
+	int rc = hw_read_wait(ar9271, 
+		AR9271_RTC_STATUS, 
+		AR9271_RTC_STATUS_MASK, 
+		AR9271_RTC_STATUS_ON);
+	if(rc != EOK) {
+		usb_log_error("Failed to wait for RTC wake up register.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int hw_set_reset(ar9271_t *ar9271, bool cold)
+{
+	uint32_t reset_value = AR9271_RTC_RC_MAC_WARM;
+	
+	if(cold) {
+		reset_value |= AR9271_RTC_RC_MAC_COLD;
+	}
+	
+	wmi_reg_t buffer[] = {
+		{
+			.offset = AR9271_RTC_FORCE_WAKE,
+			.value = AR9271_RTC_FORCE_WAKE_ENABLE | 
+				AR9271_RTC_FORCE_WAKE_ON_INT
+		},
+		{
+			.offset = AR9271_RC,
+			.value = AR9271_RC_AHB
+		},
+		{
+			.offset = AR9271_RTC_RC,
+			.value = reset_value
+		}
+	};
+	
+	wmi_reg_buffer_write(ar9271->htc_device, buffer, 
+		sizeof(buffer) / sizeof(wmi_reg_t));
+	
+	udelay(100);
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_RTC_RC, 0);
+	
+	int rc = hw_read_wait(ar9271, AR9271_RTC_RC, AR9271_RTC_RC_MASK, 0);
+	if(rc != EOK) {
+		usb_log_error("Failed to wait for RTC RC register.\n");
+		return rc;
+	}
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_RC, 0);
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_STATION_ID1, 
+		AR9271_STATION_ID1_POWER_SAVING);
+	
+	return EOK;
+}
+
+static int hw_addr_init(ar9271_t *ar9271)
+{
+	uint32_t value;
+	nic_address_t ar9271_address;
+	
+	for(int i = 0; i < 3; i++) {
+		wmi_reg_read(ar9271->htc_device, 
+			AR9271_EEPROM_MAC_ADDR_START + i*4,
+			&value);
+		
+		uint16_t two_bytes = uint16_t_be2host(value);
+		ar9271_address.address[2*i] = two_bytes >> 8;
+		ar9271_address.address[2*i+1] = two_bytes & 0xff;
+	}
+	
+	nic_t *nic = nic_get_from_ddf_dev(ar9271->ddf_dev);
+	
+	int rc = nic_report_address(nic, &ar9271_address);
+	if(rc != EOK) {
+		usb_log_error("Failed to report NIC HW address.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int hw_gpio_set_output(ar9271_t *ar9271, uint32_t gpio, uint32_t type)
+{
+	uint32_t address, gpio_shift, temp;
+	
+	if(gpio > 11) {
+		address = AR9271_GPIO_OUT_MUX3;
+	} else if(gpio > 5) {
+		address = AR9271_GPIO_OUT_MUX2;
+	} else {
+		address = AR9271_GPIO_OUT_MUX1;
+	}
+	
+	gpio_shift = (gpio % 6) * 5;
+	
+	wmi_reg_read(ar9271->htc_device, address, &temp);
+
+	temp = ((temp & 0x1F0) << 1) | (temp & ~0x1F0);
+	temp &= ~(0x1f << gpio_shift);
+	temp |= (type << gpio_shift);
+
+	wmi_reg_write(ar9271->htc_device, address, temp);
+	
+	gpio_shift = 2 * gpio;
+	
+	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);
+	
+	return EOK;
+}
+
+static int hw_gpio_set_value(ar9271_t *ar9271, uint32_t gpio, uint32_t value)
+{
+	wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_GPIO_IN_OUT,
+		(~value & 1) << gpio, 1 << gpio);
+	return EOK;
+}
+
+/**
+ * Hardware init procedure of AR9271 device.
+ * 
+ * @param ar9271 Device structure.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+static int hw_init_proc(ar9271_t *ar9271)
+{
+	int rc = hw_reset_power_on(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to HW reset power on.\n");
+		return rc;
+	}
+	
+	rc = hw_set_reset(ar9271, false);
+	if(rc != EOK) {
+		usb_log_error("Failed to HW warm reset.\n");
+		return rc;
+	}
+	
+	rc = hw_addr_init(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to init HW addr.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int hw_init_led(ar9271_t *ar9271)
+{
+	int rc = hw_gpio_set_output(ar9271, AR9271_LED_PIN, 
+		AR9271_GPIO_OUT_MUX_AS_OUT);
+	if(rc != EOK) {
+		usb_log_error("Failed to set led GPIO to output.\n");
+		return rc;
+	}
+	
+	rc = hw_gpio_set_value(ar9271, AR9271_LED_PIN, 0);
+	if(rc != EOK) {
+		usb_log_error("Failed to init bring up GPIO led.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int hw_set_operating_mode(ar9271_t *ar9271, 
+	ieee80211_operating_mode_t op_mode)
+{
+	uint32_t set_bit = 0x10000000;
+	
+	switch(op_mode) {
+		case IEEE80211_OPMODE_ADHOC:
+			set_bit |= AR9271_OPMODE_ADHOC_MASK;
+			wmi_reg_set_bit(ar9271->htc_device, AR9271_CONFIG,
+				AR9271_CONFIG_ADHOC);
+			break;
+		case IEEE80211_OPMODE_MESH:
+		case IEEE80211_OPMODE_AP:
+			set_bit |= AR9271_OPMODE_STATION_AP_MASK;
+		case IEEE80211_OPMODE_STATION:
+			wmi_reg_clear_bit(ar9271->htc_device, AR9271_CONFIG,
+				AR9271_CONFIG_ADHOC);
+	}
+	
+	wmi_reg_set_clear_bit(ar9271->htc_device, AR9271_STATION_ID1,
+		set_bit, 
+		AR9271_OPMODE_STATION_AP_MASK | AR9271_OPMODE_ADHOC_MASK);
+	
+	ieee80211_report_current_op_mode(ar9271->ieee80211_dev, op_mode);
+	
+	return EOK;
+}
+
+static int hw_reset_operating_mode(ar9271_t *ar9271)
+{
+	int rc = hw_set_operating_mode(ar9271, IEEE80211_OPMODE_STATION);
+	if(rc != EOK) {
+		usb_log_error("Failed to set opmode to station.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int hw_noise_floor_calibration(ar9271_t *ar9271)
+{
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_CALIB_EN);
+	
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_NOT_UPDATE);
+	
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_CALIB);
+	
+	return EOK;
+}
+
+static int hw_set_freq(ar9271_t *ar9271, uint16_t freq)
+{
+	/* Not supported channel frequency. */
+	if(freq < IEEE80211_FIRST_FREQ || freq > IEEE80211_MAX_FREQ) {
+		return EINVAL;
+	}
+	
+	/* Not supported channel frequency. */
+	if((freq - IEEE80211_FIRST_FREQ) % IEEE80211_CHANNEL_GAP != 0) {
+		return EINVAL;
+	}
+	
+	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,
+		tx_control & ~AR9271_PHY_CCK_TX_CTRL_JAPAN);
+	
+	/* Some magic here. */
+	uint32_t synth_ctl;
+	wmi_reg_read(ar9271->htc_device, AR9271_PHY_SYNTH_CONTROL, &synth_ctl);
+	synth_ctl &= 0xC0000000;
+	uint32_t channel_select = (freq * 0x10000) / 15;
+	synth_ctl = synth_ctl | (1 << 29) | (1 << 28) | channel_select;
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_SYNTH_CONTROL, synth_ctl);
+	
+	ieee80211_report_current_freq(ar9271->ieee80211_dev, freq);
+	
+	return EOK;
+}
+
+int hw_freq_switch(ar9271_t *ar9271, uint16_t freq)
+{
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_RFBUS_KILL, 0x1);
+	
+	int rc = hw_read_wait(ar9271, AR9271_PHY_RFBUS_GRANT, 0x1, 0x1);
+	if(rc != EOK) {
+		usb_log_error("Failed to kill RF bus.\n");
+		return rc;
+	}
+	
+	rc = hw_set_freq(ar9271, freq);
+	if(rc != EOK) {
+		usb_log_error("Failed to HW set frequency.\n");
+		return rc;
+	}
+	
+	udelay(1000);
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_RFBUS_KILL, 0x0);
+	
+	rc = hw_noise_floor_calibration(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to do NF calibration.\n");
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static int hw_set_rx_filter(ar9271_t *ar9271)
+{
+	uint32_t filter_bits;
+	
+	/* TODO: Do proper filtering here. */
+	
+	filter_bits = AR9271_RX_FILTER_UNI | AR9271_RX_FILTER_MULTI | 
+		AR9271_RX_FILTER_BROAD | AR9271_RX_FILTER_BEACON;
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_RX_FILTER, filter_bits);
+	
+	return EOK;
+}
+
+int hw_rx_init(ar9271_t *ar9271)
+{
+	wmi_reg_write(ar9271->htc_device, AR9271_COMMAND, 
+		AR9271_COMMAND_RX_ENABLE);
+	
+	int rc = hw_set_rx_filter(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to set RX filtering.\n");
+		return rc;
+	}
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_MULTICAST_FILTER1, ~0);
+	wmi_reg_write(ar9271->htc_device, AR9271_MULTICAST_FILTER2, ~0);
+	
+	/* Disable RX blocking. */
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_DIAG, (0x20 | 0x02000000));
+	
+	return EOK;
+}
+
+static int hw_activate_phy(ar9271_t *ar9271)
+{
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
+	udelay(1000);
+	
+	return EOK;
+}
+
+static int hw_init_pll(ar9271_t *ar9271)
+{
+	uint32_t pll;
+	
+	/* Some magic here (set for 2GHz channels). But VERY important :-) */
+	pll = (0x5 << 10) & 0x00003C00;
+	pll |= 0x2C & 0x000003FF;
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_RTC_PLL_CONTROL, pll);
+	
+	return EOK;
+}
+
+static int hw_set_init_values(ar9271_t *ar9271)
+{
+	uint32_t reg_offset, reg_value;
+	
+	int size = ARRAY_SIZE(ar9271_2g_mode_array);
+	
+	for(int i = 0; i < size; i++) {
+		reg_offset = ar9271_2g_mode_array[i][0];
+		reg_value = ar9271_2g_mode_array[i][1];
+		wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
+	}
+	
+	size = ARRAY_SIZE(ar9271_2g_tx_array);
+	
+	for(int i = 0; i < size; i++) {
+		reg_offset = ar9271_2g_tx_array[i][0];
+		reg_value = ar9271_2g_tx_array[i][1];
+		wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
+	}
+	
+	size = ARRAY_SIZE(ar9271_init_array);
+	
+	for(int i = 0; i < size; i++) {
+		reg_offset = ar9271_init_array[i][0];
+		reg_value = ar9271_init_array[i][1];
+		wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
+	}
+	
+	return EOK;
+}
+
+static int hw_calibration(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;
+}
+
+int hw_reset(ar9271_t *ar9271) 
+{
+	/* Set physical layer as deactivated. */
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 0);
+	
+	if(ar9271->starting_up) {
+		wmi_reg_write(ar9271->htc_device, 
+			AR9271_RESET_POWER_DOWN_CONTROL,
+			AR9271_RADIO_RF_RESET);
+
+		udelay(50);
+	}
+	
+	/* Cold reset when RX is enabled. */
+	uint32_t config_reg;
+	wmi_reg_read(ar9271->htc_device, AR9271_COMMAND, &config_reg);
+	if(config_reg & AR9271_COMMAND_RX_ENABLE) {
+		hw_set_reset(ar9271, true);
+	}
+	
+	int rc = hw_init_pll(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to init PLL.\n");
+		return rc;
+	}
+	
+	udelay(500);
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_CLOCK_CONTROL,	
+		AR9271_MAX_CPU_CLOCK);
+	
+	udelay(100);
+	
+	if(ar9271->starting_up) {
+		wmi_reg_write(ar9271->htc_device, 
+			AR9271_RESET_POWER_DOWN_CONTROL,
+			AR9271_GATE_MAC_CONTROL);
+
+		udelay(50);
+	}
+	
+	rc = hw_set_init_values(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to set device init values.\n");
+		return rc;
+	}
+	
+	/* Set physical layer mode. */
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_MODE, 
+		AR9271_PHY_MODE_DYNAMIC);
+	
+	/* Reset device operating mode. */
+	rc = hw_reset_operating_mode(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to reset operating mode.\n");
+		return rc;
+	}
+	
+	/* Set initial channel frequency. */
+	rc = hw_set_freq(ar9271, IEEE80211_FIRST_FREQ);
+	if(rc != EOK) {
+		usb_log_error("Failed to set channel.\n");
+		return rc;
+	}
+	
+	/* Initialize transmission queues. */
+	for(int i = 0; i < AR9271_QUEUES_COUNT; i++) {
+		wmi_reg_write(ar9271->htc_device, 
+			AR9271_QUEUE_BASE_MASK + (i << 2),
+			1 << i);
+	}
+	
+	/* Activate physical layer. */
+	rc = hw_activate_phy(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to activate physical layer.\n");
+		return rc;
+	}
+	
+	/* Calibration. */
+	rc = hw_calibration(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to calibrate device.\n");
+		return rc;
+	}
+	
+	rc = hw_noise_floor_calibration(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to calibrate noise floor.\n");
+		return rc;
+	}
+	
+	/* Byteswap TX and RX data buffer words. */
+	wmi_reg_write(ar9271->htc_device, AR9271_CONFIG, 0xA);
+	
+	usb_log_info("HW reset done.\n");
+	
+	return EOK;
+}
+
+/**
+ * Initialize hardware of AR9271 device.
+ * 
+ * @param ar9271 Device structure.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int hw_init(ar9271_t *ar9271)
+{
+	int rc = hw_init_proc(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to HW reset device.\n");
+		return rc;
+	}
+	
+	rc = hw_init_led(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to HW init led.\n");
+		return rc;
+	}
+	
+	usb_log_info("HW initialization finished successfully.\n");
+	
+	return EOK;
+}
Index: uspace/drv/nic/ar9271/hw.h
===================================================================
--- uspace/drv/nic/ar9271/hw.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/hw.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 Jan Kolarik
+ * 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 hw.h
+ *
+ * Definitions of AR9271 hardware related functions.
+ *
+ */
+
+#ifndef ATHEROS_HW_H
+#define	ATHEROS_HW_H
+
+#include "ar9271.h"
+
+#define HW_WAIT_LOOPS 1000
+#define HW_WAIT_TIME_US 10
+
+extern int hw_init(ar9271_t *ar9271);
+extern int hw_freq_switch(ar9271_t *, uint16_t freq);
+extern int hw_rx_init(ar9271_t *ar9271);
+extern int hw_reset(ar9271_t *ar9271);
+
+#endif	/* ATHEROS_HW_H */
Index: uspace/drv/nic/ar9271/wmi.c
===================================================================
--- uspace/drv/nic/ar9271/wmi.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/wmi.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2014 Jan Kolarik
+ * 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 wmi.c
+ *
+ * Implementation of Atheros WMI communication.
+ *
+ */
+
+#include <usb/debug.h>
+
+#include <malloc.h>
+#include <mem.h>
+#include <byteorder.h>
+
+#include "wmi.h"
+
+/**
+ * WMI registry read.
+ * 
+ * @param htc_device HTC device structure.
+ * @param reg_offset Registry offset (address) to be read.
+ * @param res Stored result.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_reg_read(htc_device_t *htc_device, uint32_t reg_offset, uint32_t *res)
+{
+	uint32_t cmd_value = host2uint32_t_be(reg_offset);
+	
+	void *resp_buffer = 
+		malloc(htc_device->ath_device->ctrl_response_length);
+	
+	int rc = wmi_send_command(htc_device, WMI_REG_READ, 
+		(uint8_t *) &cmd_value, sizeof(cmd_value), resp_buffer);
+	
+	if(rc != EOK) {
+		usb_log_error("Failed to read registry value.\n");
+		return rc;
+	}
+	
+	uint32_t *resp_value = (uint32_t *) ((void*) resp_buffer + 
+		sizeof(htc_frame_header_t) +
+		sizeof(wmi_command_header_t));
+	
+	*res = uint32_t_be2host(*resp_value);
+	
+	return rc;
+}
+
+/**
+ * WMI registry write.
+ * 
+ * @param htc_device HTC device structure.
+ * @param reg_offset Registry offset (address) to be written.
+ * @param val Value to be written
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_reg_write(htc_device_t *htc_device, uint32_t reg_offset, uint32_t val)
+{
+	uint32_t cmd_buffer[] = {
+	    host2uint32_t_be(reg_offset),
+	    host2uint32_t_be(val)
+	};
+	
+	void *resp_buffer = 
+		malloc(htc_device->ath_device->ctrl_response_length);
+	
+	int rc = wmi_send_command(htc_device, WMI_REG_WRITE, 
+		(uint8_t *) &cmd_buffer, sizeof(cmd_buffer), resp_buffer);
+	
+	free(resp_buffer);
+	
+	if(rc != EOK) {
+		usb_log_error("Failed to write registry value.\n");
+		return rc;
+	}
+	
+	return rc;
+}
+
+/**
+ * WMI registry set or clear specified bits.
+ * 
+ * @param htc_device HTC device structure.
+ * @param reg_offset Registry offset (address) to be written.
+ * @param set_bit Bit to be set.
+ * @param clear_bit Bit to be cleared.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_reg_set_clear_bit(htc_device_t *htc_device, uint32_t reg_offset, 
+	uint32_t set_bit, uint32_t clear_bit)
+{
+	uint32_t value;
+	
+	int rc = wmi_reg_read(htc_device, reg_offset, &value);
+	if(rc != EOK) {
+		usb_log_error("Failed to read registry value in RMW "
+			"function.\n");
+		return rc;
+	}
+	
+	value &= ~clear_bit;
+	value |= set_bit;
+	
+	rc = wmi_reg_write(htc_device, reg_offset, value);
+	if(rc != EOK) {
+		usb_log_error("Failed to write registry value in RMW "
+			"function.\n");
+		return rc;
+	}
+	
+	return rc;
+}
+
+/**
+ * WMI registry set specified bit.
+ * 
+ * @param htc_device HTC device structure.
+ * @param reg_offset Registry offset (address) to be written.
+ * @param set_bit Bit to be set.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_reg_set_bit(htc_device_t *htc_device, uint32_t reg_offset, 
+	uint32_t set_bit)
+{
+	return wmi_reg_set_clear_bit(htc_device, reg_offset, set_bit, 0);
+}
+
+/**
+ * WMI registry clear specified bit.
+ * 
+ * @param htc_device HTC device structure.
+ * @param reg_offset Registry offset (address) to be written.
+ * @param clear_bit Bit to be cleared.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_reg_clear_bit(htc_device_t *htc_device, uint32_t reg_offset, 
+	uint32_t clear_bit)
+{
+	return wmi_reg_set_clear_bit(htc_device, reg_offset, 0, clear_bit);
+}
+
+/**
+ * WMI multi registry write.
+ * 
+ * @param htc_device HTC device structure.
+ * @param reg_buffer Array of registry values to be written.
+ * @param elements Number of elements in array.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_reg_buffer_write(htc_device_t *htc_device, wmi_reg_t *reg_buffer,
+	size_t elements)
+{
+	size_t buffer_size = sizeof(wmi_reg_t) * elements;
+	void *buffer = malloc(buffer_size);
+	void *resp_buffer = 
+		malloc(htc_device->ath_device->ctrl_response_length);
+	
+	/* Convert values to correct endianness. */
+	for(size_t i = 0; i < elements; i++) {
+		wmi_reg_t *buffer_element = &reg_buffer[i];
+		wmi_reg_t *buffer_it = (wmi_reg_t *)
+			((void *) buffer + i*sizeof(wmi_reg_t));
+		buffer_it->offset = 
+			host2uint32_t_be(buffer_element->offset);
+		buffer_it->value =
+			host2uint32_t_be(buffer_element->value);
+	}
+	
+	int rc = wmi_send_command(htc_device, WMI_REG_WRITE, 
+		(uint8_t *) buffer, buffer_size, resp_buffer);
+	
+	free(buffer);
+	free(resp_buffer);
+	
+	if(rc != EOK) {
+		usb_log_error("Failed to write multi registry value.\n");
+		return rc;
+	}
+	
+	return rc;
+}
+
+/**
+ * Send WMI message to HTC device.
+ * 
+ * @param htc_device HTC device structure.
+ * @param command_id Command identification.
+ * @param command_buffer Buffer with command data.
+ * @param command_length Length of command data.
+ * @param response_buffer Buffer with response data.
+ * 
+ * @return EOK if succeed, negative error code otherwise.
+ */
+int wmi_send_command(htc_device_t *htc_device, wmi_command_t command_id, 
+    uint8_t *command_buffer, uint32_t command_length, void *response_buffer) 
+{
+	size_t header_size = sizeof(wmi_command_header_t) + 
+		sizeof(htc_frame_header_t);
+	size_t buffer_size = header_size + command_length;
+	void *buffer = malloc(buffer_size);
+	memcpy(buffer+header_size, command_buffer, command_length);
+	
+	/* Set up WMI header */
+	wmi_command_header_t *wmi_header = (wmi_command_header_t *)
+		((void *) buffer + sizeof(htc_frame_header_t));
+	wmi_header->command_id = 
+		host2uint16_t_be(command_id);
+	wmi_header->sequence_number = 
+		host2uint16_t_be(++htc_device->sequence_number);
+	
+	/* Send message. */
+	int rc = htc_send_control_message(htc_device, buffer, buffer_size,
+		htc_device->endpoints.wmi_endpoint);
+	if(rc != EOK) {
+		free(buffer);
+		usb_log_error("Failed to send WMI message. Error: %d\n", rc);
+		return rc;
+	}
+	
+	free(buffer);
+	
+	bool clean_resp_buffer = false;
+	size_t response_buffer_size = 
+		htc_device->ath_device->ctrl_response_length;
+	if(response_buffer == NULL) {
+		response_buffer = malloc(response_buffer_size);
+		clean_resp_buffer = true;
+	}
+	
+	/* Read response. */
+	rc = htc_read_control_message(htc_device, response_buffer, 
+		response_buffer_size, NULL);
+	if(rc != EOK) {
+		free(buffer);
+		usb_log_error("Failed to receive WMI message response. "
+		    "Error: %d\n", rc);
+		return rc;
+	}
+	
+	if(clean_resp_buffer) {
+		free(response_buffer);
+	}
+	
+	return rc;
+}
Index: uspace/drv/nic/ar9271/wmi.h
===================================================================
--- uspace/drv/nic/ar9271/wmi.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/wmi.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014 Jan Kolarik
+ * 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 wmi.h
+ *
+ * Definitions of the Atheros WMI protocol specified in the 
+ * Wireless Module Interface (WMI).
+ *
+ */
+
+#ifndef ATHEROS_WMI_H
+#define	ATHEROS_WMI_H
+
+#include "htc.h"
+
+/* Macros for creating service identificators. */
+#define WMI_SERVICE_GROUP 1
+#define CREATE_SERVICE_ID(group, i) (int) (((int) group << 8) | (int) (i))
+
+/**
+ * WMI header structure.
+ */
+typedef struct {
+    uint16_t command_id;		/**< Big Endian value! */
+    uint16_t sequence_number;           /**< Big Endian value! */
+} __attribute__((packed)) wmi_command_header_t;
+
+/**
+ * WMI services IDs
+ */
+typedef enum {
+	WMI_CONTROL_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 0),
+	WMI_BEACON_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 1),
+	WMI_CAB_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 2),
+	WMI_UAPSD_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 3),
+	WMI_MGMT_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 4),
+	WMI_DATA_VOICE_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 5),
+	WMI_DATA_VIDEO_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 6),
+	WMI_DATA_BE_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 7),
+	WMI_DATA_BK_SERVICE = CREATE_SERVICE_ID(WMI_SERVICE_GROUP, 8)
+} wmi_services_t;
+
+/**
+ * List of WMI commands
+ */
+typedef enum {
+	WMI_ECHO = 0x0001,
+	WMI_ACCESS_MEMORY,
+
+	/* Commands used for HOST -> DEVICE communication */
+	WMI_GET_FW_VERSION,
+	WMI_DISABLE_INTR,
+	WMI_ENABLE_INTR,
+	WMI_ATH_INIT,
+	WMI_ABORT_TXQ,
+	WMI_STOP_TX_DMA,
+	WMI_ABORT_TX_DMA,
+	WMI_DRAIN_TXQ,
+	WMI_DRAIN_TXQ_ALL,
+	WMI_START_RECV,
+	WMI_STOP_RECV,
+	WMI_FLUSH_RECV,
+	WMI_SET_MODE,
+	WMI_NODE_CREATE,
+	WMI_NODE_REMOVE,
+	WMI_VAP_REMOVE,
+	WMI_VAP_CREATE,
+	WMI_REG_READ,
+	WMI_REG_WRITE,
+	WMI_RC_STATE_CHANGE,
+	WMI_RC_RATE_UPDATE,
+	WMI_TARGET_IC_UPDATE,
+	WMI_TX_AGGR_ENABLE,
+	WMI_TGT_DETACH,
+	WMI_NODE_UPDATE,
+	WMI_INT_STATS,
+	WMI_TX_STATS,
+	WMI_RX_STATS,
+	WMI_BITRATE_MASK
+} wmi_command_t;
+
+/**
+ * Structure used when sending registry buffer
+ */
+typedef struct {
+	uint32_t offset;		/**< Big Endian value! */
+	uint32_t value;			/**< Big Endian value! */
+} wmi_reg_t;
+
+extern int wmi_reg_read(htc_device_t *htc_device, uint32_t reg_offset, 
+	uint32_t *res);
+extern int wmi_reg_write(htc_device_t *htc_device, uint32_t reg_offset, 
+	uint32_t val);
+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, 
+	uint32_t set_bit);
+extern int wmi_reg_clear_bit(htc_device_t *htc_device, uint32_t reg_offset, 
+	uint32_t clear_bit);
+extern int wmi_reg_buffer_write(htc_device_t *htc_device, 
+	wmi_reg_t *reg_buffer, size_t elements);
+extern int wmi_send_command(htc_device_t *htc_device, 
+	wmi_command_t command_id, 
+	uint8_t *command_buffer, uint32_t command_length, 
+	void *response_buffer);
+
+#endif	/* ATHEROS_WMI_H */
+
