diff -urN linux-2.6.24.7-rt20/arch/x86/kernel/reboot_32.c linux-2.6.24.7-rt20-atom/arch/x86/kernel/reboot_32.c
--- linux-2.6.24.7-rt20/arch/x86/kernel/reboot_32.c	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/arch/x86/kernel/reboot_32.c	2008-09-28 11:34:16.000000000 +0200
@@ -135,6 +135,16 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
 		},
 	},
+	{	/* Handle problems with rebooting on Intel Crown Beach board */
+		.callback = set_bios_reboot,
+		.ident = "Intel Crown Beach board",
+		.matches = {
+			/* Currently the DMI info is not customized and indicates 
+                         * OEM need change that */
+			DMI_MATCH(DMI_SYS_VENDOR, "To Be Filled By O.E.M."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "To Be Filled By O.E.M."),
+		},
+	},
 	{ }
 };
 
diff -urN linux-2.6.24.7-rt20/Documentation/thermal/sysfs-api.txt linux-2.6.24.7-rt20-atom/Documentation/thermal/sysfs-api.txt
--- linux-2.6.24.7-rt20/Documentation/thermal/sysfs-api.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/Documentation/thermal/sysfs-api.txt	2008-09-28 11:30:55.000000000 +0200
@@ -0,0 +1,247 @@
+Generic Thermal Sysfs driver How To
+=========================
+
+Written by Sujith Thomas <sujith.thomas@intel.com>, Zhang Rui <rui.zhang@intel.com>
+
+Updated: 2 January 2008
+
+Copyright (c)  2008 Intel Corporation
+
+
+0. Introduction
+
+The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors)
+and thermal cooling devices (fan, processor...) to register with the thermal management
+solution and to be a part of it.
+
+This how-to focusses on enabling new thermal zone and cooling devices to participate
+in thermal management.
+This solution is platform independent and any type of thermal zone devices and
+cooling devices should be able to make use of the infrastructure.
+
+The main task of the thermal sysfs driver is to expose thermal zone attributes as well
+as cooling device attributes to the user space.
+An intelligent thermal management application can make decisions based on inputs
+from thermal zone attributes (the current temperature and trip point temperature)
+and throttle appropriate devices.
+
+[0-*]	denotes any positive number starting from 0
+[1-*]	denotes any positive number starting from 1
+
+1. thermal sysfs driver interface functions
+
+1.1 thermal zone device interface
+1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips,
+				void *devdata, struct thermal_zone_device_ops *ops)
+
+	This interface function adds a new thermal zone device (sensor) to
+	/sys/class/thermal folder as thermal_zone[0-*].
+	It tries to bind all the thermal cooling devices registered at the same time.
+
+	name: the thermal zone name.
+	trips: the total number of trip points this thermal zone supports.
+	devdata: device private data
+	ops: thermal zone device callbacks.
+		.bind: bind the thermal zone device with a thermal cooling device.
+		.unbind: unbing the thermal zone device with a thermal cooling device.
+		.get_temp: get the current temperature of the thermal zone.
+		.get_mode: get the current mode (user/kernel) of the thermal zone.
+			   "kernel" means thermal management is done in kernel.
+			   "user" will prevent kernel thermal driver actions upon trip points
+			   so that user applications can take charge of thermal management.
+		.set_mode: set the mode (user/kernel) of the thermal zone.
+		.get_trip_type: get the type of certain trip point.
+		.get_trip_temp: get the temperature above which the certain trip point
+				will be fired.
+
+1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+
+	This interface function removes the thermal zone device.
+	It deletes the corresponding entry form /sys/class/thermal folder and unbind all
+	the thermal cooling devices it uses.
+
+1.2 thermal cooling device interface
+1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
+					void *devdata, struct thermal_cooling_device_ops *)
+
+	This interface function adds a new thermal cooling device (fan/processor/...) to
+	/sys/class/thermal/ folder as cooling_device[0-*].
+	It tries to bind itself to all the thermal zone devices register at the same time.
+	name: the cooling device name.
+	devdata: device private data.
+	ops: thermal cooling devices callbacks.
+		.get_max_state: get the Maximum throttle state of the cooling device.
+		.get_cur_state: get the Current throttle state of the cooling device.
+		.set_cur_state: set the Current throttle state of the cooling device.
+
+1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
+
+	This interface function remove the thermal cooling device.
+	It deletes the corresponding entry form /sys/class/thermal folder and unbind
+	itself from all	the thermal zone devices using it.
+
+1.3 interface for binding a thermal zone device with a thermal cooling device
+1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+			int trip, struct thermal_cooling_device *cdev);
+
+	This interface function bind a thermal cooling device to the certain trip point
+	of a thermal zone device.
+	This function is usually called in the thermal zone device .bind callback.
+	tz: the thermal zone device
+	cdev: thermal cooling device
+	trip: indicates which trip point the cooling devices is associated with
+		 in this thermal zone.
+
+1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+				int trip, struct thermal_cooling_device *cdev);
+
+	This interface function unbind a thermal cooling device from the certain trip point
+	of a thermal zone device.
+	This function is usually called in the thermal zone device .unbind callback.
+	tz: the thermal zone device
+	cdev: thermal cooling device
+	trip: indicates which trip point the cooling devices is associated with
+		in this thermal zone.
+
+2. sysfs attributes structure
+
+RO	read only value
+RW	read/write value
+
+All thermal sysfs attributes will be represented under /sys/class/thermal
+/sys/class/thermal/
+
+Thermal zone device sys I/F, created once it's registered:
+|thermal_zone[0-*]:
+	|-----type:			Type of the thermal zone
+	|-----temp:			Current temperature
+	|-----mode:			Working mode of the thermal zone
+	|-----trip_point_[0-*]_temp:	Trip point temperature
+	|-----trip_point_[0-*]_type:	Trip point type
+
+Thermal cooling device sys I/F, created once it's registered:
+|cooling_device[0-*]:
+	|-----type :			Type of the cooling device(processor/fan/...)
+	|-----max_state:		Maximum cooling state of the cooling device
+	|-----cur_state:		Current cooling state of the cooling device
+
+
+These two dynamic attributes are created/removed in pairs.
+They represent the relationship between a thermal zone and its associated cooling device.
+They are created/removed for each
+thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection.
+
+|thermal_zone[0-*]
+	|-----cdev[0-*]:		The [0-*]th cooling device in the current thermal zone
+	|-----cdev[0-*]_trip_point:	Trip point that cdev[0-*] is associated with
+
+
+***************************
+* Thermal zone attributes *
+***************************
+
+type				Strings which represent the thermal zone type.
+				This is given by thermal zone driver as part of registration.
+				Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
+				RO
+				Optional
+
+temp				Current temperature as reported by thermal zone (sensor)
+				Unit: degree celsius
+				RO
+				Required
+
+mode				One of the predifned values in [kernel, user]
+				This file gives information about the algorithm
+				that is currently managing the thermal zone.
+				It can be either default kernel based algorithm
+				or user space application.
+				RW
+				Optional
+				kernel	= Thermal management in kernel thermal zone driver.
+				user	= Preventing kernel thermal zone driver actions upon
+					  trip points so that user application can take full
+					  charge of the thermal management.
+
+trip_point_[0-*]_temp		The temperature above which trip point will be fired
+				Unit: degree celsius
+				RO
+				Optional
+
+trip_point_[0-*]_type 		Strings which indicate the type of the trip point
+				Eg. it can be one of critical, hot, passive,
+				    active[0-*] for ACPI thermal zone.
+				RO
+				Optional
+
+cdev[0-*]			Sysfs link to the thermal cooling device node where the sys I/F
+				for cooling device throttling control represents.
+				RO
+				Optional
+
+cdev[0-*]_trip_point		The trip point with which cdev[0-*] is assocated in this thermal zone
+				-1 means the cooling device is not associated with any trip point.
+				RO
+				Optional
+
+******************************
+* Cooling device  attributes *
+******************************
+
+type				String which represents the type of device
+				eg: For generic ACPI: this should be "Fan",
+				"Processor" or "LCD"
+				eg. For memory controller device on intel_menlow platform:
+				this should be "Memory controller"
+				RO
+				Optional
+
+max_state			The maximum permissible cooling state of this cooling device.
+				RO
+				Required
+
+cur_state			The current cooling state of this cooling device.
+				the value can any integer numbers between 0 and max_state,
+				cur_state == 0 means no cooling
+				cur_state == max_state means the maximum cooling.
+				RW
+				Required
+
+3. A simple implementation
+
+ACPI thermal zone may support multiple trip points like critical/hot/passive/active.
+If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time,
+it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all.
+It has one processor and one fan, which are both registered as thermal_cooling_device.
+If the processor is listed in _PSL method, and the fan is listed in _AL0 method,
+the sys I/F structure will be built like this:
+
+/sys/class/thermal:
+
+|thermal_zone1:
+	|-----type:			ACPI thermal zone
+	|-----temp:			37
+	|-----mode:			kernel
+	|-----trip_point_0_temp:	100
+	|-----trip_point_0_type:	critical
+	|-----trip_point_1_temp:	80
+	|-----trip_point_1_type:	passive
+	|-----trip_point_2_temp:	70
+	|-----trip_point_2_type:	active[0]
+	|-----trip_point_3_temp:	60
+	|-----trip_point_3_type:	active[1]
+	|-----cdev0:			--->/sys/class/thermal/cooling_device0
+	|-----cdev0_trip_point:		1	/* cdev0 can be used for passive */
+	|-----cdev1:			--->/sys/class/thermal/cooling_device3
+	|-----cdev1_trip_point:		2	/* cdev1 can be used for active[0]*/
+
+|cooling_device0:
+	|-----type:			Processor
+	|-----max_state:		8
+	|-----cur_state:		0
+
+|cooling_device3:
+	|-----type:			Fan
+	|-----max_state:		2
+	|-----cur_state:		0
+
diff -urN linux-2.6.24.7-rt20/drivers/acpi/bus.c linux-2.6.24.7-rt20-atom/drivers/acpi/bus.c
--- linux-2.6.24.7-rt20/drivers/acpi/bus.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/bus.c	2008-09-28 11:30:55.000000000 +0200
@@ -122,6 +122,31 @@
 
 EXPORT_SYMBOL(acpi_bus_get_status);
 
+void acpi_bus_private_data_handler(acpi_handle handle,
+				   u32 function, void *context)
+{
+	return;
+}
+EXPORT_SYMBOL(acpi_bus_private_data_handler);
+
+int acpi_bus_get_private_data(acpi_handle handle, void **data)
+{
+	acpi_status status = AE_OK;
+
+	if (!*data)
+		return -EINVAL;
+
+	status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
+	if (ACPI_FAILURE(status) || !*data) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+				handle));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(acpi_bus_get_private_data);
+
 /* --------------------------------------------------------------------------
                                  Power Management
    -------------------------------------------------------------------------- */
diff -urN linux-2.6.24.7-rt20/drivers/acpi/fan.c linux-2.6.24.7-rt20-atom/drivers/acpi/fan.c
--- linux-2.6.24.7-rt20/drivers/acpi/fan.c	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/fan.c	2008-09-28 11:30:55.000000000 +0200
@@ -30,7 +30,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
-
+#include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -68,9 +68,55 @@
 		},
 };
 
+/* thermal cooling device callbacks */
+static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+	/* ACPI fan device only support two states: ON/OFF */
+	return sprintf(buf, "1\n");
+}
+
+static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+	struct acpi_device *device = cdev->devdata;
+	int state;
+	int result;
+
+	if (!device)
+		return -EINVAL;
+
+	result = acpi_bus_get_power(device->handle, &state);
+	if (result)
+		return result;
+
+	return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
+			 (state == ACPI_STATE_D0 ? "1" : "unknown"));
+}
+
+static int
+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+	struct acpi_device *device = cdev->devdata;
+	int result;
+
+	if (!device || (state != 0 && state != 1))
+		return -EINVAL;
+
+	result = acpi_bus_set_power(device->handle,
+				state ? ACPI_STATE_D0 : ACPI_STATE_D3);
+
+	return result;
+}
+
+static struct thermal_cooling_device_ops fan_cooling_ops = {
+	.get_max_state = fan_get_max_state,
+	.get_cur_state = fan_get_cur_state,
+	.set_cur_state = fan_set_cur_state,
+};
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
 
 static struct proc_dir_entry *acpi_fan_dir;
 
@@ -171,7 +217,17 @@
 
 	return 0;
 }
+#else
+static int acpi_fan_add_fs(struct acpi_device *device)
+{
+	return 0;
+}
 
+static int acpi_fan_remove_fs(struct acpi_device *device)
+{
+	return 0;
+}
+#endif
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -179,9 +235,8 @@
 static int acpi_fan_add(struct acpi_device *device)
 {
 	int result = 0;
-	struct acpi_fan *fan = NULL;
 	int state = 0;
-
+	struct thermal_cooling_device *cdev;
 
 	if (!device)
 		return -EINVAL;
@@ -199,6 +254,25 @@
 	acpi_bus_set_power(device->handle, state);
 	device->flags.force_power_state = 0;
 
+	cdev = thermal_cooling_device_register("Fan", device,
+						&fan_cooling_ops);
+	if (cdev)
+		printk(KERN_INFO PREFIX
+			"%s is registered as cooling_device%d\n",
+			device->dev.bus_id, cdev->id);
+	else
+		goto end;
+	acpi_driver_data(device) = cdev;
+	result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
+					"thermal_cooling");
+	if (result)
+		return result;
+
+	result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
+                                       "device");
+        if (result)
+                return result;
+
 	result = acpi_fan_add_fs(device);
 	if (result)
 		goto end;
@@ -208,18 +282,20 @@
 	       !device->power.state ? "on" : "off");
 
       end:
-	if (result)
-		kfree(fan);
-
 	return result;
 }
 
 static int acpi_fan_remove(struct acpi_device *device, int type)
 {
-	if (!device || !acpi_driver_data(device))
+	struct thermal_cooling_device *cdev = acpi_driver_data(device);
+
+	if (!device || !cdev)
 		return -EINVAL;
 
 	acpi_fan_remove_fs(device);
+	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+	sysfs_remove_link(&cdev->device.kobj, "device");
+	thermal_cooling_device_unregister(cdev);
 
 	return 0;
 }
diff -urN linux-2.6.24.7-rt20/drivers/acpi/Kconfig linux-2.6.24.7-rt20-atom/drivers/acpi/Kconfig
--- linux-2.6.24.7-rt20/drivers/acpi/Kconfig	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/Kconfig	2008-09-28 11:30:55.000000000 +0200
@@ -186,6 +186,7 @@
 config ACPI_THERMAL
 	tristate "Thermal Zone"
 	depends on ACPI_PROCESSOR
+	select THERMAL
 	default y
 	help
 	  This driver adds support for ACPI thermal zones.  Most mobile and
diff -urN linux-2.6.24.7-rt20/drivers/acpi/processor_core.c linux-2.6.24.7-rt20-atom/drivers/acpi/processor_core.c
--- linux-2.6.24.7-rt20/drivers/acpi/processor_core.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/processor_core.c	2008-09-28 11:30:55.000000000 +0200
@@ -668,6 +668,24 @@
 
 	acpi_processor_power_init(pr, device);
 
+	pr->cdev = thermal_cooling_device_register("Processor", device,
+						&processor_cooling_ops);
+	if (pr->cdev)
+		printk(KERN_INFO PREFIX
+			"%s is registered as cooling_device%d\n",
+			device->dev.bus_id, pr->cdev->id);
+	else
+		goto end;
+
+	result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
+					"thermal_cooling");
+	if (result)
+		return result;
+	result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
+					"device");
+	if (result)
+		return result;
+
 	if (pr->flags.throttling) {
 		printk(KERN_INFO PREFIX "%s [%s] (supports",
 		       acpi_device_name(device), acpi_device_bid(device));
@@ -791,6 +809,11 @@
 
 	acpi_processor_remove_fs(device);
 
+	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+	sysfs_remove_link(&pr->cdev->device.kobj, "device");
+	thermal_cooling_device_unregister(pr->cdev);
+	pr->cdev = NULL;
+
 	processors[pr->id] = NULL;
 	processor_device_array[pr->id] = NULL;
 	kfree(pr);
diff -urN linux-2.6.24.7-rt20/drivers/acpi/processor_thermal.c linux-2.6.24.7-rt20-atom/drivers/acpi/processor_thermal.c
--- linux-2.6.24.7-rt20/drivers/acpi/processor_thermal.c	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/processor_thermal.c	2008-09-28 11:30:55.000000000 +0200
@@ -32,6 +32,7 @@
 #include <linux/cpufreq.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/sysdev.h>
 
 #include <asm/uaccess.h>
 
@@ -93,6 +94,9 @@
  * _any_ cpufreq driver and not only the acpi-cpufreq driver.
  */
 
+#define CPUFREQ_THERMAL_MIN_STEP 0
+#define CPUFREQ_THERMAL_MAX_STEP 3
+
 static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
 static unsigned int acpi_thermal_cpufreq_is_init = 0;
 
@@ -109,8 +113,9 @@
 	if (!cpu_has_cpufreq(cpu))
 		return -ENODEV;
 
-	if (cpufreq_thermal_reduction_pctg[cpu] < 60) {
-		cpufreq_thermal_reduction_pctg[cpu] += 20;
+	if (cpufreq_thermal_reduction_pctg[cpu] <
+		CPUFREQ_THERMAL_MAX_STEP) {
+		cpufreq_thermal_reduction_pctg[cpu]++;
 		cpufreq_update_policy(cpu);
 		return 0;
 	}
@@ -123,8 +128,9 @@
 	if (!cpu_has_cpufreq(cpu))
 		return -ENODEV;
 
-	if (cpufreq_thermal_reduction_pctg[cpu] > 20)
-		cpufreq_thermal_reduction_pctg[cpu] -= 20;
+	if (cpufreq_thermal_reduction_pctg[cpu] >
+		(CPUFREQ_THERMAL_MIN_STEP + 1))
+		cpufreq_thermal_reduction_pctg[cpu]--;
 	else
 		cpufreq_thermal_reduction_pctg[cpu] = 0;
 	cpufreq_update_policy(cpu);
@@ -143,7 +149,7 @@
 
 	max_freq =
 	    (policy->cpuinfo.max_freq *
-	     (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100;
+	     (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
 
 	cpufreq_verify_within_limits(policy, 0, max_freq);
 
@@ -155,6 +161,32 @@
 	.notifier_call = acpi_thermal_cpufreq_notifier,
 };
 
+static int cpufreq_get_max_state(unsigned int cpu)
+{
+	if (!cpu_has_cpufreq(cpu))
+		return 0;
+
+	return CPUFREQ_THERMAL_MAX_STEP;
+}
+
+static int cpufreq_get_cur_state(unsigned int cpu)
+{
+	if (!cpu_has_cpufreq(cpu))
+		return 0;
+
+	return cpufreq_thermal_reduction_pctg[cpu];
+}
+
+static int cpufreq_set_cur_state(unsigned int cpu, int state)
+{
+	if (!cpu_has_cpufreq(cpu))
+		return 0;
+
+	cpufreq_thermal_reduction_pctg[cpu] = state;
+	cpufreq_update_policy(cpu);
+	return 0;
+}
+
 void acpi_thermal_cpufreq_init(void)
 {
 	int i;
@@ -179,6 +211,20 @@
 }
 
 #else				/* ! CONFIG_CPU_FREQ */
+static int cpufreq_get_max_state(unsigned int cpu)
+{
+	return 0;
+}
+
+static int cpufreq_get_cur_state(unsigned int cpu)
+{
+	return 0;
+}
+
+static int cpufreq_set_cur_state(unsigned int cpu, int state)
+{
+	return 0;
+}
 
 static int acpi_thermal_cpufreq_increase(unsigned int cpu)
 {
@@ -310,6 +356,84 @@
 	return 0;
 }
 
+/* thermal coolign device callbacks */
+static int acpi_processor_max_state(struct acpi_processor *pr)
+{
+	int max_state = 0;
+
+	/*
+	 * There exists four states according to
+	 * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
+	 */
+	max_state += cpufreq_get_max_state(pr->id);
+	if (pr->flags.throttling)
+		max_state += (pr->throttling.state_count -1);
+
+	return max_state;
+}
+static int
+processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_processor *pr = acpi_driver_data(device);
+
+	if (!device || !pr)
+		return -EINVAL;
+
+	return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
+}
+
+static int
+processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_processor *pr = acpi_driver_data(device);
+	int cur_state;
+
+	if (!device || !pr)
+		return -EINVAL;
+
+	cur_state = cpufreq_get_cur_state(pr->id);
+	if (pr->flags.throttling)
+		cur_state += pr->throttling.state;
+
+	return sprintf(buf, "%d\n", cur_state);
+}
+
+static int
+processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_processor *pr = acpi_driver_data(device);
+	int result = 0;
+	int max_pstate;
+
+	if (!device || !pr)
+		return -EINVAL;
+
+	max_pstate = cpufreq_get_max_state(pr->id);
+
+	if (state > acpi_processor_max_state(pr))
+		return -EINVAL;
+
+	if (state <= max_pstate) {
+		if (pr->flags.throttling && pr->throttling.state)
+			result = acpi_processor_set_throttling(pr, 0);
+		cpufreq_set_cur_state(pr->id, state);
+	} else {
+		cpufreq_set_cur_state(pr->id, max_pstate);
+		result = acpi_processor_set_throttling(pr,
+				state - max_pstate);
+	}
+	return result;
+}
+
+struct thermal_cooling_device_ops processor_cooling_ops = {
+	.get_max_state = processor_get_max_state,
+	.get_cur_state = processor_get_cur_state,
+	.set_cur_state = processor_set_cur_state,
+};
+
 /* /proc interface */
 
 static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
diff -urN linux-2.6.24.7-rt20/drivers/acpi/thermal.c linux-2.6.24.7-rt20-atom/drivers/acpi/thermal.c
--- linux-2.6.24.7-rt20/drivers/acpi/thermal.c	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/thermal.c	2008-09-28 11:30:55.000000000 +0200
@@ -43,7 +43,7 @@
 #include <linux/seq_file.h>
 #include <linux/reboot.h>
 #include <asm/uaccess.h>
-
+#include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -65,9 +65,6 @@
 #define ACPI_THERMAL_MAX_ACTIVE	10
 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
 
-#define KELVIN_TO_CELSIUS(t)    (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
-#define CELSIUS_TO_KELVIN(t)	((t+273)*10)
-
 #define _COMPONENT		ACPI_THERMAL_COMPONENT
 ACPI_MODULE_NAME("thermal");
 
@@ -195,6 +192,8 @@
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct timer_list timer;
+	struct thermal_zone_device *thermal_zone;
+	int tz_enabled;
 	struct mutex lock;
 };
 
@@ -321,173 +320,221 @@
 	return 0;
 }
 
-static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
+#define ACPI_TRIPS_CRITICAL	0x01
+#define ACPI_TRIPS_HOT		0x02
+#define ACPI_TRIPS_PASSIVE	0x04
+#define ACPI_TRIPS_ACTIVE	0x08
+#define ACPI_TRIPS_DEVICES	0x10
+
+#define ACPI_TRIPS_REFRESH_THRESHOLDS	(ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
+#define ACPI_TRIPS_REFRESH_DEVICES	ACPI_TRIPS_DEVICES
+
+#define ACPI_TRIPS_INIT      (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT |	\
+			      ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE |	\
+			      ACPI_TRIPS_DEVICES)
+
+/*
+ * This exception is thrown out in two cases:
+ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
+ *   when re-evaluating the AML code.
+ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
+ *   We need to re-bind the cooling devices of a thermal zone when this occurs.
+ */
+#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str)	\
+do {	\
+	if (flags != ACPI_TRIPS_INIT)	\
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,	\
+		"ACPI thermal trip point %s changed\n"	\
+		"Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
+} while (0)
+
+static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
 {
 	acpi_status status = AE_OK;
-	int i = 0;
-
-
-	if (!tz)
-		return -EINVAL;
+	struct acpi_handle_list devices;
+	int valid = 0;
+	int i;
 
 	/* Critical Shutdown (required) */
-
-	status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
-				       &tz->trips.critical.temperature);
-	if (ACPI_FAILURE(status)) {
-		tz->trips.critical.flags.valid = 0;
-		ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
-		return -ENODEV;
-	} else {
-		tz->trips.critical.flags.valid = 1;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Found critical threshold [%lu]\n",
-				  tz->trips.critical.temperature));
-	}
-
-	if (tz->trips.critical.flags.valid == 1) {
-		if (crt == -1) {
+	if (flag & ACPI_TRIPS_CRITICAL) {
+		status = acpi_evaluate_integer(tz->device->handle,
+				"_CRT", NULL, &tz->trips.critical.temperature);
+		if (ACPI_FAILURE(status)) {
 			tz->trips.critical.flags.valid = 0;
-		} else if (crt > 0) {
-			unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
-
-			/*
-			 * Allow override to lower critical threshold
-			 */
-			if (crt_k < tz->trips.critical.temperature)
-				tz->trips.critical.temperature = crt_k;
+			ACPI_EXCEPTION((AE_INFO, status,
+					"No critical threshold"));
+			return -ENODEV;
+		} else {
+			tz->trips.critical.flags.valid = 1;
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					"Found critical threshold [%lu]\n",
+					tz->trips.critical.temperature));
+		}
+		if (tz->trips.critical.flags.valid == 1) {
+			if (crt == -1) {
+				tz->trips.critical.flags.valid = 0;
+			} else if (crt > 0) {
+				unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+				/*
+				 * Allow override to lower critical threshold
+				 */
+				if (crt_k < tz->trips.critical.temperature)
+					tz->trips.critical.temperature = crt_k;
+			}
 		}
 	}
 
 	/* Critical Sleep (optional) */
-
-	status =
-	    acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
-				  &tz->trips.hot.temperature);
-	if (ACPI_FAILURE(status)) {
-		tz->trips.hot.flags.valid = 0;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
-	} else {
-		tz->trips.hot.flags.valid = 1;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
-				  tz->trips.hot.temperature));
-	}
-
-	/* Passive: Processors (optional) */
-
-	if (psv == -1) {
-		status = AE_SUPPORT;
-	} else if (psv > 0) {
-		tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
-		status = AE_OK;
-	} else {
+	if (flag & ACPI_TRIPS_HOT) {
 		status = acpi_evaluate_integer(tz->device->handle,
-			"_PSV", NULL, &tz->trips.passive.temperature);
+				"_HOT", NULL, &tz->trips.hot.temperature);
+		if (ACPI_FAILURE(status)) {
+			tz->trips.hot.flags.valid = 0;
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					"No hot threshold\n"));
+		} else {
+			tz->trips.hot.flags.valid = 1;
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					"Found hot threshold [%lu]\n",
+					tz->trips.critical.temperature));
+		}
 	}
 
-	if (ACPI_FAILURE(status)) {
-		tz->trips.passive.flags.valid = 0;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
-	} else {
-		tz->trips.passive.flags.valid = 1;
-
-		status =
-		    acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,
-					  &tz->trips.passive.tc1);
-		if (ACPI_FAILURE(status))
-			tz->trips.passive.flags.valid = 0;
-
-		status =
-		    acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
-					  &tz->trips.passive.tc2);
-		if (ACPI_FAILURE(status))
-			tz->trips.passive.flags.valid = 0;
+	/* Passive (optional) */
+	if (flag & ACPI_TRIPS_PASSIVE) {
+		valid = tz->trips.passive.flags.valid;
+		if (psv == -1) {
+			status = AE_SUPPORT;
+		} else if (psv > 0) {
+			tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+			status = AE_OK;
+		} else {
+			status = acpi_evaluate_integer(tz->device->handle,
+				"_PSV", NULL, &tz->trips.passive.temperature);
+		}
 
-		status =
-		    acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
-					  &tz->trips.passive.tsp);
 		if (ACPI_FAILURE(status))
 			tz->trips.passive.flags.valid = 0;
-
-		status =
-		    acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
-					    &tz->trips.passive.devices);
+		else {
+			tz->trips.passive.flags.valid = 1;
+			if (flag == ACPI_TRIPS_INIT) {
+				status = acpi_evaluate_integer(
+						tz->device->handle, "_TC1",
+						NULL, &tz->trips.passive.tc1);
+				if (ACPI_FAILURE(status))
+					tz->trips.passive.flags.valid = 0;
+				status = acpi_evaluate_integer(
+						tz->device->handle, "_TC2",
+						NULL, &tz->trips.passive.tc2);
+				if (ACPI_FAILURE(status))
+					tz->trips.passive.flags.valid = 0;
+				status = acpi_evaluate_integer(
+						tz->device->handle, "_TSP",
+						NULL, &tz->trips.passive.tsp);
+				if (ACPI_FAILURE(status))
+					tz->trips.passive.flags.valid = 0;
+			}
+		}
+	}
+	if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
+		memset(&devices, 0, sizeof(struct acpi_handle_list));
+		status = acpi_evaluate_reference(tz->device->handle, "_PSL",
+							NULL, &devices);
 		if (ACPI_FAILURE(status))
 			tz->trips.passive.flags.valid = 0;
-
-		if (!tz->trips.passive.flags.valid)
-			printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
 		else
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Found passive threshold [%lu]\n",
-					  tz->trips.passive.temperature));
-	}
+			tz->trips.passive.flags.valid = 1;
 
-	/* Active: Fans, etc. (optional) */
+		if (memcmp(&tz->trips.passive.devices, &devices,
+				sizeof(struct acpi_handle_list))) {
+			memcpy(&tz->trips.passive.devices, &devices,
+				sizeof(struct acpi_handle_list));
+			ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+		}
+	}
+	if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
+		if (valid != tz->trips.passive.flags.valid)
+				ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
+	}
 
+	/* Active (optional) */
 	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-
 		char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
+		valid = tz->trips.active[i].flags.valid;
 
 		if (act == -1)
-			break;	/* disable all active trip points */
+			break; /* disable all active trip points */
 
-		status = acpi_evaluate_integer(tz->device->handle,
-			name, NULL, &tz->trips.active[i].temperature);
-
-		if (ACPI_FAILURE(status)) {
-			if (i == 0)	/* no active trip points */
+		if (flag & ACPI_TRIPS_ACTIVE) {
+			status = acpi_evaluate_integer(tz->device->handle,
+				name, NULL, &tz->trips.active[i].temperature);
+			if (ACPI_FAILURE(status)) {
+				tz->trips.active[i].flags.valid = 0;
+				if (i == 0)
+					break;
+				if (act <= 0)
+					break;
+				if (i == 1)
+					tz->trips.active[0].temperature =
+						CELSIUS_TO_KELVIN(act);
+				else
+					/*
+					 * Don't allow override higher than
+					 * the next higher trip point
+					 */
+					tz->trips.active[i - 1].temperature =
+						(tz->trips.active[i - 2].temperature <
+						CELSIUS_TO_KELVIN(act) ?
+						tz->trips.active[i - 2].temperature :
+						CELSIUS_TO_KELVIN(act));
 				break;
-			if (act <= 0)	/* no override requested */
-				break;
-			if (i == 1) {	/* 1 trip point */
-				tz->trips.active[0].temperature =
-					CELSIUS_TO_KELVIN(act);
-			} else {	/* multiple trips */
-				/*
-				 * Don't allow override higher than
-				 * the next higher trip point
-				 */
-				tz->trips.active[i - 1].temperature =
-				    (tz->trips.active[i - 2].temperature <
-					CELSIUS_TO_KELVIN(act) ?
-					tz->trips.active[i - 2].temperature :
-					CELSIUS_TO_KELVIN(act));
-			}
-			break;
+			} else
+				tz->trips.active[i].flags.valid = 1;
 		}
 
 		name[2] = 'L';
-		status =
-		    acpi_evaluate_reference(tz->device->handle, name, NULL,
-					    &tz->trips.active[i].devices);
-		if (ACPI_SUCCESS(status)) {
-			tz->trips.active[i].flags.valid = 1;
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "Found active threshold [%d]:[%lu]\n",
-					  i, tz->trips.active[i].temperature));
-		} else
-			ACPI_EXCEPTION((AE_INFO, status,
-					"Invalid active threshold [%d]", i));
+		if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
+			memset(&devices, 0, sizeof(struct acpi_handle_list));
+			status = acpi_evaluate_reference(tz->device->handle,
+						name, NULL, &devices);
+			if (ACPI_FAILURE(status))
+				tz->trips.active[i].flags.valid = 0;
+			else
+				tz->trips.active[i].flags.valid = 1;
+
+			if (memcmp(&tz->trips.active[i].devices, &devices,
+					sizeof(struct acpi_handle_list))) {
+				memcpy(&tz->trips.active[i].devices, &devices,
+					sizeof(struct acpi_handle_list));
+				ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+			}
+		}
+		if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
+			if (valid != tz->trips.active[i].flags.valid)
+				ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
+
+		if (!tz->trips.active[i].flags.valid)
+			break;
+	}
+
+	if (flag & ACPI_TRIPS_DEVICES) {
+		memset(&devices, 0, sizeof(struct acpi_handle_list));
+		status = acpi_evaluate_reference(tz->device->handle, "_TZD",
+						NULL, &devices);
+		if (memcmp(&tz->devices, &devices,
+				sizeof(struct acpi_handle_list))) {
+			memcpy(&tz->devices, &devices,
+				sizeof(struct acpi_handle_list));
+			ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
+		}
 	}
 
 	return 0;
 }
 
-static int acpi_thermal_get_devices(struct acpi_thermal *tz)
+static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 {
-	acpi_status status = AE_OK;
-
-
-	if (!tz)
-		return -EINVAL;
-
-	status =
-	    acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
-
-	return 0;
+	return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
 }
 
 static int acpi_thermal_critical(struct acpi_thermal *tz)
@@ -732,6 +779,9 @@
 	if (result)
 		goto unlock;
 
+	if (!tz->tz_enabled)
+		goto unlock;
+
 	memset(&tz->state, 0, sizeof(tz->state));
 
 	/*
@@ -825,6 +875,290 @@
 	mutex_unlock(&tz->lock);
 }
 
+/* sys I/F for generic thermal sysfs support */
+static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
+{
+	struct acpi_thermal *tz = thermal->devdata;
+
+	if (!tz)
+		return -EINVAL;
+
+	return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
+}
+
+static const char enabled[] = "kernel";
+static const char disabled[] = "user";
+static int thermal_get_mode(struct thermal_zone_device *thermal,
+				char *buf)
+{
+	struct acpi_thermal *tz = thermal->devdata;
+
+	if (!tz)
+		return -EINVAL;
+
+	return sprintf(buf, "%s\n", tz->tz_enabled ?
+			enabled : disabled);
+}
+
+static int thermal_set_mode(struct thermal_zone_device *thermal,
+				const char *buf)
+{
+	struct acpi_thermal *tz = thermal->devdata;
+	int enable;
+
+	if (!tz)
+		return -EINVAL;
+
+	/*
+	 * enable/disable thermal management from ACPI thermal driver
+	 */
+	if (!strncmp(buf, enabled, sizeof enabled - 1))
+		enable = 1;
+	else if (!strncmp(buf, disabled, sizeof disabled - 1))
+		enable = 0;
+	else
+		return -EINVAL;
+
+	if (enable != tz->tz_enabled) {
+		tz->tz_enabled = enable;
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"%s ACPI thermal control\n",
+			tz->tz_enabled ? enabled : disabled));
+		acpi_thermal_check(tz);
+	}
+	return 0;
+}
+
+static int thermal_get_trip_type(struct thermal_zone_device *thermal,
+				 int trip, char *buf)
+{
+	struct acpi_thermal *tz = thermal->devdata;
+	int i;
+
+	if (!tz || trip < 0)
+		return -EINVAL;
+
+	if (tz->trips.critical.flags.valid) {
+		if (!trip)
+			return sprintf(buf, "critical\n");
+		trip--;
+	}
+
+	if (tz->trips.hot.flags.valid) {
+		if (!trip)
+			return sprintf(buf, "hot\n");
+		trip--;
+	}
+
+	if (tz->trips.passive.flags.valid) {
+		if (!trip)
+			return sprintf(buf, "passive\n");
+		trip--;
+	}
+
+	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+		tz->trips.active[i].flags.valid; i++) {
+		if (!trip)
+			return sprintf(buf, "active%d\n", i);
+		trip--;
+	}
+
+	return -EINVAL;
+}
+
+static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
+				 int trip, char *buf)
+{
+	struct acpi_thermal *tz = thermal->devdata;
+	int i;
+
+	if (!tz || trip < 0)
+		return -EINVAL;
+
+	if (tz->trips.critical.flags.valid) {
+		if (!trip)
+			return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+				tz->trips.critical.temperature));
+		trip--;
+	}
+
+	if (tz->trips.hot.flags.valid) {
+		if (!trip)
+			return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+					tz->trips.hot.temperature));
+		trip--;
+	}
+
+	if (tz->trips.passive.flags.valid) {
+		if (!trip)
+			return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+					tz->trips.passive.temperature));
+		trip--;
+	}
+
+	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+		tz->trips.active[i].flags.valid; i++) {
+		if (!trip)
+			return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
+					tz->trips.active[i].temperature));
+		trip--;
+	}
+
+	return -EINVAL;
+}
+
+typedef int (*cb)(struct thermal_zone_device *, int,
+		  struct thermal_cooling_device *);
+static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
+					struct thermal_cooling_device *cdev,
+					cb action)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_thermal *tz = thermal->devdata;
+	struct acpi_device *dev;
+	acpi_status status;
+	acpi_handle handle;
+	int i;
+	int j;
+	int trip = -1;
+	int result = 0;
+
+	if (tz->trips.critical.flags.valid)
+		trip++;
+
+	if (tz->trips.hot.flags.valid)
+		trip++;
+
+	if (tz->trips.passive.flags.valid) {
+		trip++;
+		for (i = 0; i < tz->trips.passive.devices.count;
+		    i++) {
+			handle = tz->trips.passive.devices.handles[i];
+			status = acpi_bus_get_device(handle, &dev);
+			if (ACPI_SUCCESS(status) && (dev == device)) {
+				result = action(thermal, trip, cdev);
+				if (result)
+					goto failed;
+			}
+		}
+	}
+
+	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+		if (!tz->trips.active[i].flags.valid)
+			break;
+		trip++;
+		for (j = 0;
+		    j < tz->trips.active[i].devices.count;
+		    j++) {
+			handle = tz->trips.active[i].devices.handles[j];
+			status = acpi_bus_get_device(handle, &dev);
+			if (ACPI_SUCCESS(status) && (dev == device)) {
+				result = action(thermal, trip, cdev);
+				if (result)
+					goto failed;
+			}
+		}
+	}
+
+	for (i = 0; i < tz->devices.count; i++) {
+		handle = tz->devices.handles[i];
+		status = acpi_bus_get_device(handle, &dev);
+		if (ACPI_SUCCESS(status) && (dev == device)) {
+			result = action(thermal, -1, cdev);
+			if (result)
+				goto failed;
+		}
+	}
+
+failed:
+	return result;
+}
+
+static int
+acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
+					struct thermal_cooling_device *cdev)
+{
+	return acpi_thermal_cooling_device_cb(thermal, cdev,
+				thermal_zone_bind_cooling_device);
+}
+
+static int
+acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
+					struct thermal_cooling_device *cdev)
+{
+	return acpi_thermal_cooling_device_cb(thermal, cdev,
+				thermal_zone_unbind_cooling_device);
+}
+
+static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
+	.bind = acpi_thermal_bind_cooling_device,
+	.unbind	= acpi_thermal_unbind_cooling_device,
+	.get_temp = thermal_get_temp,
+	.get_mode = thermal_get_mode,
+	.set_mode = thermal_set_mode,
+	.get_trip_type = thermal_get_trip_type,
+	.get_trip_temp = thermal_get_trip_temp,
+};
+
+static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
+{
+	int trips = 0;
+	int result;
+	acpi_status status;
+	int i;
+
+	if (tz->trips.critical.flags.valid)
+		trips++;
+
+	if (tz->trips.hot.flags.valid)
+		trips++;
+
+	if (tz->trips.passive.flags.valid)
+		trips++;
+
+	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
+			tz->trips.active[i].flags.valid; i++, trips++);
+	tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+					trips, tz, &acpi_thermal_zone_ops);
+	if (!tz->thermal_zone)
+		return -ENODEV;
+
+	result = sysfs_create_link(&tz->device->dev.kobj,
+				   &tz->thermal_zone->device.kobj, "thermal_zone");
+	if (result)
+		return result;
+
+	result = sysfs_create_link(&tz->thermal_zone->device.kobj,
+				   &tz->device->dev.kobj, "device");
+	if (result)
+		return result;
+
+	status = acpi_attach_data(tz->device->handle,
+				  acpi_bus_private_data_handler,
+				  tz->thermal_zone);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Error attaching device data\n"));
+		return -ENODEV;
+	}
+
+	tz->tz_enabled = 1;
+
+	printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
+			tz->device->dev.bus_id, tz->thermal_zone->id);
+	return 0;
+}
+
+static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
+{
+	sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
+	sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
+	thermal_zone_device_unregister(tz->thermal_zone);
+	tz->thermal_zone = NULL;
+	acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
+}
+
+
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
@@ -1181,15 +1515,15 @@
 		acpi_thermal_check(tz);
 		break;
 	case ACPI_THERMAL_NOTIFY_THRESHOLDS:
-		acpi_thermal_get_trip_points(tz);
+		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
 		acpi_thermal_check(tz);
 		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  device->dev.bus_id, event, 0);
 		break;
 	case ACPI_THERMAL_NOTIFY_DEVICES:
-		if (tz->flags.devices)
-			acpi_thermal_get_devices(tz);
+		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
+		acpi_thermal_check(tz);
 		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  device->dev.bus_id, event, 0);
@@ -1232,11 +1566,6 @@
 	else
 		acpi_thermal_get_polling_frequency(tz);
 
-	/* Get devices in this thermal zone [_TZD] (optional) */
-	result = acpi_thermal_get_devices(tz);
-	if (!result)
-		tz->flags.devices = 1;
-
 	return 0;
 }
 
@@ -1260,13 +1589,19 @@
 	strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
 	acpi_driver_data(device) = tz;
 	mutex_init(&tz->lock);
+
+
 	result = acpi_thermal_get_info(tz);
 	if (result)
-		goto end;
+		goto free_memory;
+
+	result = acpi_thermal_register_thermal_zone(tz);
+	if (result)
+		goto free_memory;
 
 	result = acpi_thermal_add_fs(device);
 	if (result)
-		goto end;
+		goto unregister_thermal_zone;
 
 	init_timer(&tz->timer);
 
@@ -1277,19 +1612,21 @@
 					     acpi_thermal_notify, tz);
 	if (ACPI_FAILURE(status)) {
 		result = -ENODEV;
-		goto end;
+		goto remove_fs;
 	}
 
 	printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
 	       acpi_device_name(device), acpi_device_bid(device),
 	       KELVIN_TO_CELSIUS(tz->temperature));
+	goto end;
 
-      end:
-	if (result) {
-		acpi_thermal_remove_fs(device);
-		kfree(tz);
-	}
-
+remove_fs:
+	acpi_thermal_remove_fs(device);
+unregister_thermal_zone:
+	thermal_zone_device_unregister(tz->thermal_zone);
+free_memory:
+	kfree(tz);
+end:
 	return result;
 }
 
@@ -1329,6 +1666,7 @@
 	}
 
 	acpi_thermal_remove_fs(device);
+	acpi_thermal_unregister_thermal_zone(tz);
 	mutex_destroy(&tz->lock);
 	kfree(tz);
 	return 0;
diff -urN linux-2.6.24.7-rt20/drivers/acpi/video.c linux-2.6.24.7-rt20-atom/drivers/acpi/video.c
--- linux-2.6.24.7-rt20/drivers/acpi/video.c	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/acpi/video.c	2008-09-28 11:30:55.000000000 +0200
@@ -34,6 +34,7 @@
 #include <linux/seq_file.h>
 #include <linux/input.h>
 #include <linux/backlight.h>
+#include <linux/thermal.h>
 #include <linux/video_output.h>
 #include <asm/uaccess.h>
 
@@ -179,6 +180,7 @@
 	struct acpi_device *dev;
 	struct acpi_video_device_brightness *brightness;
 	struct backlight_device *backlight;
+	struct thermal_cooling_device *cdev;
 	struct output_device *output_dev;
 };
 
@@ -334,6 +336,54 @@
 	.set_state = acpi_video_output_set,
 	.get_status = acpi_video_output_get,
 };
+
+
+/* thermal cooling device callbacks */
+static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_video_device *video = acpi_driver_data(device);
+
+	return sprintf(buf, "%d\n", video->brightness->count - 3);
+}
+
+static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_video_device *video = acpi_driver_data(device);
+	unsigned long level;
+	int state;
+
+	acpi_video_device_lcd_get_level_current(video, &level);
+	for (state = 2; state < video->brightness->count; state++)
+		if (level == video->brightness->levels[state])
+			return sprintf(buf, "%d\n",
+				       video->brightness->count - state - 1);
+
+	return -EINVAL;
+}
+
+static int
+video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+{
+	struct acpi_device *device = cdev->devdata;
+	struct acpi_video_device *video = acpi_driver_data(device);
+	int level;
+
+	if ( state >= video->brightness->count - 2)
+		return -EINVAL;
+
+	state = video->brightness->count - state;
+	level = video->brightness->levels[state -1];
+	return acpi_video_device_lcd_set_level(video, level);
+}
+
+static struct thermal_cooling_device_ops video_cooling_ops = {
+	.get_max_state = video_get_max_state,
+	.get_cur_state = video_get_cur_state,
+	.set_cur_state = video_set_cur_state,
+};
+
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -653,6 +703,7 @@
 
 	if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
 		unsigned long tmp;
+		int result;
 		static int count = 0;
 		char *name;
 		name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
@@ -666,8 +717,25 @@
 		device->backlight->props.max_brightness = max_level;
 		device->backlight->props.brightness = (int)tmp;
 		backlight_update_status(device->backlight);
-
 		kfree(name);
+
+		device->cdev = thermal_cooling_device_register("LCD",
+					device->dev, &video_cooling_ops);
+		if (device->cdev) {
+			printk(KERN_INFO PREFIX
+				"%s is registered as cooling_device%d\n",
+				device->dev->dev.bus_id, device->cdev->id);
+			result = sysfs_create_link(&device->dev->dev.kobj,
+					  &device->cdev->device.kobj,
+					  "thermal_cooling");
+			if (result)
+				printk(KERN_ERR PREFIX "Create sysfs link\n");
+			result = sysfs_create_link(&device->cdev->device.kobj,
+					  &device->dev->dev.kobj,
+					  "device");
+                        if (result)
+				printk(KERN_ERR PREFIX "Create sysfs link\n");
+		}
 	}
 	if (device->cap._DCS && device->cap._DSS){
 		static int count = 0;
@@ -1729,6 +1797,14 @@
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_device_notify);
 	backlight_device_unregister(device->backlight);
+	if (device->cdev) {
+		sysfs_remove_link(&device->dev->dev.kobj,
+				  "thermal_cooling");
+		sysfs_remove_link(&device->cdev->device.kobj,
+				  "device");
+		thermal_cooling_device_unregister(device->cdev);
+		device->cdev = NULL;
+	}
 	video_output_unregister(device->output_dev);
 
 	return 0;
diff -urN linux-2.6.24.7-rt20/drivers/ata/ata_piix.c linux-2.6.24.7-rt20-atom/drivers/ata/ata_piix.c
--- linux-2.6.24.7-rt20/drivers/ata/ata_piix.c	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/ata/ata_piix.c	2008-09-28 11:32:29.000000000 +0200
@@ -214,6 +214,7 @@
 	/* ICH7/7-R (i945, i975) UDMA 100*/
 	{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+	{ 0x8086, 0x811A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* ICH8 Mobile PATA Controller */
 	{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 
@@ -731,6 +732,12 @@
 		lap++;
 	}
 
+	/* workaround for Poulsbo PATA controller, this controller's
+	 * IOCFG register is "reserved"
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+		pdev->device == PCI_DEVICE_ID_INTEL_POULSBO_IDE)
+		return ATA_CBL_PATA80;
 	/* check BIOS cable detect results */
 	mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
 	pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
@@ -752,8 +759,13 @@
 	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
-	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
-		return -ENOENT;
+	/* workaround for Poulsbo PATA controller, this controller's port
+	 * enable registers are "reserved"
+	 */
+	if (pdev->vendor != PCI_VENDOR_ID_INTEL ||
+		pdev->device != PCI_DEVICE_ID_INTEL_POULSBO_IDE)
+		if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
+			return -ENOENT;
 	return ata_std_prereset(link, deadline);
 }
 
diff -urN linux-2.6.24.7-rt20/drivers/hwmon/coretemp.c linux-2.6.24.7-rt20-atom/drivers/hwmon/coretemp.c
--- linux-2.6.24.7-rt20/drivers/hwmon/coretemp.c	2008-10-06 08:30:17.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/hwmon/coretemp.c	2008-09-28 12:03:36.000000000 +0200
@@ -1,7 +1,7 @@
 /*
  * coretemp.c - Linux kernel module for hardware monitoring
  *
- * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
+ * Copyright (C) 2007, 2008 Rudolf Marek <r.marek@assembler.cz>
  *
  * Inspired from many hwmon drivers
  *
@@ -38,7 +38,8 @@
 
 #define DRVNAME	"coretemp"
 
-typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
+typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
+		SHOW_NAME } SHOW;
 
 /*
  * Functions declaration
@@ -55,6 +56,7 @@
 	unsigned long last_updated;	/* in jiffies */
 	int temp;
 	int tjmax;
+	int ttarget;
 	u8 alarm;
 };
 
@@ -93,9 +95,10 @@
 
 	if (attr->index == SHOW_TEMP)
 		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
-	else
+	else if (attr->index == SHOW_TJMAX)
 		err = sprintf(buf, "%d\n", data->tjmax);
-
+	else
+		err = sprintf(buf, "%d\n", data->ttarget);
 	return err;
 }
 
@@ -103,6 +106,8 @@
 			  SHOW_TEMP);
 static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
 			  SHOW_TJMAX);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
+			  SHOW_TTARGET);
 static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
 static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
 static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
@@ -147,6 +152,56 @@
 	return data;
 }
 
+static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+{
+	/* The 100C is default for both mobile and non mobile CPUs */
+
+	int tjmax = 100000;
+	int ismobile = 1;
+	int err;
+	u32 eax, edx;
+
+	/* Early chips have no MSR for TjMax */
+
+	if ((c->x86_model == 0xf) && (c->x86_mask < 4)) {
+		ismobile = 0;
+	}
+
+	if ((c->x86_model > 0xe) && (ismobile)) {
+
+		/* Now we can detect the mobile CPU using Intel provided table
+		   http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
+		   For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
+		*/
+
+		err = rdmsr_safe_on_cpu(id, 0x17, &eax, &edx);
+		if (err) {
+			dev_warn(dev,
+				 "Unable to access MSR 0x17, assuming desktop"
+				 " CPU\n");
+			ismobile = 0;
+		} else if (!(eax & 0x10000000)) {
+			ismobile = 0;
+		}
+	}
+
+	if (ismobile) {
+
+		err = rdmsr_safe_on_cpu(id, 0xee, &eax, &edx);
+		if (err) {
+			dev_warn(dev,
+				 "Unable to access MSR 0xEE, for Tjmax, left"
+				 " at default");
+		} else if (eax & 0x40000000) {
+			tjmax = 85000;
+		}
+	} else {
+		dev_warn(dev, "Using relative temperature scale!\n");
+	}
+
+	return tjmax;
+}
+
 static int __devinit coretemp_probe(struct platform_device *pdev)
 {
 	struct coretemp_data *data;
@@ -163,8 +218,6 @@
 	data->id = pdev->id;
 	data->name = "coretemp";
 	mutex_init(&data->update_lock);
-	/* Tjmax default is 100 degrees C */
-	data->tjmax = 100000;
 
 	/* test if we can access the THERM_STATUS MSR */
 	err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
@@ -191,40 +244,37 @@
 		}
 	}
 
-	/* Some processors have Tjmax 85 following magic should detect it
-	   Intel won't disclose the information without signed NDA, but
-	   individuals cannot sign it. Catch(ed) 22.
-	*/
+	/* Intel Atom has only fixed TjMax at 95C */
 
-	if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
-		(c->x86_model == 0xe))  {
-		err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
-		if (err) {
-			dev_warn(&pdev->dev,
-				 "Unable to access MSR 0xEE, Tjmax left at %d "
-				 "degrees C\n", data->tjmax/1000);
-		} else if (eax & 0x40000000) {
-			data->tjmax = 85000;
-		}
+	if (c->x86_model == 0x1c) {
+		data->tjmax = 95000;
+	} else {
+		/* Adjust the TjMax for the rest of Core2 family */
+		data->tjmax = adjust_tjmax(c, data->id, &pdev->dev);
 	}
 
-	/* Intel says that above should not work for desktop Core2 processors,
-	   but it seems to work. There is no other way how get the absolute
-	   readings. Warn the user about this. First check if are desktop,
-	   bit 50 of MSR_IA32_PLATFORM_ID should be 0.
-	*/
-
-	rdmsr_safe_on_cpu(data->id, MSR_IA32_PLATFORM_ID, &eax, &edx);
+	/* read the still undocumented IA32_TEMPERATURE_TARGET it exists
+	   on older CPUs but not in this register */
 
-	if ((c->x86_model == 0xf) && (!(edx & 0x00040000))) {
-		dev_warn(&pdev->dev, "Using undocumented features, absolute "
-			 "temperature might be wrong!\n");
+	if (c->x86_model > 0xe) {
+		err = rdmsr_safe_on_cpu(data->id, 0x1a2, &eax, &edx);
+		if (err) {
+			dev_warn(&pdev->dev, "Unable to read"
+					" IA32_TEMPERATURE_TARGET MSR\n");
+		} else {
+			data->ttarget = data->tjmax -
+					(((eax >> 8) & 0xff) * 1000);
+			err = device_create_file(&pdev->dev,
+					&sensor_dev_attr_temp1_max.dev_attr);
+			if (err)
+				goto exit_free;
+		}
 	}
 
 	platform_set_drvdata(pdev, data);
 
 	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
-		goto exit_free;
+		goto exit_dev;
 
 	data->hwmon_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(data->hwmon_dev)) {
@@ -238,6 +288,8 @@
 
 exit_class:
 	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+exit_dev:
+	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
 exit_free:
 	kfree(data);
 exit:
@@ -250,6 +302,7 @@
 
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+	device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 	return 0;
@@ -330,7 +383,7 @@
 	mutex_unlock(&pdev_list_mutex);
 }
 
-static int coretemp_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
 				 unsigned long action, void *hcpu)
 {
 	unsigned int cpu = (unsigned long) hcpu;
@@ -347,7 +400,7 @@
 	return NOTIFY_OK;
 }
 
-static struct notifier_block coretemp_cpu_notifier = {
+static struct notifier_block coretemp_cpu_notifier /* __refdata */ = {
 	.notifier_call = coretemp_cpu_callback,
 };
 #endif				/* !CONFIG_HOTPLUG_CPU */
@@ -368,10 +421,11 @@
 	for_each_online_cpu(i) {
 		struct cpuinfo_x86 *c = &cpu_data(i);
 
-		/* check if family 6, models e, f, 16 */
+		/* check if family 6 or models 0xe/0xf/0x16/0x17/0x1a/0x1c */
 		if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
 		    !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
-			(c->x86_model == 0x16))) {
+			(c->x86_model == 0x16) || (c->x86_model == 0x17) ||
+			(c->x86_model == 0x1a) || (c->x86_model == 0x1c))) {
 
 			/* supported CPU not found, but report the unknown
 			   family 6 CPU */
diff -urN linux-2.6.24.7-rt20/drivers/i2c/busses/i2c-sch.c linux-2.6.24.7-rt20-atom/drivers/i2c/busses/i2c-sch.c
--- linux-2.6.24.7-rt20/drivers/i2c/busses/i2c-sch.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/i2c/busses/i2c-sch.c	2008-09-28 11:32:13.000000000 +0200
@@ -0,0 +1,393 @@
+/*
+    i2c-sch.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+    Based on piix4.c
+    Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   Supports:
+	Intel POULSBO
+
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/apm_bios.h>
+#include <asm/io.h>
+
+
+struct sd {
+	const unsigned short mfr;
+	const unsigned short dev;
+	const unsigned char fn;
+	const char *name;
+};
+/* POULSBO SMBus address offsets */
+#define SMBHSTCNT	(0 + poulsbo_smba)
+#define SMBHSTSTS	(1 + poulsbo_smba)
+#define SMBHSTADD	(4 + poulsbo_smba) /* TSA */
+#define SMBHSTCMD	(5 + poulsbo_smba)
+#define SMBHSTDAT0	(6 + poulsbo_smba)
+#define SMBHSTDAT1	(7 + poulsbo_smba)
+#define SMBBLKDAT	(0x20 + poulsbo_smba)
+
+
+/* count for request_region */
+#define SMBIOSIZE	8
+
+/* PCI Address Constants */
+#define SMBBA_SCH	0x040
+
+/* Other settings */
+#define MAX_TIMEOUT	500
+#define  ENABLE_INT9	0
+
+/* POULSBO constants */
+#define POULSBO_QUICK		0x00
+#define POULSBO_BYTE		0x01
+#define POULSBO_BYTE_DATA		0x02
+#define POULSBO_WORD_DATA		0x03
+#define POULSBO_BLOCK_DATA	0x05
+
+/* insmod parameters */
+
+/* If force is set to anything different from 0, we forcibly enable the
+   POULSBO. DANGEROUS! */
+static int force;
+module_param (force, int, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the POULSBO. DANGEROUS!");
+
+
+static int poulsbo_transaction(void);
+
+static unsigned short poulsbo_smba;
+static struct pci_driver poulsbo_driver;
+static struct i2c_adapter poulsbo_adapter;
+
+
+static int __devinit poulsbo_setup(struct pci_dev *POULSBO_dev,
+				const struct pci_device_id *id)
+{
+	unsigned short smbase;
+	if(POULSBO_dev->device != PCI_DEVICE_ID_INTEL_POULSBO_LPC) {
+		/* match up the function */
+		if (PCI_FUNC(POULSBO_dev->devfn) != id->driver_data)
+			return -ENODEV;
+		dev_info(&POULSBO_dev->dev, "Found %s device\n", pci_name(POULSBO_dev));
+	} else {
+		dev_info(&POULSBO_dev->dev, "Found POULSBO SMBUS %s device\n", pci_name(POULSBO_dev));
+		/* find SMBUS base address */
+		pci_read_config_word(POULSBO_dev, 0x40, &smbase);
+		dev_info(&POULSBO_dev->dev, "POULSBO SM base = 0x%04x\n", smbase);
+	}
+
+
+	/* Determine the address of the SMBus areas */
+		if(POULSBO_dev->device == PCI_DEVICE_ID_INTEL_POULSBO_LPC)
+			pci_read_config_word(POULSBO_dev, SMBBA_SCH, &poulsbo_smba);
+		else
+		        poulsbo_smba=0;
+		
+		poulsbo_smba &= 0xfff0;
+		if(poulsbo_smba == 0) {
+			dev_err(&POULSBO_dev->dev, "SMB base address "
+				"uninitialized - upgrade BIOS or use "
+				"force_addr=0xaddr\n");
+			return -ENODEV;
+		}
+
+	if (!request_region(poulsbo_smba, SMBIOSIZE, poulsbo_driver.name)) {
+		dev_err(&POULSBO_dev->dev, "SMB region 0x%x already in use!\n",
+			poulsbo_smba);
+		return -ENODEV;
+	}
+
+	dev_dbg(&POULSBO_dev->dev, "SMBA = 0x%X\n", poulsbo_smba);
+
+	return 0;
+}
+
+/* Another internally used function */
+static int poulsbo_transaction(void)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&poulsbo_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+	  if(temp == 1) {
+		dev_dbg(&poulsbo_adapter.dev, "Completion (%02x). "
+			"clear...\n", temp);
+		outb_p(temp, SMBHSTSTS);
+
+	  } else  if(temp & 0xe) {
+		dev_dbg(&poulsbo_adapter.dev, "SMBus error (%02x). "
+			"Resetting...\n", temp);
+		outb_p(temp, SMBHSTSTS);
+	  }
+	  if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+	    dev_err(&poulsbo_adapter.dev, "Failed! (%02x)\n", temp);
+	    return -1;
+	  } else {
+	    dev_dbg(&poulsbo_adapter.dev, "Successfull!\n");
+	  }
+	}
+
+	/* start the transaction by setting bit 4 */
+	outb_p(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
+
+	/* We will always wait for a fraction of a second! (See POULSBO docs errata) */
+	do {
+		msleep(1);
+		temp = inb_p(SMBHSTSTS);
+	} while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout >= MAX_TIMEOUT) {
+		dev_err(&poulsbo_adapter.dev, "SMBus Timeout!\n");
+		result = -1;
+	}
+
+	if (temp & 0x10) {
+		result = -1;
+		dev_err(&poulsbo_adapter.dev, "Error: Failed bus transaction\n");
+	}
+
+	if (temp & 0x08) {
+		result = -1;
+		dev_dbg(&poulsbo_adapter.dev, "Bus collision! SMBus may be "
+			"locked until next hard reset. (sorry!)\n");
+		/* Clock stops and slave is stuck in mid-transmission */
+	}
+
+	if (temp & 0x04) {
+		result = -1;
+		dev_dbg(&poulsbo_adapter.dev, "Error: no response!\n");
+	}
+	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+	  if( temp == 0x1) {
+	    dev_dbg(&poulsbo_adapter.dev, "post complete!\n");
+	    outb_p(temp, SMBHSTSTS);
+	}
+	  else if(temp & 0xe) {
+	    dev_dbg(&poulsbo_adapter.dev, "Error: bus, etc!\n");
+	    outb_p(inb(SMBHSTSTS), SMBHSTSTS);
+	  }
+	}
+	  msleep(1);
+	if ((temp = inb_p(SMBHSTSTS)) & 0xe) {
+	  /* BSY, device or bus error */
+		dev_err(&poulsbo_adapter.dev, "Failed reset at end of "
+			"transaction (%02x), Bus error\n", temp);
+	}
+	dev_dbg(&poulsbo_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+	return result;
+}
+
+/* Return -1 on error. */
+static s32 poulsbo_access(struct i2c_adapter * adap, u16 addr,
+		 unsigned short flags, char read_write,
+		 u8 command, int size, union i2c_smbus_data * data)
+{
+	int i, len;
+	dev_dbg(&poulsbo_adapter.dev,"access size: %d %s\n", size, (read_write)?"READ":"WRITE");
+	switch (size) {
+	case I2C_SMBUS_PROC_CALL:
+		dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
+		return -1;
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = POULSBO_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		size = POULSBO_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		size = POULSBO_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		size = POULSBO_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0)
+				len = 0;
+			if (len > 32)
+				len = 32;
+			outb_p(len, SMBHSTDAT0);
+			i = inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		size = POULSBO_BLOCK_DATA;
+		break;
+	}
+	dev_dbg(&poulsbo_adapter.dev,"write size %d to 0x%04x\n", size, SMBHSTCNT);
+	outb_p((size & 0x7), SMBHSTCNT);
+
+	if (poulsbo_transaction())	/* Error in transaction */
+		return -1;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == POULSBO_QUICK))
+		return 0;
+
+
+	switch (size) {
+	case POULSBO_BYTE:	/* Where is the result put? I assume here it is in
+				   SMBHSTDAT0 but it might just as well be in the
+				   SMBHSTCMD. No clue in the docs */
+
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case POULSBO_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case POULSBO_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case POULSBO_BLOCK_DATA:
+		data->block[0] = inb_p(SMBHSTDAT0);
+		i = inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
+		for (i = 1; i <= data->block[0]; i++)
+			data->block[i] = inb_p(SMBBLKDAT);
+		break;
+	}
+	return 0;
+}
+
+static u32 poulsbo_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= poulsbo_access,
+	.functionality	= poulsbo_func,
+};
+
+static struct i2c_adapter poulsbo_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON,
+	.algo		= &smbus_algorithm,
+};
+
+static struct pci_device_id poulsbo_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_LPC),
+	  .driver_data = 0xf8 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, poulsbo_ids);
+
+static int __devinit poulsbo_probe(struct pci_dev *dev,
+				const struct pci_device_id *id)
+{
+	int retval;
+	retval = poulsbo_setup(dev, id);
+	if (retval)
+		return retval;
+
+	/* set up the driverfs linkage to our parent device */
+	poulsbo_adapter.dev.parent = &dev->dev;
+
+	snprintf(poulsbo_adapter.name, I2C_NAME_SIZE,
+		"SMBus POULSBO adapter at %04x", poulsbo_smba);
+
+	if ((retval = i2c_add_adapter(&poulsbo_adapter))) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(poulsbo_smba, SMBIOSIZE);
+		poulsbo_smba = 0;
+	}
+
+	return retval;
+}
+
+static void __devexit poulsbo_remove(struct pci_dev *dev)
+{
+	if (poulsbo_smba) {
+		i2c_del_adapter(&poulsbo_adapter);
+		release_region(poulsbo_smba, SMBIOSIZE);
+		poulsbo_smba = 0;
+	}
+}
+
+static struct pci_driver poulsbo_driver = {
+	.name		= "poulsbo_smbus",
+	.id_table	= poulsbo_ids,
+	.probe		= poulsbo_probe,
+	.remove		= __devexit_p(poulsbo_remove),
+};
+
+static int __init i2c_poulsbo_init(void)
+{
+	return pci_register_driver(&poulsbo_driver);
+}
+
+static void __exit i2c_poulsbo_exit(void)
+{
+	pci_unregister_driver(&poulsbo_driver);
+}
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com> ");
+MODULE_DESCRIPTION("POULSBO SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_poulsbo_init);
+module_exit(i2c_poulsbo_exit);
diff -urN linux-2.6.24.7-rt20/drivers/i2c/busses/Kconfig linux-2.6.24.7-rt20-atom/drivers/i2c/busses/Kconfig
--- linux-2.6.24.7-rt20/drivers/i2c/busses/Kconfig	2008-10-06 08:30:17.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/i2c/busses/Kconfig	2008-09-28 11:32:13.000000000 +0200
@@ -239,6 +239,15 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-piix4.
 
+config I2C_POULSBO
+       tristate "Intel SCH (Poulsbo SMBUS 1.0)"
+       depends on I2C && PCI
+       help
+         If you say yes to this option, support will be included for the Intel
+         SCH
+           Intel  POULSBO
+         will be called i2c-sch.
+
 config I2C_IBM_IIC
 	tristate "IBM PPC 4xx on-chip I2C interface"
 	depends on IBM_OCP
diff -urN linux-2.6.24.7-rt20/drivers/i2c/busses/Makefile linux-2.6.24.7-rt20-atom/drivers/i2c/busses/Makefile
--- linux-2.6.24.7-rt20/drivers/i2c/busses/Makefile	2008-10-06 08:30:17.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/i2c/busses/Makefile	2008-09-28 11:32:13.000000000 +0200
@@ -33,6 +33,7 @@
 obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
 obj-$(CONFIG_I2C_PMCMSP)	+= i2c-pmcmsp.o
+obj-$(CONFIG_I2C_POULSBO)      += i2c-sch.o
 obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
 obj-$(CONFIG_I2C_PROSAVAGE)	+= i2c-prosavage.o
 obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
diff -urN linux-2.6.24.7-rt20/drivers/ide/pci/piix.c linux-2.6.24.7-rt20-atom/drivers/ide/pci/piix.c
--- linux-2.6.24.7-rt20/drivers/ide/pci/piix.c	2008-10-06 08:30:17.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/ide/pci/piix.c	2008-09-28 11:32:29.000000000 +0200
@@ -438,6 +438,7 @@
 	/* 22 */ DECLARE_ICH_DEV("ICH4",	ATA_UDMA5),
 	/* 23 */ DECLARE_ICH_DEV("ESB2",	ATA_UDMA5),
 	/* 24 */ DECLARE_ICH_DEV("ICH8M",	ATA_UDMA5),
+	/* 25 */ DECLARE_ICH_DEV("POULSBO",	ATA_UDMA5),
 };
 
 /**
@@ -511,6 +512,7 @@
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1),  22 },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18),    23 },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6),     24 },
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_POULSBO_IDE),     25 },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
diff -urN linux-2.6.24.7-rt20/drivers/input/mousedev.c linux-2.6.24.7-rt20-atom/drivers/input/mousedev.c
--- linux-2.6.24.7-rt20/drivers/input/mousedev.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/input/mousedev.c	2008-09-28 11:33:37.000000000 +0200
@@ -1009,6 +1009,8 @@
 		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
 		.relbit = { BIT_MASK(REL_WHEEL) },
 	},	/* A separate scrollwheel */
+/* masked for MID device touchscreen double-click issue */
+#if 0
 	{
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
 				INPUT_DEVICE_ID_MATCH_KEYBIT |
@@ -1018,6 +1020,7 @@
 		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
 	},	/* A tablet like device, at least touch detection,
 		   two absolute axes */
+#endif
 	{
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
 				INPUT_DEVICE_ID_MATCH_KEYBIT |
diff -urN linux-2.6.24.7-rt20/drivers/Kconfig linux-2.6.24.7-rt20-atom/drivers/Kconfig
--- linux-2.6.24.7-rt20/drivers/Kconfig	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/Kconfig	2008-09-28 11:30:55.000000000 +0200
@@ -58,6 +58,8 @@
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/thermal/Kconfig"
+
 source "drivers/watchdog/Kconfig"
 
 source "drivers/ssb/Kconfig"
diff -urN linux-2.6.24.7-rt20/drivers/Makefile linux-2.6.24.7-rt20-atom/drivers/Makefile
--- linux-2.6.24.7-rt20/drivers/Makefile	2008-10-06 08:30:16.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/Makefile	2008-09-28 11:30:55.000000000 +0200
@@ -65,6 +65,7 @@
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_POWER_SUPPLY)	+= power/
 obj-$(CONFIG_HWMON)		+= hwmon/
+obj-$(CONFIG_THERMAL)		+= thermal/
 obj-$(CONFIG_WATCHDOG)		+= watchdog/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
diff -urN linux-2.6.24.7-rt20/drivers/misc/intel_menlow.c linux-2.6.24.7-rt20-atom/drivers/misc/intel_menlow.c
--- linux-2.6.24.7-rt20/drivers/misc/intel_menlow.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/misc/intel_menlow.c	2008-09-28 11:30:55.000000000 +0200
@@ -0,0 +1,527 @@
+/*
+*  intel_menlow.c - Intel menlow Driver for thermal management extension
+*
+*  Copyright (C) 2008 Intel Corp
+*  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+*  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; version 2 of the License.
+*
+*  This program is distributed in the hope that it will be useful, but
+*  WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+*  General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along
+*  with this program; if not, write to the Free Software Foundation, Inc.,
+*  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+*
+*  This driver creates the sys I/F for programming the sensors.
+*  It also implements the driver for intel menlow memory controller (hardware
+*  id is INT0002) which makes use of the platform specific ACPI methods
+*  to get/set bandwidth.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+
+#include <linux/thermal.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Thomas Sujith");
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Intel Menlow platform specific driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Memory controller device control
+ */
+
+#define MEMORY_GET_BANDWIDTH "GTHS"
+#define MEMORY_SET_BANDWIDTH "STHS"
+#define MEMORY_ARG_CUR_BANDWIDTH 1
+#define MEMORY_ARG_MAX_BANDWIDTH 0
+
+static int
+memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
+			     unsigned long *max_state)
+{
+	struct acpi_device *device = cdev->devdata;
+	acpi_handle handle = device->handle;
+	unsigned long value;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	acpi_status status = AE_OK;
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
+	status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
+				       &arg_list, &value);
+	if (ACPI_FAILURE(status))
+		return -EFAULT;
+
+	*max_state = value - 1;
+	return 0;
+}
+
+static int
+memory_get_max_bandwidth(struct thermal_cooling_device *cdev, char *buf)
+{
+	unsigned long value;
+	if (memory_get_int_max_bandwidth(cdev,&value))
+		return -EINVAL;
+
+	return sprintf(buf, "%ld\n", value);
+}
+
+static int
+memory_get_cur_bandwidth(struct thermal_cooling_device *cdev, char *buf)
+{
+	struct acpi_device *device = cdev->devdata;
+	acpi_handle handle = device->handle;
+	unsigned long value;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	acpi_status status = AE_OK;
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
+	status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
+				       &arg_list, &value);
+	if (ACPI_FAILURE(status))
+		return -EFAULT;
+
+	return sprintf(buf, "%ld\n", value);
+}
+
+static int
+memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
+			 unsigned int state)
+{
+	struct acpi_device *device = cdev->devdata;
+	acpi_handle handle = device->handle;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	acpi_status status;
+	int temp;
+	unsigned long max_state;
+
+	if (memory_get_int_max_bandwidth(cdev,&max_state))
+		return -EFAULT;
+
+	if (max_state < 0 || state > max_state)
+		return -EINVAL;
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = state;
+
+	status =
+	    acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
+				  (unsigned long *)&temp);
+
+	printk(KERN_INFO
+		"Bandwidth value was %d: status is %d\n", state, status);
+	if (ACPI_FAILURE(status))
+		return -EFAULT;
+
+	return 0;
+}
+
+static struct thermal_cooling_device_ops memory_cooling_ops = {
+	.get_max_state = memory_get_max_bandwidth,
+	.get_cur_state = memory_get_cur_bandwidth,
+	.set_cur_state = memory_set_cur_bandwidth,
+};
+
+/*
+ * Memory Device Management
+ */
+static int intel_menlow_memory_add(struct acpi_device *device)
+{
+	int result = -ENODEV;
+	acpi_status status = AE_OK;
+	acpi_handle dummy;
+	struct thermal_cooling_device *cdev;
+
+	if (!device)
+		return -EINVAL;
+
+	status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy);
+	if (ACPI_FAILURE(status))
+		goto end;
+
+	status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy);
+	if (ACPI_FAILURE(status))
+		goto end;
+
+	cdev = thermal_cooling_device_register("Memory controller", device,
+					       &memory_cooling_ops);
+	acpi_driver_data(device) = cdev;
+	if (!cdev)
+		result = -ENODEV;
+	else {
+		result =
+		    sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
+				      "thermal_cooling");
+		if (result)
+			goto end;
+		result =
+		    sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
+				      "device");
+		if (result)
+			goto end;
+	}
+
+      end:
+	return result;
+}
+
+static int intel_menlow_memory_remove(struct acpi_device *device, int type)
+{
+	struct thermal_cooling_device *cdev = acpi_driver_data(device);
+
+	if (!device || !cdev)
+		return -EINVAL;
+
+	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+	sysfs_remove_link(&cdev->device.kobj, "device");
+	thermal_cooling_device_unregister(cdev);
+
+	return 0;
+}
+
+const static struct acpi_device_id intel_menlow_memory_ids[] = {
+	{"INT0002", 0},
+	{"", 0},
+};
+
+static struct acpi_driver intel_menlow_memory_driver = {
+	.name = "intel_menlow_thermal_control",
+	.ids = intel_menlow_memory_ids,
+	.ops = {
+		.add = intel_menlow_memory_add,
+		.remove = intel_menlow_memory_remove,
+		},
+};
+
+/*
+ * Sensor control on menlow platform
+ */
+
+#define THERMAL_AUX0 0
+#define THERMAL_AUX1 1
+#define GET_AUX0 "GAX0"
+#define GET_AUX1 "GAX1"
+#define SET_AUX0 "SAX0"
+#define SET_AUX1 "SAX1"
+
+struct intel_menlow_attribute {
+	struct device_attribute attr;
+	struct device *device;
+	acpi_handle handle;
+	struct list_head node;
+};
+
+static LIST_HEAD(intel_menlow_attr_list);
+static DEFINE_MUTEX(intel_menlow_attr_lock);
+
+/*
+ * sensor_get_auxtrip
+ * -----------------
+ * get the current auxtrip value from sensor through proprietory ACPI methods
+ * name: Thermalzone name
+ * auxtype : AUX0/AUX1
+ * buf: syfs buffer
+ */
+static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
+{
+	acpi_status status;
+
+	if ((index != 0 && index != 1) || !value)
+		return -EINVAL;
+
+	status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
+				       NULL, (unsigned long *)value);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * sensor_set_auxtrip
+ * -----------------
+ * set the new auxtrip value to sensor through proprietory ACPI methods
+ * name: Thermalzone name
+ * auxtype : AUX0/AUX1
+ * buf: syfs buffer
+ */
+static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
+{
+	acpi_status status;
+	union acpi_object arg = {
+		ACPI_TYPE_INTEGER
+	};
+	struct acpi_object_list args = {
+		1, &arg
+	};
+	int temp;
+
+	if (index != 0 && index != 1)
+		return -EINVAL;
+
+	status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
+				       NULL, (unsigned long *)&temp);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+	if ((index && value < temp) || (!index && value > temp))
+		return -EINVAL;
+
+	arg.integer.value = value;
+	status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
+				       &args, (unsigned long *)&temp);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+
+	/* do we need to check the return value of SAX0/SAX1 ? */
+
+	return 0;
+}
+
+#define to_intel_menlow_attr(_attr)	\
+	container_of(_attr, struct intel_menlow_attribute, attr)
+
+static ssize_t aux0_show(struct device *dev,
+			 struct device_attribute *dev_attr, char *buf)
+{
+	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+	int value;
+	int result;
+
+	result = sensor_get_auxtrip(attr->handle, 0, &value);
+
+	return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
+}
+
+static ssize_t aux1_show(struct device *dev,
+			 struct device_attribute *dev_attr, char *buf)
+{
+	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+	int value;
+	int result;
+
+	result = sensor_get_auxtrip(attr->handle, 1, &value);
+
+	return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
+}
+
+static ssize_t aux0_store(struct device *dev,
+			  struct device_attribute *dev_attr,
+			  const char *buf, size_t count)
+{
+	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+	int value;
+	int result;
+
+	/*Sanity check; should be a positive integer */
+	if (!sscanf(buf, "%d", &value))
+		return -EINVAL;
+
+	if (value < 0)
+		return -EINVAL;
+
+	result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
+	return result ? result : count;
+}
+
+static ssize_t aux1_store(struct device *dev,
+			  struct device_attribute *dev_attr,
+			  const char *buf, size_t count)
+{
+	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
+	int value;
+	int result;
+
+	/*Sanity check; should be a positive integer */
+	if (!sscanf(buf, "%d", &value))
+		return -EINVAL;
+
+	if (value < 0)
+		return -EINVAL;
+
+	result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
+	return result ? result : count;
+}
+
+/* BIOS can enable/disable the thermal user application in dabney platform */
+#define BIOS_ENABLED "\\_TZ.GSTS"
+static ssize_t bios_enabled_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	acpi_status status;
+	unsigned long bios_enabled;
+
+	status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
+}
+
+static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
+					  void *store, struct device *dev,
+					  acpi_handle handle)
+{
+	struct intel_menlow_attribute *attr;
+	int result;
+
+	attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	attr->attr.attr.name = name;
+	attr->attr.attr.mode = mode;
+	attr->attr.show = show;
+	attr->attr.store = store;
+	attr->device = dev;
+	attr->handle = handle;
+
+	result = device_create_file(dev, &attr->attr);
+	if (result)
+		return result;
+
+	mutex_lock(&intel_menlow_attr_lock);
+	list_add_tail(&attr->node, &intel_menlow_attr_list);
+	mutex_unlock(&intel_menlow_attr_lock);
+
+	return 0;
+}
+
+static acpi_status
+intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
+			     void *context, void **rv)
+{
+	acpi_status status;
+	acpi_handle dummy;
+	struct thermal_zone_device *thermal;
+	int result;
+
+	result = acpi_bus_get_private_data(handle, (void **)&thermal);
+	if (result)
+		return 0;
+
+	/* _TZ must have the AUX0/1 methods */
+	status = acpi_get_handle(handle, GET_AUX0, &dummy);
+	if (ACPI_FAILURE(status))
+		goto not_found;
+
+	status = acpi_get_handle(handle, SET_AUX0, &dummy);
+	if (ACPI_FAILURE(status))
+		goto not_found;
+
+	result = intel_menlow_add_one_attribute("aux0", 0644,
+						aux0_show, aux0_store,
+						&thermal->device, handle);
+	if (result)
+		return AE_ERROR;
+
+	status = acpi_get_handle(handle, GET_AUX1, &dummy);
+	if (ACPI_FAILURE(status))
+		goto not_found;
+
+	status = acpi_get_handle(handle, SET_AUX1, &dummy);
+	if (ACPI_FAILURE(status))
+		goto not_found;
+
+	result = intel_menlow_add_one_attribute("aux1", 0644,
+						aux1_show, aux1_store,
+						&thermal->device, handle);
+	if (result)
+		return AE_ERROR;
+
+	/*
+	 * create the "dabney_enabled" attribute which means the user app
+	 * should be loaded or not
+	 */
+
+	result = intel_menlow_add_one_attribute("bios_enabled", 0444,
+						bios_enabled_show, NULL,
+						&thermal->device, handle);
+	if (result)
+		return AE_ERROR;
+
+      not_found:
+	if (status == AE_NOT_FOUND)
+		return AE_OK;
+	else
+		return status;
+}
+
+static void intel_menlow_unregister_sensor(void)
+{
+	struct intel_menlow_attribute *pos, *next;
+
+	mutex_lock(&intel_menlow_attr_lock);
+	list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
+		list_del(&pos->node);
+		device_remove_file(pos->device, &pos->attr);
+		kfree(pos);
+	}
+	mutex_unlock(&intel_menlow_attr_lock);
+
+	return;
+}
+
+static int __init intel_menlow_module_init(void)
+{
+	int result = -ENODEV;
+	acpi_status status;
+	unsigned long enable;
+
+	if (acpi_disabled)
+		return result;
+
+	/* Looking for the \_TZ.GSTS method */
+	status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
+	if (ACPI_FAILURE(status) || !enable)
+		return -ENODEV;
+
+	/* Looking for ACPI device MEM0 with hardware id INT0002 */
+	result = acpi_bus_register_driver(&intel_menlow_memory_driver);
+	if (result)
+		return result;
+
+	/* Looking for sensors in each ACPI thermal zone */
+	status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
+				     ACPI_UINT32_MAX,
+				     intel_menlow_register_sensor, NULL, NULL);
+	if (ACPI_FAILURE(status))
+		result = -ENODEV;
+
+	return 0;
+}
+
+static void __exit intel_menlow_module_exit(void)
+{
+	acpi_bus_unregister_driver(&intel_menlow_memory_driver);
+	intel_menlow_unregister_sensor();
+}
+
+module_init(intel_menlow_module_init);
+module_exit(intel_menlow_module_exit);
diff -urN linux-2.6.24.7-rt20/drivers/misc/Kconfig linux-2.6.24.7-rt20-atom/drivers/misc/Kconfig
--- linux-2.6.24.7-rt20/drivers/misc/Kconfig	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/misc/Kconfig	2008-09-28 11:30:55.000000000 +0200
@@ -232,4 +232,14 @@
 
 	  If unsure, say N.
 
+config INTEL_MENLOW
+        tristate "Thermal Management driver for Intel menlow platform"
+        depends on ACPI_THERMAL
+	default n
+        ---help---
+          ACPI thermal management enhancement driver on
+	  Intel Menlow platform.
+
+          If you are not sure, say N here.
+
 endif # MISC_DEVICES
diff -urN linux-2.6.24.7-rt20/drivers/misc/Makefile linux-2.6.24.7-rt20-atom/drivers/misc/Makefile
--- linux-2.6.24.7-rt20/drivers/misc/Makefile	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/misc/Makefile	2008-09-28 11:30:55.000000000 +0200
@@ -17,3 +17,4 @@
 obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
 obj-$(CONFIG_FUJITSU_LAPTOP)	+= fujitsu-laptop.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
+obj-$(CONFIG_INTEL_MENLOW)	+= intel_menlow.o
diff -urN linux-2.6.24.7-rt20/drivers/mmc/core/core.c linux-2.6.24.7-rt20-atom/drivers/mmc/core/core.c
--- linux-2.6.24.7-rt20/drivers/mmc/core/core.c	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/mmc/core/core.c	2008-09-28 11:32:59.000000000 +0200
@@ -645,6 +645,10 @@
 		mmc_claim_host(host);
 
 		mmc_power_up(host);
+
+		/* add a 25ms delay for SiB workaround */
+		mmc_delay(25);
+
 		mmc_go_idle(host);
 
 		mmc_send_if_cond(host, host->ocr_avail);
diff -urN linux-2.6.24.7-rt20/drivers/mmc/core/sdio_cis.c linux-2.6.24.7-rt20-atom/drivers/mmc/core/sdio_cis.c
--- linux-2.6.24.7-rt20/drivers/mmc/core/sdio_cis.c	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/mmc/core/sdio_cis.c	2008-09-28 11:32:59.000000000 +0200
@@ -151,7 +151,8 @@
 	if (ret) {
 		printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
 		       "type %u\n", mmc_hostname(card->host), size, buf[0]);
-		return ret;
+		/* masked by feng for 8688 + CB debug . */
+		/* return ret; */
 	}
 
 	return 0;
diff -urN linux-2.6.24.7-rt20/drivers/mmc/core/sdio_io.c linux-2.6.24.7-rt20-atom/drivers/mmc/core/sdio_io.c
--- linux-2.6.24.7-rt20/drivers/mmc/core/sdio_io.c	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/mmc/core/sdio_io.c	2008-09-28 11:32:59.000000000 +0200
@@ -546,3 +546,72 @@
 		*err_ret = ret;
 }
 EXPORT_SYMBOL_GPL(sdio_f0_writeb);
+
+static char* sdio_version[4] = {
+	"version 1.00",
+	"version 1.10",
+	"version 1.20",
+	"version 2.00"
+};
+
+static char* sd_phy_version[4] = {
+	"version 1.01",
+	"version 1.10",
+	"version 2.00"
+};
+
+void sdio_dump_cccr(struct sdio_func *func)
+{
+	struct mmc_card *card = func->card;
+	u8       data, val;
+	u8      *str;
+	int      i;
+
+	printk(KERN_INFO "\nStart to dump SDIO CCCR registers:\n");
+
+	/* dump sdio version */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
+	val = (data >> 4) & 0xf;
+	if (val <= 3)
+		printk(KERN_INFO "SDIO Spec: %s\n", sdio_version[val]);
+	else
+		printk(KERN_INFO "This card doesn't comply with any SDIO spec version!!\n");
+                
+	/* dump sd PHY version */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SD, 0, &data);
+	val = data & 0xf;
+	if (val <= 2)
+		printk(KERN_INFO "SD PHY spec: %s\n", sd_phy_version[val]);
+	else
+		printk(KERN_INFO "This card doesn't comply with any SD PHY spec version!!\n");
+
+	/* dump IO Enalbe reg */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IOEx, 0, &data);
+	printk(KERN_INFO "IO Enable Reg: 0x%02x\n", data); 
+
+	/* dump IO Ready reg */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IORx, 0, &data);
+	printk(KERN_INFO "IO Ready Reg: 0x%02x\n", data); 
+        
+	/* dump INT Enable reg */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IENx, 0, &data);
+	printk(KERN_INFO "INT Enable Reg: 0x%02x\n", data); 
+
+	/* dump INT Pending reg */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &data);
+	printk(KERN_INFO "INT Pending Reg: 0x%02x\n", data); 
+
+	/* dump Bus Interface reg */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &data);
+	val = data & 0x3;
+	printk(KERN_INFO "Bus Width: %d bit\n", (val ? 4 : 1));
+
+	/* dump capability reg */
+	mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
+	printk(KERN_INFO "Multi-Block support: %s\n", (data & SDIO_CCCR_CAP_SMB) ? "YES" : "NO");
+	printk(KERN_INFO "Suspend/Resume support: %s\n", (data & SDIO_CCCR_CAP_SBS) ? "YES" : "NO");
+	printk(KERN_INFO "Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_LSC) ? "YES" : "NO");
+	printk(KERN_INFO "4 bits Low Speed Card: %s\n", (data & SDIO_CCCR_CAP_4BLS) ? "YES" : "NO");
+}
+EXPORT_SYMBOL_GPL(sdio_dump_cccr);
+
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/82571.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/82571.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/82571.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/82571.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1351 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/*
- * 82571EB Gigabit Ethernet Controller
- * 82571EB Gigabit Ethernet Controller (Fiber)
- * 82572EI Gigabit Ethernet Controller (Copper)
- * 82572EI Gigabit Ethernet Controller (Fiber)
- * 82572EI Gigabit Ethernet Controller
- * 82573V Gigabit Ethernet Controller (Copper)
- * 82573E Gigabit Ethernet Controller (Copper)
- * 82573L Gigabit Ethernet Controller
- */
-
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "e1000.h"
-
-#define ID_LED_RESERVED_F746 0xF746
-#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
-			      (ID_LED_OFF1_ON2  <<  8) | \
-			      (ID_LED_DEF1_DEF2 <<  4) | \
-			      (ID_LED_DEF1_DEF2))
-
-#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
-
-static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
-static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
-static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
-static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
-				      u16 words, u16 *data);
-static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
-static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
-static s32 e1000_setup_link_82571(struct e1000_hw *hw);
-static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
-
-/**
- *  e1000_init_phy_params_82571 - Init PHY func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-
-	if (hw->media_type != e1000_media_type_copper) {
-		phy->type = e1000_phy_none;
-		return 0;
-	}
-
-	phy->addr			 = 1;
-	phy->autoneg_mask		 = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us		 = 100;
-
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		phy->type		 = e1000_phy_igp_2;
-		break;
-	case e1000_82573:
-		phy->type		 = e1000_phy_m88;
-		break;
-	default:
-		return -E1000_ERR_PHY;
-		break;
-	}
-
-	/* This can only be done after all function pointers are setup. */
-	ret_val = e1000_get_phy_id_82571(hw);
-
-	/* Verify phy id */
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		if (phy->id != IGP01E1000_I_PHY_ID)
-			return -E1000_ERR_PHY;
-		break;
-	case e1000_82573:
-		if (phy->id != M88E1111_I_PHY_ID)
-			return -E1000_ERR_PHY;
-		break;
-	default:
-		return -E1000_ERR_PHY;
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_init_nvm_params_82571 - Init NVM func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u16 size;
-
-	nvm->opcode_bits = 8;
-	nvm->delay_usec = 1;
-	switch (nvm->override) {
-	case e1000_nvm_override_spi_large:
-		nvm->page_size = 32;
-		nvm->address_bits = 16;
-		break;
-	case e1000_nvm_override_spi_small:
-		nvm->page_size = 8;
-		nvm->address_bits = 8;
-		break;
-	default:
-		nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
-		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
-		break;
-	}
-
-	switch (hw->mac.type) {
-	case e1000_82573:
-		if (((eecd >> 15) & 0x3) == 0x3) {
-			nvm->type = e1000_nvm_flash_hw;
-			nvm->word_size = 2048;
-			/* Autonomous Flash update bit must be cleared due
-			 * to Flash update issue.
-			 */
-			eecd &= ~E1000_EECD_AUPDEN;
-			ew32(EECD, eecd);
-			break;
-		}
-		/* Fall Through */
-	default:
-		nvm->type	= e1000_nvm_eeprom_spi;
-		size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
-				  E1000_EECD_SIZE_EX_SHIFT);
-		/* Added to a constant, "size" becomes the left-shift value
-		 * for setting word_size.
-		 */
-		size += NVM_WORD_SIZE_BASE_SHIFT;
-		nvm->word_size	= 1 << size;
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_init_mac_params_82571 - Init MAC func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_mac_operations *func = &mac->ops;
-
-	/* Set media type */
-	switch (adapter->pdev->device) {
-	case E1000_DEV_ID_82571EB_FIBER:
-	case E1000_DEV_ID_82572EI_FIBER:
-	case E1000_DEV_ID_82571EB_QUAD_FIBER:
-		hw->media_type = e1000_media_type_fiber;
-		break;
-	case E1000_DEV_ID_82571EB_SERDES:
-	case E1000_DEV_ID_82572EI_SERDES:
-		hw->media_type = e1000_media_type_internal_serdes;
-		break;
-	default:
-		hw->media_type = e1000_media_type_copper;
-		break;
-	}
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid =
-		(er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
-
-	/* check for link */
-	switch (hw->media_type) {
-	case e1000_media_type_copper:
-		func->setup_physical_interface = e1000_setup_copper_link_82571;
-		func->check_for_link = e1000e_check_for_copper_link;
-		func->get_link_up_info = e1000e_get_speed_and_duplex_copper;
-		break;
-	case e1000_media_type_fiber:
-		func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
-		func->check_for_link = e1000e_check_for_fiber_link;
-		func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
-		break;
-	case e1000_media_type_internal_serdes:
-		func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
-		func->check_for_link = e1000e_check_for_serdes_link;
-		func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
-		break;
-	default:
-		return -E1000_ERR_CONFIG;
-		break;
-	}
-
-	return 0;
-}
-
-static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	static int global_quad_port_a; /* global port a indication */
-	struct pci_dev *pdev = adapter->pdev;
-	u16 eeprom_data = 0;
-	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
-	s32 rc;
-
-	rc = e1000_init_mac_params_82571(adapter);
-	if (rc)
-		return rc;
-
-	rc = e1000_init_nvm_params_82571(hw);
-	if (rc)
-		return rc;
-
-	rc = e1000_init_phy_params_82571(hw);
-	if (rc)
-		return rc;
-
-	/* tag quad port adapters first, it's used below */
-	switch (pdev->device) {
-	case E1000_DEV_ID_82571EB_QUAD_COPPER:
-	case E1000_DEV_ID_82571EB_QUAD_FIBER:
-	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
-		adapter->flags |= FLAG_IS_QUAD_PORT;
-		/* mark the first port */
-		if (global_quad_port_a == 0)
-			adapter->flags |= FLAG_IS_QUAD_PORT_A;
-		/* Reset for multiple quad port adapters */
-		global_quad_port_a++;
-		if (global_quad_port_a == 4)
-			global_quad_port_a = 0;
-		break;
-	default:
-		break;
-	}
-
-	switch (adapter->hw.mac.type) {
-	case e1000_82571:
-		/* these dual ports don't have WoL on port B at all */
-		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
-		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
-		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
-		    (is_port_b))
-			adapter->flags &= ~FLAG_HAS_WOL;
-		/* quad ports only support WoL on port A */
-		if (adapter->flags & FLAG_IS_QUAD_PORT &&
-		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
-			adapter->flags &= ~FLAG_HAS_WOL;
-		break;
-
-	case e1000_82573:
-		if (pdev->device == E1000_DEV_ID_82573L) {
-			e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
-				       &eeprom_data);
-			if (eeprom_data & NVM_WORD1A_ASPM_MASK)
-				adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
-		}
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY registers and stores the PHY ID and possibly the PHY
- *  revision in the hardware structure.
- **/
-static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		/* The 82571 firmware may still be configuring the PHY.
-		 * In this case, we cannot access the PHY until the
-		 * configuration is done.  So we explicitly set the
-		 * PHY ID. */
-		phy->id = IGP01E1000_I_PHY_ID;
-		break;
-	case e1000_82573:
-		return e1000e_get_phy_id(hw);
-		break;
-	default:
-		return -E1000_ERR_PHY;
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Acquire the HW semaphore to access the PHY or NVM
- **/
-static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
-{
-	u32 swsm;
-	s32 timeout = hw->nvm.word_size + 1;
-	s32 i = 0;
-
-	/* Get the FW semaphore. */
-	for (i = 0; i < timeout; i++) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
-
-		/* Semaphore acquired if bit latched */
-		if (er32(SWSM) & E1000_SWSM_SWESMBI)
-			break;
-
-		udelay(50);
-	}
-
-	if (i == timeout) {
-		/* Release semaphores */
-		e1000e_put_hw_semaphore(hw);
-		hw_dbg(hw, "Driver can't access the NVM\n");
-		return -E1000_ERR_NVM;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_put_hw_semaphore_82571 - Release hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Release hardware semaphore used to access the PHY or NVM
- **/
-static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
-{
-	u32 swsm;
-
-	swsm = er32(SWSM);
-
-	swsm &= ~E1000_SWSM_SWESMBI;
-
-	ew32(SWSM, swsm);
-}
-
-/**
- *  e1000_acquire_nvm_82571 - Request for access to the EEPROM
- *  @hw: pointer to the HW structure
- *
- *  To gain access to the EEPROM, first we must obtain a hardware semaphore.
- *  Then for non-82573 hardware, set the EEPROM access request bit and wait
- *  for EEPROM access grant bit.  If the access grant bit is not set, release
- *  hardware semaphore.
- **/
-static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	ret_val = e1000_get_hw_semaphore_82571(hw);
-	if (ret_val)
-		return ret_val;
-
-	if (hw->mac.type != e1000_82573)
-		ret_val = e1000e_acquire_nvm(hw);
-
-	if (ret_val)
-		e1000_put_hw_semaphore_82571(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_release_nvm_82571 - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
- **/
-static void e1000_release_nvm_82571(struct e1000_hw *hw)
-{
-	e1000e_release_nvm(hw);
-	e1000_put_hw_semaphore_82571(hw);
-}
-
-/**
- *  e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  For non-82573 silicon, write data to EEPROM at offset using SPI interface.
- *
- *  If e1000e_update_nvm_checksum is not called after this function, the
- *  EEPROM will most likley contain an invalid checksum.
- **/
-static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
-				 u16 *data)
-{
-	s32 ret_val;
-
-	switch (hw->mac.type) {
-	case e1000_82573:
-		ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
-		break;
-	case e1000_82571:
-	case e1000_82572:
-		ret_val = e1000e_write_nvm_spi(hw, offset, words, data);
-		break;
-	default:
-		ret_val = -E1000_ERR_NVM;
-		break;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_update_nvm_checksum_82571 - Update EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
- *  up to the checksum.  Then calculates the EEPROM checksum and writes the
- *  value to the EEPROM.
- **/
-static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
-{
-	u32 eecd;
-	s32 ret_val;
-	u16 i;
-
-	ret_val = e1000e_update_nvm_checksum_generic(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* If our nvm is an EEPROM, then we're done
-	 * otherwise, commit the checksum to the flash NVM. */
-	if (hw->nvm.type != e1000_nvm_flash_hw)
-		return ret_val;
-
-	/* Check for pending operations. */
-	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
-		msleep(1);
-		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
-			break;
-	}
-
-	if (i == E1000_FLASH_UPDATES)
-		return -E1000_ERR_NVM;
-
-	/* Reset the firmware if using STM opcode. */
-	if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) {
-		/* The enabling of and the actual reset must be done
-		 * in two write cycles.
-		 */
-		ew32(HICR, E1000_HICR_FW_RESET_ENABLE);
-		e1e_flush();
-		ew32(HICR, E1000_HICR_FW_RESET);
-	}
-
-	/* Commit the write to flash */
-	eecd = er32(EECD) | E1000_EECD_FLUPD;
-	ew32(EECD, eecd);
-
-	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
-		msleep(1);
-		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
-			break;
-	}
-
-	if (i == E1000_FLASH_UPDATES)
-		return -E1000_ERR_NVM;
-
-	return 0;
-}
-
-/**
- *  e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
- *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
- **/
-static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
-{
-	if (hw->nvm.type == e1000_nvm_flash_hw)
-		e1000_fix_nvm_checksum_82571(hw);
-
-	return e1000e_validate_nvm_checksum_generic(hw);
-}
-
-/**
- *  e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  After checking for invalid values, poll the EEPROM to ensure the previous
- *  command has completed before trying to write the next word.  After write
- *  poll for completion.
- *
- *  If e1000e_update_nvm_checksum is not called after this function, the
- *  EEPROM will most likley contain an invalid checksum.
- **/
-static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
-				      u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i;
-	u32 eewr = 0;
-	s32 ret_val = 0;
-
-	/* A check for invalid values:  offset too large, too many words,
-	 * and not enough words. */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-		return -E1000_ERR_NVM;
-	}
-
-	for (i = 0; i < words; i++) {
-		eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
-		       ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
-		       E1000_NVM_RW_REG_START;
-
-		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
-		if (ret_val)
-			break;
-
-		ew32(EEWR, eewr);
-
-		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
-		if (ret_val)
-			break;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_get_cfg_done_82571 - Poll for configuration done
- *  @hw: pointer to the HW structure
- *
- *  Reads the management control register for the config done bit to be set.
- **/
-static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
-{
-	s32 timeout = PHY_CFG_TIMEOUT;
-
-	while (timeout) {
-		if (er32(EEMNGCTL) &
-		    E1000_NVM_CFG_DONE_PORT_0)
-			break;
-		msleep(1);
-		timeout--;
-	}
-	if (!timeout) {
-		hw_dbg(hw, "MNG configuration cycle has not completed.\n");
-		return -E1000_ERR_RESET;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
- *  @hw: pointer to the HW structure
- *  @active: TRUE to enable LPLU, FALSE to disable
- *
- *  Sets the LPLU D0 state according to the active flag.  When activating LPLU
- *  this function also disables smart speed and vice versa.  LPLU will not be
- *  activated unless the device autonegotiation advertisement meets standards
- *  of either 10 or 10/100 or 10/100/1000 at all duplexes.  This is a function
- *  pointer entry point only called by PHY setup routines.
- **/
-static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		return ret_val;
-
-	if (active) {
-		data |= IGP02E1000_PM_D0_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
-		if (ret_val)
-			return ret_val;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
-		if (ret_val)
-			return ret_val;
-	} else {
-		data &= ~IGP02E1000_PM_D0_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
-		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained. */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     &data);
-			if (ret_val)
-				return ret_val;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     &data);
-			if (ret_val)
-				return ret_val;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_reset_hw_82571 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.  This is a
- *  function pointer entry point called by the api module.
- **/
-static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	u32 extcnf_ctrl;
-	u32 ctrl_ext;
-	u32 icr;
-	s32 ret_val;
-	u16 i = 0;
-
-	/* Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = e1000e_disable_pcie_master(hw);
-	if (ret_val)
-		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
-
-	hw_dbg(hw, "Masking off all interrupts\n");
-	ew32(IMC, 0xffffffff);
-
-	ew32(RCTL, 0);
-	ew32(TCTL, E1000_TCTL_PSP);
-	e1e_flush();
-
-	msleep(10);
-
-	/* Must acquire the MDIO ownership before MAC reset.
-	 * Ownership defaults to firmware after a reset. */
-	if (hw->mac.type == e1000_82573) {
-		extcnf_ctrl = er32(EXTCNF_CTRL);
-		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
-		do {
-			ew32(EXTCNF_CTRL, extcnf_ctrl);
-			extcnf_ctrl = er32(EXTCNF_CTRL);
-
-			if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
-				break;
-
-			extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
-			msleep(2);
-			i++;
-		} while (i < MDIO_OWNERSHIP_TIMEOUT);
-	}
-
-	ctrl = er32(CTRL);
-
-	hw_dbg(hw, "Issuing a global reset to MAC\n");
-	ew32(CTRL, ctrl | E1000_CTRL_RST);
-
-	if (hw->nvm.type == e1000_nvm_flash_hw) {
-		udelay(10);
-		ctrl_ext = er32(CTRL_EXT);
-		ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-		ew32(CTRL_EXT, ctrl_ext);
-		e1e_flush();
-	}
-
-	ret_val = e1000e_get_auto_rd_done(hw);
-	if (ret_val)
-		/* We don't want to continue accessing MAC registers. */
-		return ret_val;
-
-	/* Phy configuration from NVM just starts after EECD_AUTO_RD is set.
-	 * Need to wait for Phy configuration completion before accessing
-	 * NVM and Phy.
-	 */
-	if (hw->mac.type == e1000_82573)
-		msleep(25);
-
-	/* Clear any pending interrupt events. */
-	ew32(IMC, 0xffffffff);
-	icr = er32(ICR);
-
-	return 0;
-}
-
-/**
- *  e1000_init_hw_82571 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 e1000_init_hw_82571(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 reg_data;
-	s32 ret_val;
-	u16 i;
-	u16 rar_count = mac->rar_entry_count;
-
-	e1000_initialize_hw_bits_82571(hw);
-
-	/* Initialize identification LED */
-	ret_val = e1000e_id_led_init(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error initializing identification LED\n");
-		return ret_val;
-	}
-
-	/* Disabling VLAN filtering */
-	hw_dbg(hw, "Initializing the IEEE VLAN\n");
-	e1000e_clear_vfta(hw);
-
-	/* Setup the receive address. */
-	/* If, however, a locally administered address was assigned to the
-	 * 82571, we must reserve a RAR for it to work around an issue where
-	 * resetting one port will reload the MAC on the other port.
-	 */
-	if (e1000e_get_laa_state_82571(hw))
-		rar_count--;
-	e1000e_init_rx_addrs(hw, rar_count);
-
-	/* Zero out the Multicast HASH table */
-	hw_dbg(hw, "Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/* Setup link and flow control */
-	ret_val = e1000_setup_link_82571(hw);
-
-	/* Set the transmit descriptor write-back policy */
-	reg_data = er32(TXDCTL);
-	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-		   E1000_TXDCTL_FULL_TX_DESC_WB |
-		   E1000_TXDCTL_COUNT_DESC;
-	ew32(TXDCTL, reg_data);
-
-	/* ...for both queues. */
-	if (mac->type != e1000_82573) {
-		reg_data = er32(TXDCTL1);
-		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-			   E1000_TXDCTL_FULL_TX_DESC_WB |
-			   E1000_TXDCTL_COUNT_DESC;
-		ew32(TXDCTL1, reg_data);
-	} else {
-		e1000e_enable_tx_pkt_filtering(hw);
-		reg_data = er32(GCR);
-		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
-		ew32(GCR, reg_data);
-	}
-
-	/* Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_82571(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
- *  @hw: pointer to the HW structure
- *
- *  Initializes required hardware-dependent bits needed for normal operation.
- **/
-static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
-{
-	u32 reg;
-
-	/* Transmit Descriptor Control 0 */
-	reg = er32(TXDCTL);
-	reg |= (1 << 22);
-	ew32(TXDCTL, reg);
-
-	/* Transmit Descriptor Control 1 */
-	reg = er32(TXDCTL1);
-	reg |= (1 << 22);
-	ew32(TXDCTL1, reg);
-
-	/* Transmit Arbitration Control 0 */
-	reg = er32(TARC0);
-	reg &= ~(0xF << 27); /* 30:27 */
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
-		break;
-	default:
-		break;
-	}
-	ew32(TARC0, reg);
-
-	/* Transmit Arbitration Control 1 */
-	reg = er32(TARC1);
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		reg &= ~((1 << 29) | (1 << 30));
-		reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
-		if (er32(TCTL) & E1000_TCTL_MULR)
-			reg &= ~(1 << 28);
-		else
-			reg |= (1 << 28);
-		ew32(TARC1, reg);
-		break;
-	default:
-		break;
-	}
-
-	/* Device Control */
-	if (hw->mac.type == e1000_82573) {
-		reg = er32(CTRL);
-		reg &= ~(1 << 29);
-		ew32(CTRL, reg);
-	}
-
-	/* Extended Device Control */
-	if (hw->mac.type == e1000_82573) {
-		reg = er32(CTRL_EXT);
-		reg &= ~(1 << 23);
-		reg |= (1 << 22);
-		ew32(CTRL_EXT, reg);
-	}
-}
-
-/**
- *  e1000e_clear_vfta - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-void e1000e_clear_vfta(struct e1000_hw *hw)
-{
-	u32 offset;
-	u32 vfta_value = 0;
-	u32 vfta_offset = 0;
-	u32 vfta_bit_in_reg = 0;
-
-	if (hw->mac.type == e1000_82573) {
-		if (hw->mng_cookie.vlan_id != 0) {
-			/* The VFTA is a 4096b bit-field, each identifying
-			 * a single VLAN ID.  The following operations
-			 * determine which 32b entry (i.e. offset) into the
-			 * array we want to set the VLAN ID (i.e. bit) of
-			 * the manageability unit.
-			 */
-			vfta_offset = (hw->mng_cookie.vlan_id >>
-				       E1000_VFTA_ENTRY_SHIFT) &
-				      E1000_VFTA_ENTRY_MASK;
-			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
-					       E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
-		}
-	}
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-		/* If the offset we want to clear is the same offset of the
-		 * manageability VLAN ID, then clear all bits except that of
-		 * the manageability unit.
-		 */
-		vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
-		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
-		e1e_flush();
-	}
-}
-
-/**
- *  e1000_mc_addr_list_update_82571 - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *  @rar_used_count: the first RAR register free to program
- *  @rar_count: total number of supported Receive Address Registers
- *
- *  Updates the Receive Address Registers and Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- *  The parameter rar_count will usually be hw->mac.rar_entry_count
- *  unless there are workarounds that change this.
- **/
-static void e1000_mc_addr_list_update_82571(struct e1000_hw *hw,
-					    u8 *mc_addr_list,
-					    u32 mc_addr_count,
-					    u32 rar_used_count,
-					    u32 rar_count)
-{
-	if (e1000e_get_laa_state_82571(hw))
-		rar_count--;
-
-	e1000e_mc_addr_list_update_generic(hw, mc_addr_list, mc_addr_count,
-					  rar_used_count, rar_count);
-}
-
-/**
- *  e1000_setup_link_82571 - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-static s32 e1000_setup_link_82571(struct e1000_hw *hw)
-{
-	/* 82573 does not have a word in the NVM to determine
-	 * the default flow control setting, so we explicitly
-	 * set it to full.
-	 */
-	if (hw->mac.type == e1000_82573)
-		hw->mac.fc = e1000_fc_full;
-
-	return e1000e_setup_link(hw);
-}
-
-/**
- *  e1000_setup_copper_link_82571 - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Configures the link for auto-neg or forced speed and duplex.  Then we check
- *  for link, once link is established calls to configure collision distance
- *  and flow control are called.
- **/
-static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	u32 led_ctrl;
-	s32 ret_val;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ew32(CTRL, ctrl);
-
-	switch (hw->phy.type) {
-	case e1000_phy_m88:
-		ret_val = e1000e_copper_link_setup_m88(hw);
-		break;
-	case e1000_phy_igp_2:
-		ret_val = e1000e_copper_link_setup_igp(hw);
-		/* Setup activity LED */
-		led_ctrl = er32(LEDCTL);
-		led_ctrl &= IGP_ACTIVITY_LED_MASK;
-		led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
-		ew32(LEDCTL, led_ctrl);
-		break;
-	default:
-		return -E1000_ERR_PHY;
-		break;
-	}
-
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000e_setup_copper_link(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber and serdes links.
- *  Upon successful setup, poll for link.
- **/
-static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
-{
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		/* If SerDes loopback mode is entered, there is no form
-		 * of reset to take the adapter out of that mode.  So we
-		 * have to explicitly take the adapter out of loopback
-		 * mode.  This prevents drivers from twidling their thumbs
-		 * if another tool failed to take it out of loopback mode.
-		 */
-		ew32(SCTL,
-				E1000_SCTL_DISABLE_SERDES_LOOPBACK);
-		break;
-	default:
-		break;
-	}
-
-	return e1000e_setup_fiber_serdes_link(hw);
-}
-
-/**
- *  e1000_valid_led_default_82571 - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-
-	if (hw->mac.type == e1000_82573 &&
-	    *data == ID_LED_RESERVED_F746)
-		*data = ID_LED_DEFAULT_82573;
-	else if (*data == ID_LED_RESERVED_0000 ||
-		 *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT;
-
-	return 0;
-}
-
-/**
- *  e1000e_get_laa_state_82571 - Get locally administered address state
- *  @hw: pointer to the HW structure
- *
- *  Retrieve and return the current locally administed address state.
- **/
-bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
-{
-	if (hw->mac.type != e1000_82571)
-		return 0;
-
-	return hw->dev_spec.e82571.laa_is_present;
-}
-
-/**
- *  e1000e_set_laa_state_82571 - Set locally administered address state
- *  @hw: pointer to the HW structure
- *  @state: enable/disable locally administered address
- *
- *  Enable/Disable the current locally administed address state.
- **/
-void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
-{
-	if (hw->mac.type != e1000_82571)
-		return;
-
-	hw->dev_spec.e82571.laa_is_present = state;
-
-	/* If workaround is activated... */
-	if (state)
-		/* Hold a copy of the LAA in RAR[14] This is done so that
-		 * between the time RAR[0] gets clobbered and the time it
-		 * gets fixed, the actual LAA is in one of the RARs and no
-		 * incoming packets directed to this port are dropped.
-		 * Eventually the LAA will be in RAR[0] and RAR[14].
-		 */
-		e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1);
-}
-
-/**
- *  e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Verifies that the EEPROM has completed the update.  After updating the
- *  EEPROM, we need to check bit 15 in work 0x23 for the checksum fix.  If
- *  the checksum fix is not implemented, we need to set the bit and update
- *  the checksum.  Otherwise, if bit 15 is set and the checksum is incorrect,
- *  we need to return bad checksum.
- **/
-static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
-	u16 data;
-
-	if (nvm->type != e1000_nvm_flash_hw)
-		return 0;
-
-	/* Check bit 4 of word 10h.  If it is 0, firmware is done updating
-	 * 10h-12h.  Checksum may need to be fixed.
-	 */
-	ret_val = e1000_read_nvm(hw, 0x10, 1, &data);
-	if (ret_val)
-		return ret_val;
-
-	if (!(data & 0x10)) {
-		/* Read 0x23 and check bit 15.  This bit is a 1
-		 * when the checksum has already been fixed.  If
-		 * the checksum is still wrong and this bit is a
-		 * 1, we need to return bad checksum.  Otherwise,
-		 * we need to set this bit to a 1 and update the
-		 * checksum.
-		 */
-		ret_val = e1000_read_nvm(hw, 0x23, 1, &data);
-		if (ret_val)
-			return ret_val;
-
-		if (!(data & 0x8000)) {
-			data |= 0x8000;
-			ret_val = e1000_write_nvm(hw, 0x23, 1, &data);
-			if (ret_val)
-				return ret_val;
-			ret_val = e1000e_update_nvm_checksum(hw);
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
-{
-	u32 temp;
-
-	e1000e_clear_hw_cntrs_base(hw);
-
-	temp = er32(PRC64);
-	temp = er32(PRC127);
-	temp = er32(PRC255);
-	temp = er32(PRC511);
-	temp = er32(PRC1023);
-	temp = er32(PRC1522);
-	temp = er32(PTC64);
-	temp = er32(PTC127);
-	temp = er32(PTC255);
-	temp = er32(PTC511);
-	temp = er32(PTC1023);
-	temp = er32(PTC1522);
-
-	temp = er32(ALGNERRC);
-	temp = er32(RXERRC);
-	temp = er32(TNCRS);
-	temp = er32(CEXTERR);
-	temp = er32(TSCTC);
-	temp = er32(TSCTFC);
-
-	temp = er32(MGTPRC);
-	temp = er32(MGTPDC);
-	temp = er32(MGTPTC);
-
-	temp = er32(IAC);
-	temp = er32(ICRXOC);
-
-	temp = er32(ICRXPTC);
-	temp = er32(ICRXATC);
-	temp = er32(ICTXPTC);
-	temp = er32(ICTXATC);
-	temp = er32(ICTXQEC);
-	temp = er32(ICTXQMTC);
-	temp = er32(ICRXDMTC);
-}
-
-static struct e1000_mac_operations e82571_mac_ops = {
-	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
-	/* .check_for_link: media type dependent */
-	.cleanup_led		= e1000e_cleanup_led_generic,
-	.clear_hw_cntrs		= e1000_clear_hw_cntrs_82571,
-	.get_bus_info		= e1000e_get_bus_info_pcie,
-	/* .get_link_up_info: media type dependent */
-	.led_on			= e1000e_led_on_generic,
-	.led_off		= e1000e_led_off_generic,
-	.mc_addr_list_update	= e1000_mc_addr_list_update_82571,
-	.reset_hw		= e1000_reset_hw_82571,
-	.init_hw		= e1000_init_hw_82571,
-	.setup_link		= e1000_setup_link_82571,
-	/* .setup_physical_interface: media type dependent */
-};
-
-static struct e1000_phy_operations e82_phy_ops_igp = {
-	.acquire_phy		= e1000_get_hw_semaphore_82571,
-	.check_reset_block	= e1000e_check_reset_block_generic,
-	.commit_phy		= NULL,
-	.force_speed_duplex	= e1000e_phy_force_speed_duplex_igp,
-	.get_cfg_done		= e1000_get_cfg_done_82571,
-	.get_cable_length	= e1000e_get_cable_length_igp_2,
-	.get_phy_info		= e1000e_get_phy_info_igp,
-	.read_phy_reg		= e1000e_read_phy_reg_igp,
-	.release_phy		= e1000_put_hw_semaphore_82571,
-	.reset_phy		= e1000e_phy_hw_reset_generic,
-	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
-	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
-	.write_phy_reg		= e1000e_write_phy_reg_igp,
-};
-
-static struct e1000_phy_operations e82_phy_ops_m88 = {
-	.acquire_phy		= e1000_get_hw_semaphore_82571,
-	.check_reset_block	= e1000e_check_reset_block_generic,
-	.commit_phy		= e1000e_phy_sw_reset,
-	.force_speed_duplex	= e1000e_phy_force_speed_duplex_m88,
-	.get_cfg_done		= e1000e_get_cfg_done,
-	.get_cable_length	= e1000e_get_cable_length_m88,
-	.get_phy_info		= e1000e_get_phy_info_m88,
-	.read_phy_reg		= e1000e_read_phy_reg_m88,
-	.release_phy		= e1000_put_hw_semaphore_82571,
-	.reset_phy		= e1000e_phy_hw_reset_generic,
-	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
-	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
-	.write_phy_reg		= e1000e_write_phy_reg_m88,
-};
-
-static struct e1000_nvm_operations e82571_nvm_ops = {
-	.acquire_nvm		= e1000_acquire_nvm_82571,
-	.read_nvm		= e1000e_read_nvm_spi,
-	.release_nvm		= e1000_release_nvm_82571,
-	.update_nvm		= e1000_update_nvm_checksum_82571,
-	.valid_led_default	= e1000_valid_led_default_82571,
-	.validate_nvm		= e1000_validate_nvm_checksum_82571,
-	.write_nvm		= e1000_write_nvm_82571,
-};
-
-static struct e1000_nvm_operations e82573_nvm_ops = {
-	.acquire_nvm		= e1000_acquire_nvm_82571,
-	.read_nvm		= e1000e_read_nvm_eerd,
-	.release_nvm		= e1000_release_nvm_82571,
-	.update_nvm		= e1000_update_nvm_checksum_82571,
-	.valid_led_default	= e1000_valid_led_default_82571,
-	.validate_nvm		= e1000_validate_nvm_checksum_82571,
-	.write_nvm		= e1000_write_nvm_82571,
-};
-
-struct e1000_info e1000_82571_info = {
-	.mac			= e1000_82571,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_STATS_PTC_PRC
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_STATS_ICR_ICT
-				  | FLAG_HAS_SMART_POWER_DOWN
-				  | FLAG_RESET_OVERWRITES_LAA /* errata */
-				  | FLAG_TARC_SPEED_MODE_BIT /* errata */
-				  | FLAG_APME_CHECK_PORT_B,
-	.pba			= 38,
-	.get_invariants		= e1000_get_invariants_82571,
-	.mac_ops		= &e82571_mac_ops,
-	.phy_ops		= &e82_phy_ops_igp,
-	.nvm_ops		= &e82571_nvm_ops,
-};
-
-struct e1000_info e1000_82572_info = {
-	.mac			= e1000_82572,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_STATS_PTC_PRC
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_STATS_ICR_ICT
-				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */
-	.pba			= 38,
-	.get_invariants		= e1000_get_invariants_82571,
-	.mac_ops		= &e82571_mac_ops,
-	.phy_ops		= &e82_phy_ops_igp,
-	.nvm_ops		= &e82571_nvm_ops,
-};
-
-struct e1000_info e1000_82573_info = {
-	.mac			= e1000_82573,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_STATS_PTC_PRC
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_STATS_ICR_ICT
-				  | FLAG_HAS_SMART_POWER_DOWN
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_ASPM
-				  | FLAG_HAS_ERT
-				  | FLAG_HAS_SWSM_ON_LOAD,
-	.pba			= 20,
-	.get_invariants		= e1000_get_invariants_82571,
-	.mac_ops		= &e82571_mac_ops,
-	.phy_ops		= &e82_phy_ops_m88,
-	.nvm_ops		= &e82573_nvm_ops,
-};
-
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/defines.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/defines.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/defines.h	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/defines.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,739 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#ifndef _E1000_DEFINES_H_
-#define _E1000_DEFINES_H_
-
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-
-/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
-#define REQ_TX_DESCRIPTOR_MULTIPLE  8
-#define REQ_RX_DESCRIPTOR_MULTIPLE  8
-
-/* Definitions for power management and wakeup registers */
-/* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-
-/* Wake Up Filter Control */
-#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
-#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
-#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
-#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
-#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
-
-/* Extended Device Control */
-#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
-#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
-#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
-#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
-#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
-#define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
-#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
-
-/* Receive Decriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-
-#define E1000_RXDEXT_STATERR_CE    0x01000000
-#define E1000_RXDEXT_STATERR_SE    0x02000000
-#define E1000_RXDEXT_STATERR_SEQ   0x04000000
-#define E1000_RXDEXT_STATERR_CXE   0x10000000
-#define E1000_RXDEXT_STATERR_RXE   0x80000000
-
-/* mask to determine if packets should be dropped due to frame errors */
-#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
-    E1000_RXD_ERR_CE  |                \
-    E1000_RXD_ERR_SE  |                \
-    E1000_RXD_ERR_SEQ |                \
-    E1000_RXD_ERR_CXE |                \
-    E1000_RXD_ERR_RXE)
-
-/* Same mask, but for extended and packet split descriptors */
-#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
-    E1000_RXDEXT_STATERR_CE  |            \
-    E1000_RXDEXT_STATERR_SE  |            \
-    E1000_RXDEXT_STATERR_SEQ |            \
-    E1000_RXDEXT_STATERR_CXE |            \
-    E1000_RXDEXT_STATERR_RXE)
-
-#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
-#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
-						    * filtering */
-#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
-					     * memory */
-
-/* Receive Control */
-#define E1000_RCTL_EN             0x00000002    /* enable */
-#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
-#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
-#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
-#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
-#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
-#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
-#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
-#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
-#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
-#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
-#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
-#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
-
-/* Use byte values for the following shift parameters
- * Usage:
- *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
- *                  E1000_PSRCTL_BSIZE0_MASK) |
- *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
- *                  E1000_PSRCTL_BSIZE1_MASK) |
- *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
- *                  E1000_PSRCTL_BSIZE2_MASK) |
- *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
- *                  E1000_PSRCTL_BSIZE3_MASK))
- * where value0 = [128..16256],  default=256
- *       value1 = [1024..64512], default=4096
- *       value2 = [0..64512],    default=4096
- *       value3 = [0..64512],    default=0
- */
-
-#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
-#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
-#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
-#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
-
-#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
-#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
-#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
-#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
-
-/* SWFW_SYNC Definitions */
-#define E1000_SWFW_EEP_SM   0x1
-#define E1000_SWFW_PHY0_SM  0x2
-#define E1000_SWFW_PHY1_SM  0x4
-
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
-#define E1000_STATUS_FUNC_SHIFT 2
-#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
-#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
-#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion by NVM */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
-
-/* Constants used to intrepret the masked PCI-X bus speed. */
-
-#define HALF_DUPLEX 1
-#define FULL_DUPLEX 2
-
-
-#define ADVERTISE_10_HALF                 0x0001
-#define ADVERTISE_10_FULL                 0x0002
-#define ADVERTISE_100_HALF                0x0004
-#define ADVERTISE_100_FULL                0x0008
-#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
-#define ADVERTISE_1000_FULL               0x0020
-
-/* 1000/H is not supported, nor spec-compliant. */
-#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-				ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
-						     ADVERTISE_1000_FULL)
-#define E1000_ALL_NOT_GIG      ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-				ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
-#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
-
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
-
-/* LED Control */
-#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
-#define E1000_LEDCTL_LED0_MODE_SHIFT      0
-#define E1000_LEDCTL_LED0_IVRT            0x00000040
-#define E1000_LEDCTL_LED0_BLINK           0x00000080
-
-#define E1000_LEDCTL_MODE_LED_ON        0xE
-#define E1000_LEDCTL_MODE_LED_OFF       0xF
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-
-/* Transmit Control */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
-
-/* Transmit Arbitration Count */
-
-/* SerDes Control */
-#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
-
-/* Receive Checksum Control */
-#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
-#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
-
-/* Header split receive */
-#define E1000_RFCTL_EXTEN               0x00008000
-#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
-#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
-
-/* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       15
-#define E1000_CT_SHIFT                  4
-#define E1000_COLLISION_DISTANCE        63
-#define E1000_COLD_SHIFT                12
-
-/* Default values for the transmit IPG register */
-#define DEFAULT_82543_TIPG_IPGT_COPPER 8
-
-#define E1000_TIPG_IPGT_MASK  0x000003FF
-
-#define DEFAULT_82543_TIPG_IPGR1 8
-#define E1000_TIPG_IPGR1_SHIFT  10
-
-#define DEFAULT_82543_TIPG_IPGR2 6
-#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
-#define E1000_TIPG_IPGR2_SHIFT  20
-
-#define MAX_JUMBO_FRAME_SIZE    0x3F00
-
-/* Extended Configuration Control and Size */
-#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
-#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
-#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
-
-#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
-#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
-#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
-#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
-
-#define E1000_KABGTXD_BGSQLBIAS           0x00050000
-
-/* PBA constants */
-#define E1000_PBA_8K  0x0008    /* 8KB, default Rx allocation */
-#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
-
-#define E1000_PBS_16K E1000_PBA_16K
-
-#define IFS_MAX       80
-#define IFS_MIN       40
-#define IFS_RATIO     4
-#define IFS_STEP      10
-#define MIN_NUM_XMITS 1000
-
-/* SW Semaphore Register */
-#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
-#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
-#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
-#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
-
-/* This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXT0   = Receiver Timer Interrupt (ring 0)
- *   o TXDW   = Transmit Descriptor Written Back
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- *   o LSC    = Link Status Change
- */
-#define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC)
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-
-/* Interrupt Cause Set */
-#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-
-/* Transmit Descriptor Control */
-#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
-#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
-#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
-#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
-#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
-					      still to be processed. */
-
-/* Flow Control Constants */
-#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
-#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
-#define FLOW_CONTROL_TYPE         0x8808
-
-/* 802.1q VLAN Packet Size */
-#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
-
-/* Receive Address */
-/* Number of high/low register pairs in the RAR. The RAR (Receive Address
- * Registers) holds the directed and multicast addresses that we monitor.
- * Technically, we have 16 spots.  However, we reserve one of these spots
- * (RAR[15]) for our directed address used by controllers with
- * manageability enabled, allowing us room for 15 multicast addresses.
- */
-#define E1000_RAR_ENTRIES     15
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-
-/* Error Codes */
-#define E1000_ERR_NVM      1
-#define E1000_ERR_PHY      2
-#define E1000_ERR_CONFIG   3
-#define E1000_ERR_PARAM    4
-#define E1000_ERR_MAC_INIT 5
-#define E1000_ERR_PHY_TYPE 6
-#define E1000_ERR_RESET   9
-#define E1000_ERR_MASTER_REQUESTS_PENDING 10
-#define E1000_ERR_HOST_INTERFACE_COMMAND 11
-#define E1000_BLK_PHY_RESET   12
-#define E1000_ERR_SWFW_SYNC 13
-#define E1000_NOT_IMPLEMENTED 14
-
-/* Loop limit on how long we wait for auto-negotiation to complete */
-#define FIBER_LINK_UP_LIMIT               50
-#define COPPER_LINK_UP_LIMIT              10
-#define PHY_AUTO_NEG_LIMIT                45
-#define PHY_FORCE_LIMIT                   20
-/* Number of 100 microseconds we wait for PCI Express master disable */
-#define MASTER_DISABLE_TIMEOUT      800
-/* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT             100
-/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
-#define MDIO_OWNERSHIP_TIMEOUT      10
-/* Number of milliseconds for NVM auto read done after MAC reset. */
-#define AUTO_READ_DONE_TIMEOUT      10
-
-/* Flow Control */
-#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
-
-/* Transmit Configuration Word */
-#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
-#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
-#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
-#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
-#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
-
-/* Receive Configuration Word */
-#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
-#define E1000_RXCW_C          0x20000000        /* Receive config */
-#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
-
-/* PCI Express Control */
-#define E1000_GCR_RXD_NO_SNOOP          0x00000001
-#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
-#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
-#define E1000_GCR_TXD_NO_SNOOP          0x00000008
-#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
-#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
-
-#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
-			   E1000_GCR_RXDSCW_NO_SNOOP      | \
-			   E1000_GCR_RXDSCR_NO_SNOOP      | \
-			   E1000_GCR_TXD_NO_SNOOP         | \
-			   E1000_GCR_TXDSCW_NO_SNOOP      | \
-			   E1000_GCR_TXDSCR_NO_SNOOP)
-
-/* PHY Control Register */
-#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
-#define MII_CR_POWER_DOWN       0x0800  /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
-#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
-#define MII_CR_SPEED_1000       0x0040
-#define MII_CR_SPEED_100        0x2000
-#define MII_CR_SPEED_10         0x0000
-
-/* PHY Status Register */
-#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
-#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
-#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
-
-/* Autoneg Expansion Register */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
-					/* 0=DTE device */
-#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
-					/* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
-					/* 0=Automatic Master/Slave config */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
-
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CONTROL      0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Regiser */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-
-/* NVM Control */
-#define E1000_EECD_SK        0x00000001 /* NVM Clock */
-#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* NVM Data In */
-#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
-#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
-#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
-#define E1000_EECD_ADDR_BITS 0x00000400 /* NVM Addressing bits based on type
-					 * (0-small, 1-large) */
-#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
-#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
-#define E1000_EECD_SIZE_EX_SHIFT     11
-#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-
-#define E1000_NVM_RW_REG_DATA   16   /* Offset to data in NVM read/write registers */
-#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
-#define E1000_NVM_RW_REG_START  1    /* Start operation */
-#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
-#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
-#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
-#define E1000_FLASH_UPDATES  2000
-
-/* NVM Word Offsets */
-#define NVM_ID_LED_SETTINGS        0x0004
-#define NVM_INIT_CONTROL2_REG      0x000F
-#define NVM_INIT_CONTROL3_PORT_B   0x0014
-#define NVM_INIT_3GIO_3            0x001A
-#define NVM_INIT_CONTROL3_PORT_A   0x0024
-#define NVM_CFG                    0x0012
-#define NVM_CHECKSUM_REG           0x003F
-
-#define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
-#define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
-
-/* Mask bits for fields in Word 0x0f of the NVM */
-#define NVM_WORD0F_PAUSE_MASK       0x3000
-#define NVM_WORD0F_PAUSE            0x1000
-#define NVM_WORD0F_ASM_DIR          0x2000
-
-/* Mask bits for fields in Word 0x1a of the NVM */
-#define NVM_WORD1A_ASPM_MASK  0x000C
-
-/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
-#define NVM_SUM                    0xBABA
-
-/* PBA (printed board assembly) number words */
-#define NVM_PBA_OFFSET_0           8
-#define NVM_PBA_OFFSET_1           9
-
-#define NVM_WORD_SIZE_BASE_SHIFT   6
-
-/* NVM Commands - SPI */
-#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
-#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
-#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
-#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
-#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
-#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
-
-/* SPI NVM Status Register */
-#define NVM_STATUS_RDY_SPI         0x01
-
-/* Word definitions for ID LED Settings */
-#define ID_LED_RESERVED_0000 0x0000
-#define ID_LED_RESERVED_FFFF 0xFFFF
-#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
-			      (ID_LED_OFF1_OFF2 <<  8) | \
-			      (ID_LED_DEF1_DEF2 <<  4) | \
-			      (ID_LED_DEF1_DEF2))
-#define ID_LED_DEF1_DEF2     0x1
-#define ID_LED_DEF1_ON2      0x2
-#define ID_LED_DEF1_OFF2     0x3
-#define ID_LED_ON1_DEF2      0x4
-#define ID_LED_ON1_ON2       0x5
-#define ID_LED_ON1_OFF2      0x6
-#define ID_LED_OFF1_DEF2     0x7
-#define ID_LED_OFF1_ON2      0x8
-#define ID_LED_OFF1_OFF2     0x9
-
-#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
-#define IGP_ACTIVITY_LED_ENABLE 0x0300
-#define IGP_LED3_MODE           0x07000000
-
-/* PCI/PCI-X/PCI-EX Config space */
-#define PCI_HEADER_TYPE_REGISTER     0x0E
-#define PCIE_LINK_STATUS             0x12
-
-#define PCI_HEADER_TYPE_MULTIFUNC    0x80
-#define PCIE_LINK_WIDTH_MASK         0x3F0
-#define PCIE_LINK_WIDTH_SHIFT        4
-
-#define PHY_REVISION_MASK      0xFFFFFFF0
-#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG 0xF
-
-/* Bit definitions for valid PHY IDs. */
-/* I = Integrated
- * E = External
- */
-#define M88E1000_E_PHY_ID    0x01410C50
-#define M88E1000_I_PHY_ID    0x01410C30
-#define M88E1011_I_PHY_ID    0x01410C20
-#define IGP01E1000_I_PHY_ID  0x02A80380
-#define M88E1111_I_PHY_ID    0x01410CC0
-#define GG82563_E_PHY_ID     0x01410CA0
-#define IGP03E1000_E_PHY_ID  0x02A80390
-#define IFE_E_PHY_ID         0x02A80330
-#define IFE_PLUS_E_PHY_ID    0x02A80320
-#define IFE_C_E_PHY_ID       0x02A80310
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
-
-#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
-#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
-#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
-					       /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
-#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
-						*  100BASE-TX/10BASE-T:
-						*  MDI Mode
-						*/
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled
-						* all speeds.
-						*/
-					/* 1=Enable Extended 10BASE-T distance
-					 * (Lower 10BASE-T RX Threshold)
-					 * 0=Normal 10BASE-T RX Threshold */
-					/* 1=5-Bit interface in 100BASE-TX
-					 * 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
-#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
-#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
-					    * 3=110-140M;4=>140M */
-#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* Number of times we will attempt to autonegotiate before downshifting if we
- * are the master */
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
-/* Number of times we will attempt to autonegotiate before downshifting if we
- * are the slave */
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
-#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
-
-/* M88EC018 Rev 2 specific DownShift settings */
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
-
-/* Bits...
- * 15-5: page
- * 4-0: register offset
- */
-#define GG82563_PAGE_SHIFT        5
-#define GG82563_REG(page, reg)    \
-	(((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
-#define GG82563_MIN_ALT_REG       30
-
-/* GG82563 Specific Registers */
-#define GG82563_PHY_SPEC_CTRL           \
-	GG82563_REG(0, 16) /* PHY Specific Control */
-#define GG82563_PHY_PAGE_SELECT         \
-	GG82563_REG(0, 22) /* Page Select */
-#define GG82563_PHY_SPEC_CTRL_2         \
-	GG82563_REG(0, 26) /* PHY Specific Control 2 */
-#define GG82563_PHY_PAGE_SELECT_ALT     \
-	GG82563_REG(0, 29) /* Alternate Page Select */
-
-#define GG82563_PHY_MAC_SPEC_CTRL       \
-	GG82563_REG(2, 21) /* MAC Specific Control Register */
-
-#define GG82563_PHY_DSP_DISTANCE    \
-	GG82563_REG(5, 26) /* DSP Distance */
-
-/* Page 193 - Port Control Registers */
-#define GG82563_PHY_KMRN_MODE_CTRL   \
-	GG82563_REG(193, 16) /* Kumeran Mode Control */
-#define GG82563_PHY_PWR_MGMT_CTRL       \
-	GG82563_REG(193, 20) /* Power Management Control */
-
-/* Page 194 - KMRN Registers */
-#define GG82563_PHY_INBAND_CTRL         \
-	GG82563_REG(194, 18) /* Inband Control */
-
-/* MDI Control */
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* SerDes Control */
-#define E1000_GEN_POLL_TIMEOUT          640
-
-#endif /* _E1000_DEFINES_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_80003es2lan.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_80003es2lan.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_80003es2lan.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_80003es2lan.c	2008-06-23 18:27:32.000000000 +0200
@@ -0,0 +1,1419 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_80003es2lan
+ */
+
+#include "e1000_hw.h"
+
+static s32  e1000_init_phy_params_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_acquire_phy_80003es2lan(struct e1000_hw *hw);
+static void e1000_release_phy_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw);
+static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                   u32 offset,
+                                                   u16 *data);
+static s32  e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                    u32 offset,
+                                                    u16 data);
+static s32  e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+                                        u16 words, u16 *data);
+static s32  e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_get_cable_length_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex);
+static s32  e1000_reset_hw_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_init_hw_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static s32  e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
+static s32  e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static s32  e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static s32  e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw);
+static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
+
+/*
+ * A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const u16 e1000_gg82563_cable_length_table[] =
+         { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+#define GG82563_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_gg82563_cable_length_table) / \
+                 sizeof(e1000_gg82563_cable_length_table[0]))
+
+/**
+ *  e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_phy_params_80003es2lan");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type        = e1000_phy_none;
+		goto out;
+	} else {
+		phy->ops.power_up = e1000_power_up_phy_copper;
+		phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan;
+	}
+
+	phy->addr                = 1;
+	phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us      = 100;
+	phy->type                = e1000_phy_gg82563;
+
+	phy->ops.acquire            = e1000_acquire_phy_80003es2lan;
+	phy->ops.check_polarity     = e1000_check_polarity_m88;
+	phy->ops.check_reset_block  = e1000_check_reset_block_generic;
+	phy->ops.commit             = e1000_phy_sw_reset_generic;
+	phy->ops.get_cfg_done       = e1000_get_cfg_done_80003es2lan;
+	phy->ops.get_info           = e1000_get_phy_info_m88;
+	phy->ops.release            = e1000_release_phy_80003es2lan;
+	phy->ops.reset              = e1000_phy_hw_reset_generic;
+	phy->ops.set_d3_lplu_state  = e1000_set_d3_lplu_state_generic;
+
+	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan;
+	phy->ops.get_cable_length   = e1000_get_cable_length_80003es2lan;
+	phy->ops.read_reg           = e1000_read_phy_reg_gg82563_80003es2lan;
+	phy->ops.write_reg          = e1000_write_phy_reg_gg82563_80003es2lan;
+
+	/* This can only be done after all function pointers are setup. */
+	ret_val = e1000_get_phy_id(hw);
+
+	/* Verify phy id */
+	if (phy->id != GG82563_E_PHY_ID) {
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u16 size;
+
+	DEBUGFUNC("e1000_init_nvm_params_80003es2lan");
+
+	nvm->opcode_bits        = 8;
+	nvm->delay_usec         = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size    = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size    = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	nvm->type               = e1000_nvm_eeprom_spi;
+
+	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+	                  E1000_EECD_SIZE_EX_SHIFT);
+
+	/*
+	 * Added to a constant, "size" becomes the left-shift value
+	 * for setting word_size.
+	 */
+	size += NVM_WORD_SIZE_BASE_SHIFT;
+
+	/* EEPROM access above 16k is unsupported */
+	if (size > 14)
+		size = 14;
+	nvm->word_size	= 1 << size;
+
+	/* Function Pointers */
+	nvm->ops.acquire           = e1000_acquire_nvm_80003es2lan;
+	nvm->ops.read              = e1000_read_nvm_eerd;
+	nvm->ops.release           = e1000_release_nvm_80003es2lan;
+	nvm->ops.update            = e1000_update_nvm_checksum_generic;
+	nvm->ops.valid_led_default = e1000_valid_led_default_generic;
+	nvm->ops.validate          = e1000_validate_nvm_checksum_generic;
+	nvm->ops.write             = e1000_write_nvm_80003es2lan;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_mac_params_80003es2lan");
+
+	/* Set media type */
+	switch (hw->device_id) {
+	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->phy.media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+	        (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+	                ? true : false;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_80003es2lan;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_80003es2lan;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_generic;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_setup_copper_link_80003es2lan
+	                : e1000_setup_fiber_serdes_link_generic;
+	/* check for link */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+		break;
+	case e1000_media_type_fiber:
+		mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
+		break;
+	case e1000_media_type_internal_serdes:
+		mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
+		break;
+	default:
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+	/* check management mode */
+	mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000_clear_vfta_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000_read_mac_addr_80003es2lan;
+	/* blink LED */
+	mac->ops.blink_led = e1000_blink_led_generic;
+	/* setup LED */
+	mac->ops.setup_led = e1000_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000_cleanup_led_generic;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000_led_on_generic;
+	mac->ops.led_off = e1000_led_off_generic;
+	/* remove device */
+	mac->ops.remove_device = e1000_remove_device_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan;
+	/* link info */
+	mac->ops.get_link_up_info = e1000_get_link_up_info_80003es2lan;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_function_pointers_80003es2lan - Init ESB2 func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  The only function explicitly called by the api module to initialize
+ *  all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_80003es2lan");
+
+	e1000_init_mac_ops_generic(hw);
+	e1000_init_nvm_ops_generic(hw);
+	hw->mac.ops.init_params = e1000_init_mac_params_80003es2lan;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_80003es2lan;
+	hw->phy.ops.init_params = e1000_init_phy_params_80003es2lan;
+}
+
+/**
+ *  e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to acquire access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	DEBUGFUNC("e1000_acquire_phy_80003es2lan");
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+	mask |= E1000_SWFW_CSR_SM;
+
+	return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000_release_phy_80003es2lan - Release rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to release access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	DEBUGFUNC("e1000_release_phy_80003es2lan");
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+	mask |= E1000_SWFW_CSR_SM;
+
+	e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the semaphore to access the EEPROM.  This is a function
+ *  pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_acquire_nvm_80003es2lan");
+
+	ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_acquire_nvm_generic(hw);
+
+	if (ret_val)
+		e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  Release the semaphore used to access the EEPROM.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_release_nvm_80003es2lan");
+
+	e1000_release_nvm_generic(hw);
+	e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 ret_val = E1000_SUCCESS;
+	s32 i = 0, timeout = 200;
+
+	DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan");
+
+	while (i < timeout) {
+		if (e1000_get_hw_semaphore_generic(hw)) {
+			ret_val = -E1000_ERR_SWFW_SYNC;
+			goto out;
+		}
+
+		swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		/*
+		 * Firmware currently using resource (fwmask)
+		 * or other software thread using resource (swmask)
+		 */
+		e1000_put_hw_semaphore_generic(hw);
+		msec_delay_irq(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -E1000_ERR_SWFW_SYNC;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+	e1000_put_hw_semaphore_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	DEBUGFUNC("e1000_release_swfw_sync_80003es2lan");
+
+	while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS);
+	/* Empty */
+
+	swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+
+	e1000_put_hw_semaphore_generic(hw);
+}
+
+/**
+ *  e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @data: pointer to the data returned from the operation
+ *
+ *  Read the GG82563 PHY register.  This is a function pointer entry
+ *  point called by the api module.
+ **/
+static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                  u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u32 page_select;
+	u16 temp;
+
+	DEBUGFUNC("e1000_read_phy_reg_gg82563_80003es2lan");
+
+	ret_val = e1000_acquire_phy_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	/* Select Configuration Page */
+	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+		page_select = GG82563_PHY_PAGE_SELECT;
+	} else {
+		/*
+		 * Use Alternative Page Select register to access
+		 * registers 30 and 31
+		 */
+		page_select = GG82563_PHY_PAGE_SELECT_ALT;
+	}
+
+	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+	ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
+	if (ret_val) {
+		e1000_release_phy_80003es2lan(hw);
+		goto out;
+	}
+
+	/*
+	 * The "ready" bit in the MDIC register may be incorrectly set
+	 * before the device has completed the "Page Select" MDI
+	 * transaction.  So we wait 200us after each MDI command...
+	 */
+	usec_delay(200);
+
+	/* ...and verify the command was successful. */
+	ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+
+	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+		ret_val = -E1000_ERR_PHY;
+		e1000_release_phy_80003es2lan(hw);
+		goto out;
+	}
+
+	usec_delay(200);
+
+	ret_val = e1000_read_phy_reg_mdic(hw,
+	                                 MAX_PHY_REG_ADDRESS & offset,
+	                                 data);
+
+	usec_delay(200);
+	e1000_release_phy_80003es2lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @data: value to write to the register
+ *
+ *  Write to the GG82563 PHY register.  This is a function pointer entry
+ *  point called by the api module.
+ **/
+static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+                                                   u32 offset, u16 data)
+{
+	s32 ret_val;
+	u32 page_select;
+	u16 temp;
+
+	DEBUGFUNC("e1000_write_phy_reg_gg82563_80003es2lan");
+
+	ret_val = e1000_acquire_phy_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	/* Select Configuration Page */
+	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
+		page_select = GG82563_PHY_PAGE_SELECT;
+	} else {
+		/*
+		 * Use Alternative Page Select register to access
+		 * registers 30 and 31
+		 */
+		page_select = GG82563_PHY_PAGE_SELECT_ALT;
+	}
+
+	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+	ret_val = e1000_write_phy_reg_mdic(hw, page_select, temp);
+	if (ret_val) {
+		e1000_release_phy_80003es2lan(hw);
+		goto out;
+	}
+
+
+	/*
+	 * The "ready" bit in the MDIC register may be incorrectly set
+	 * before the device has completed the "Page Select" MDI
+	 * transaction.  So we wait 200us after each MDI command...
+	 */
+	usec_delay(200);
+
+	/* ...and verify the command was successful. */
+	ret_val = e1000_read_phy_reg_mdic(hw, page_select, &temp);
+
+	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+		ret_val = -E1000_ERR_PHY;
+		e1000_release_phy_80003es2lan(hw);
+		goto out;
+	}
+
+	usec_delay(200);
+
+	ret_val = e1000_write_phy_reg_mdic(hw,
+	                                  MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	usec_delay(200);
+	e1000_release_phy_80003es2lan(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_80003es2lan - Write to ESB2 NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @words: number of words to write
+ *  @data: buffer of data to write to the NVM
+ *
+ *  Write "words" of data to the ESB2 NVM.  This is a function
+ *  pointer entry point called by the api module.
+ **/
+static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+                            u16 words, u16 *data)
+{
+	DEBUGFUNC("e1000_write_nvm_80003es2lan");
+
+	return e1000_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ *  e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
+ *  @hw: pointer to the HW structure
+ *
+ *  Wait a specific amount of time for manageability processes to complete.
+ *  This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+	DEBUGFUNC("e1000_get_cfg_done_80003es2lan");
+
+	if (hw->bus.func == 1)
+		mask = E1000_NVM_CFG_DONE_PORT_1;
+
+	while (timeout) {
+		if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
+			break;
+		msec_delay(1);
+		timeout--;
+	}
+	if (!timeout) {
+		DEBUGOUT("MNG configuration cycle has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the speed and duplex settings onto the PHY.  This is a
+ *  function pointer entry point called by the phy module.
+ **/
+static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_80003es2lan");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+	ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("GG82563 PSCR: %X\n", phy_data);
+
+	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	/* Reset the phy to commit changes. */
+	phy_data |= MII_CR_RESET;
+
+	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	usec_delay(1);
+
+	if (hw->phy.autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link "
+		         "on GG82563 phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = e1000_phy_reset_dsp_generic(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+		                                     100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to verify the TX_CLK corresponds
+	 * to the link speed.  10Mbps -> 2.5MHz, else 25MHz.
+	 */
+	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+	if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+	else
+		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+	ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_80003es2lan - Set approximate cable length
+ *  @hw: pointer to the HW structure
+ *
+ *  Find the approximate cable length as measured by the GG82563 PHY.
+ *  This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data, index;
+
+	DEBUGFUNC("e1000_get_cable_length_80003es2lan");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+	phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+	phy->max_cable_length = e1000_gg82563_cable_length_table[index+5];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_link_up_info_80003es2lan - Report speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to speed buffer
+ *  @duplex: pointer to duplex buffer
+ *
+ *  Retrieve the current speed and duplex configuration.
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_get_link_up_info_80003es2lan");
+
+	if (hw->phy.media_type == e1000_media_type_copper) {
+		ret_val = e1000_get_speed_and_duplex_copper_generic(hw,
+		                                                    speed,
+		                                                    duplex);
+		if (ret_val)
+			goto out;
+		if (*speed == SPEED_1000)
+			ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+		else
+			ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw,
+			                                      *duplex);
+	} else {
+		ret_val = e1000_get_speed_and_duplex_fiber_serdes_generic(hw,
+		                                                  speed,
+		                                                  duplex);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_hw_80003es2lan - Reset the ESB2 controller
+ *  @hw: pointer to the HW structure
+ *
+ *  Perform a global reset to the ESB2 controller.
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+	u32 ctrl, icr;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_reset_hw_80003es2lan");
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000_disable_pcie_master_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("PCI-E Master disable polling has failed.\n");
+	}
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	msec_delay(10);
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGOUT("Issuing a global reset to MAC\n");
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	ret_val = e1000_get_auto_rd_done_generic(hw);
+	if (ret_val)
+		/* We don't want to continue accessing MAC registers. */
+		goto out;
+
+	/* Clear any pending interrupt events. */
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	icr = E1000_READ_REG(hw, E1000_ICR);
+
+	e1000_check_alt_mac_addr_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_80003es2lan - Initialize the ESB2 controller
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg_data;
+	s32 ret_val;
+	u16 i;
+
+	DEBUGFUNC("e1000_init_hw_80003es2lan");
+
+	e1000_initialize_hw_bits_80003es2lan(hw);
+
+	/* Initialize identification LED */
+	ret_val = e1000_id_led_init_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	DEBUGOUT("Initializing the IEEE VLAN\n");
+	mac->ops.clear_vfta(hw);
+
+	/* Setup the receive address. */
+	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy */
+	reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+	           E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
+
+	/* ...for both queues. */
+	reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+	           E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
+
+	/* Enable retransmit on late collisions */
+	reg_data = E1000_READ_REG(hw, E1000_TCTL);
+	reg_data |= E1000_TCTL_RTLC;
+	E1000_WRITE_REG(hw, E1000_TCTL, reg_data);
+
+	/* Configure Gigabit Carry Extend Padding */
+	reg_data = E1000_READ_REG(hw, E1000_TCTL_EXT);
+	reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+	reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+	E1000_WRITE_REG(hw, E1000_TCTL_EXT, reg_data);
+
+	/* Configure Transmit Inter-Packet Gap */
+	reg_data = E1000_READ_REG(hw, E1000_TIPG);
+	reg_data &= ~E1000_TIPG_IPGT_MASK;
+	reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+	E1000_WRITE_REG(hw, E1000_TIPG, reg_data);
+
+	reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+	reg_data &= ~0x00100000;
+	E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_80003es2lan(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	DEBUGFUNC("e1000_initialize_hw_bits_80003es2lan");
+
+	if (hw->mac.disable_hw_init_bits)
+		goto out;
+
+	/* Transmit Descriptor Control 0 */
+	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = E1000_READ_REG(hw, E1000_TARC(0));
+	reg &= ~(0xF << 27); /* 30:27 */
+	if (hw->phy.media_type != e1000_media_type_copper)
+		reg &= ~(1 << 20);
+	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = E1000_READ_REG(hw, E1000_TARC(1));
+	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+		reg &= ~(1 << 28);
+	else
+		reg |= (1 << 28);
+	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+
+out:
+	return;
+}
+
+/**
+ *  e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ *  @hw: pointer to the HW structure
+ *
+ *  Setup some GG82563 PHY registers for obtaining link
+ **/
+static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u32 ctrl_ext;
+	u32 i = 0;
+	u16 data, data2;
+
+	DEBUGFUNC("e1000_copper_link_setup_gg82563_80003es2lan");
+
+	if (!phy->reset_disable) {
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+		                             &data);
+		if (ret_val)
+			goto out;
+
+		data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+		/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+		data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+		ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
+		                              data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Options:
+		 *   MDI/MDI-X = 0 (default)
+		 *   0 - Auto for all speeds
+		 *   1 - MDI mode
+		 *   2 - MDI-X mode
+		 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+		switch (phy->mdix) {
+		case 1:
+			data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+			break;
+		case 2:
+			data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+			break;
+		case 0:
+		default:
+			data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+			break;
+		}
+
+		/*
+		 * Options:
+		 *   disable_polarity_correction = 0 (default)
+		 *       Automatic Correction for Reversed Cable Polarity
+		 *   0 - Disabled
+		 *   1 - Enabled
+		 */
+		data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+		if (phy->disable_polarity_correction)
+			data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+		ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL, data);
+		if (ret_val)
+			goto out;
+
+		/* SW Reset the PHY so all changes take effect */
+		ret_val = hw->phy.ops.commit(hw);
+		if (ret_val) {
+			DEBUGOUT("Error Resetting the PHY\n");
+			goto out;
+		}
+
+	}
+
+	/* Bypass Rx and Tx FIFO's */
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                        E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+	                        E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+	                                E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_read_kmrn_reg_generic(hw,
+	                              E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+	                              &data);
+	if (ret_val)
+		goto out;
+	data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
+	                               data);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+	ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_SPEC_CTRL_2, data);
+	if (ret_val)
+		goto out;
+
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+	ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Do not init these registers when the HW is in IAMT mode, since the
+	 * firmware will have already initialized them.  We only initialize
+	 * them if the HW is not in IAMT mode.
+	 */
+	if (!(hw->mac.ops.check_mng_mode(hw))) {
+		/* Enable Electrical Idle on the PHY */
+		data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+		ret_val = hw->phy.ops.write_reg(hw,
+		                             GG82563_PHY_PWR_MGMT_CTRL,
+		                             data);
+		if (ret_val)
+			goto out;
+
+		do {
+			ret_val = hw->phy.ops.read_reg(hw,
+			                          GG82563_PHY_KMRN_MODE_CTRL,
+			                          &data);
+			if (ret_val)
+				goto out;
+
+			ret_val = hw->phy.ops.read_reg(hw,
+			                          GG82563_PHY_KMRN_MODE_CTRL,
+			                          &data2);
+			if (ret_val)
+				goto out;
+			i++;
+		} while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+		ret_val = hw->phy.ops.write_reg(hw,
+		                             GG82563_PHY_KMRN_MODE_CTRL,
+		                             data);
+
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Workaround: Disable padding in Kumeran interface in the MAC
+	 * and in the PHY to avoid CRC errors.
+	 */
+	ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_INBAND_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data |= GG82563_ICR_DIS_PADDING;
+	ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_INBAND_CTRL, data);
+	if (ret_val)
+		goto out;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ *  @hw: pointer to the HW structure
+ *
+ *  Essentially a wrapper for setting up all things "copper" related.
+ *  This is a function pointer entry point called by the mac module.
+ **/
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32  ret_val;
+	u16 reg_data;
+
+	DEBUGFUNC("e1000_setup_copper_link_80003es2lan");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	/*
+	 * Set the mac to wait the maximum time between each
+	 * iteration and increase the max iterations when
+	 * polling the phy; this fixes erroneous timeouts at 10Mbps.
+	 */
+	ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4),
+	                                       0xFFFF);
+	if (ret_val)
+		goto out;
+	ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9),
+	                                      &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= 0x3F;
+	ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9),
+	                                       reg_data);
+	if (ret_val)
+		goto out;
+	ret_val = e1000_read_kmrn_reg_generic(hw,
+	                              E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+	                              &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+	                               reg_data);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ *  @hw: pointer to the HW structure
+ *  @duplex: current duplex setting
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  10/100 operation.
+ **/
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 tipg;
+	u32 i = 0;
+	u16 reg_data, reg_data2;
+
+	DEBUGFUNC("e1000_configure_kmrn_for_10_100");
+
+	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+	                               reg_data);
+	if (ret_val)
+		goto out;
+
+	/* Configure Transmit Inter-Packet Gap */
+	tipg = E1000_READ_REG(hw, E1000_TIPG);
+	tipg &= ~E1000_TIPG_IPGT_MASK;
+	tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+	E1000_WRITE_REG(hw, E1000_TIPG, tipg);
+
+
+	do {
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                             &reg_data);
+		if (ret_val)
+			goto out;
+
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                             &reg_data2);
+		if (ret_val)
+			goto out;
+		i++;
+	} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+	if (duplex == HALF_DUPLEX)
+		reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+	else
+		reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+	ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  gigabit operation.
+ **/
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 reg_data, reg_data2;
+	u32 tipg;
+	u32 i = 0;
+
+	DEBUGFUNC("e1000_configure_kmrn_for_1000");
+
+	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+	                               reg_data);
+	if (ret_val)
+		goto out;
+
+	/* Configure Transmit Inter-Packet Gap */
+	tipg = E1000_READ_REG(hw, E1000_TIPG);
+	tipg &= ~E1000_TIPG_IPGT_MASK;
+	tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+	E1000_WRITE_REG(hw, E1000_TIPG, tipg);
+
+
+	do {
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                             &reg_data);
+		if (ret_val)
+			goto out;
+
+		ret_val = hw->phy.ops.read_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+		                             &reg_data2);
+		if (ret_val)
+			goto out;
+		i++;
+	} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
+
+	reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+	ret_val = hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_mac_addr_80003es2lan - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_mac_addr_80003es2lan");
+	if (e1000_check_alt_mac_addr_generic(hw))
+		ret_val = e1000_read_mac_addr_generic(hw);
+
+	return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw)
+{
+	/* If the management interface is not enabled, then power down */
+	if (!(hw->mac.ops.check_mng_mode(hw) ||
+	      hw->phy.ops.check_reset_block(hw)))
+		e1000_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
+{
+	volatile u32 temp;
+
+	DEBUGFUNC("e1000_clear_hw_cntrs_80003es2lan");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+
+	temp = E1000_READ_REG(hw, E1000_PRC64);
+	temp = E1000_READ_REG(hw, E1000_PRC127);
+	temp = E1000_READ_REG(hw, E1000_PRC255);
+	temp = E1000_READ_REG(hw, E1000_PRC511);
+	temp = E1000_READ_REG(hw, E1000_PRC1023);
+	temp = E1000_READ_REG(hw, E1000_PRC1522);
+	temp = E1000_READ_REG(hw, E1000_PTC64);
+	temp = E1000_READ_REG(hw, E1000_PTC127);
+	temp = E1000_READ_REG(hw, E1000_PTC255);
+	temp = E1000_READ_REG(hw, E1000_PTC511);
+	temp = E1000_READ_REG(hw, E1000_PTC1023);
+	temp = E1000_READ_REG(hw, E1000_PTC1522);
+
+	temp = E1000_READ_REG(hw, E1000_ALGNERRC);
+	temp = E1000_READ_REG(hw, E1000_RXERRC);
+	temp = E1000_READ_REG(hw, E1000_TNCRS);
+	temp = E1000_READ_REG(hw, E1000_CEXTERR);
+	temp = E1000_READ_REG(hw, E1000_TSCTC);
+	temp = E1000_READ_REG(hw, E1000_TSCTFC);
+
+	temp = E1000_READ_REG(hw, E1000_MGTPRC);
+	temp = E1000_READ_REG(hw, E1000_MGTPDC);
+	temp = E1000_READ_REG(hw, E1000_MGTPTC);
+
+	temp = E1000_READ_REG(hw, E1000_IAC);
+	temp = E1000_READ_REG(hw, E1000_ICRXOC);
+
+	temp = E1000_READ_REG(hw, E1000_ICRXPTC);
+	temp = E1000_READ_REG(hw, E1000_ICRXATC);
+	temp = E1000_READ_REG(hw, E1000_ICTXPTC);
+	temp = E1000_READ_REG(hw, E1000_ICTXATC);
+	temp = E1000_READ_REG(hw, E1000_ICTXQEC);
+	temp = E1000_READ_REG(hw, E1000_ICTXQMTC);
+	temp = E1000_READ_REG(hw, E1000_ICRXDMTC);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_80003es2lan.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_80003es2lan.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_80003es2lan.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_80003es2lan.h	2008-06-23 18:27:32.000000000 +0200
@@ -0,0 +1,95 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_80003ES2LAN_H_
+#define _E1000_80003ES2LAN_H_
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL       0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL        0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL         0x10
+#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE  0x1F
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS    0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS    0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING   0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT   0x0000
+#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE          0x2000
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN        0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN       0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN     0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE  0x0002 /* 1=Reversal Disabled */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK        0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI         0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX        0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO        0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG          0x2000
+                                               /* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK                0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5          0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25          0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_2_5        0x0006
+#define GG82563_MSCR_TX_CLK_1000MBPS_25         0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX           0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-100M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define GG82563_DSPD_CABLE_LENGTH               0x0007
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER         0x0800
+
+/* Max number of times Kumeran read/write should be validated */
+#define GG82563_MAX_KMRN_RETRY                  0x5
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE     0x0001
+                                          /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING                 0x0010 /* Disable Padding */
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_82571.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_82571.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_82571.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_82571.c	2008-06-23 18:27:32.000000000 +0200
@@ -0,0 +1,1538 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_82571
+ * e1000_82572
+ * e1000_82573
+ * e1000_82574
+ */
+
+#include "e1000_hw.h"
+
+static s32  e1000_init_phy_params_82571(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_82571(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_82571(struct e1000_hw *hw);
+static s32  e1000_acquire_nvm_82571(struct e1000_hw *hw);
+static void e1000_release_nvm_82571(struct e1000_hw *hw);
+static s32  e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset,
+                                  u16 words, u16 *data);
+static s32  e1000_update_nvm_checksum_82571(struct e1000_hw *hw);
+static s32  e1000_validate_nvm_checksum_82571(struct e1000_hw *hw);
+static s32  e1000_get_cfg_done_82571(struct e1000_hw *hw);
+static s32  e1000_set_d0_lplu_state_82571(struct e1000_hw *hw,
+                                          bool active);
+static s32  e1000_reset_hw_82571(struct e1000_hw *hw);
+static s32  e1000_init_hw_82571(struct e1000_hw *hw);
+static void e1000_clear_vfta_82571(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
+static s32 e1000_led_on_82574(struct e1000_hw *hw);
+static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw,
+                                           u8 *mc_addr_list, u32 mc_addr_count,
+                                           u32 rar_used_count, u32 rar_count);
+static s32  e1000_setup_link_82571(struct e1000_hw *hw);
+static s32  e1000_setup_copper_link_82571(struct e1000_hw *hw);
+static s32  e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+static s32  e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data);
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+static s32  e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
+static s32  e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static s32  e1000_get_phy_id_82571(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
+static s32  e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+                                       u16 words, u16 *data);
+static s32  e1000_read_mac_addr_82571(struct e1000_hw *hw);
+static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw);
+
+struct e1000_dev_spec_82571 {
+	bool laa_is_present;
+};
+
+/**
+ *  e1000_init_phy_params_82571 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_phy_params_82571");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		phy->type        = e1000_phy_none;
+		goto out;
+	}
+
+	phy->addr                        = 1;
+	phy->autoneg_mask                = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us              = 100;
+
+	phy->ops.acquire                 = e1000_get_hw_semaphore_82571;
+	phy->ops.check_polarity          = e1000_check_polarity_igp;
+	phy->ops.check_reset_block       = e1000_check_reset_block_generic;
+	phy->ops.release                 = e1000_put_hw_semaphore_82571;
+	phy->ops.reset                   = e1000_phy_hw_reset_generic;
+	phy->ops.set_d0_lplu_state       = e1000_set_d0_lplu_state_82571;
+	phy->ops.set_d3_lplu_state       = e1000_set_d3_lplu_state_generic;
+	phy->ops.power_up                = e1000_power_up_phy_copper;
+	phy->ops.power_down              = e1000_power_down_phy_copper_82571;
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		phy->type                   = e1000_phy_igp_2;
+		phy->ops.get_cfg_done       = e1000_get_cfg_done_82571;
+		phy->ops.get_info           = e1000_get_phy_info_igp;
+		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
+		phy->ops.get_cable_length   = e1000_get_cable_length_igp_2;
+		phy->ops.read_reg           = e1000_read_phy_reg_igp;
+		phy->ops.write_reg          = e1000_write_phy_reg_igp;
+
+		/* This uses above function pointers */
+		ret_val = e1000_get_phy_id_82571(hw);
+
+		/* Verify PHY ID */
+		if (phy->id != IGP01E1000_I_PHY_ID) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+		break;
+	case e1000_82573:
+		phy->type                   = e1000_phy_m88;
+		phy->ops.get_cfg_done       = e1000_get_cfg_done_generic;
+		phy->ops.get_info           = e1000_get_phy_info_m88;
+		phy->ops.commit             = e1000_phy_sw_reset_generic;
+		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+		phy->ops.get_cable_length   = e1000_get_cable_length_m88;
+		phy->ops.read_reg           = e1000_read_phy_reg_m88;
+		phy->ops.write_reg          = e1000_write_phy_reg_m88;
+
+		/* This uses above function pointers */
+		ret_val = e1000_get_phy_id_82571(hw);
+
+		/* Verify PHY ID */
+		if (phy->id != M88E1111_I_PHY_ID) {
+			ret_val = -E1000_ERR_PHY;
+			DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+			goto out;
+		}
+		break;
+	case e1000_82574:
+		phy->type                   = e1000_phy_bm;
+		phy->ops.get_cfg_done       = e1000_get_cfg_done_generic;
+		phy->ops.get_info           = e1000_get_phy_info_m88;
+		phy->ops.commit             = e1000_phy_sw_reset_generic;
+		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
+		phy->ops.get_cable_length   = e1000_get_cable_length_m88;
+		phy->ops.read_reg           = e1000_read_phy_reg_bm2;
+		phy->ops.write_reg          = e1000_write_phy_reg_bm2;
+
+		/* This uses above function pointers */
+		ret_val = e1000_get_phy_id_82571(hw);
+		/* Verify PHY ID */
+		if (phy->id != BME1000_E_PHY_ID_R2) { 
+			ret_val = -E1000_ERR_PHY;
+			DEBUGOUT1("PHY ID unknown: type = 0x%08x\n", phy->id);
+			goto out;
+		}
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+		break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_82571 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u16 size;
+
+	DEBUGFUNC("e1000_init_nvm_params_82571");
+
+	nvm->opcode_bits          = 8;
+	nvm->delay_usec           = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size    = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size    = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+		if (((eecd >> 15) & 0x3) == 0x3) {
+			nvm->type = e1000_nvm_flash_hw;
+			nvm->word_size = 2048;
+			/*
+			 * Autonomous Flash update bit must be cleared due
+			 * to Flash update issue.
+			 */
+			eecd &= ~E1000_EECD_AUPDEN;
+			E1000_WRITE_REG(hw, E1000_EECD, eecd);
+			break;
+		}
+		/* Fall Through */
+	default:
+		nvm->type	= e1000_nvm_eeprom_spi;
+		size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+		                  E1000_EECD_SIZE_EX_SHIFT);
+		/*
+		 * Added to a constant, "size" becomes the left-shift value
+		 * for setting word_size.
+		 */
+		size += NVM_WORD_SIZE_BASE_SHIFT;
+
+		/* EEPROM access above 16k is unsupported */
+		if (size > 14)
+			size = 14;
+		nvm->word_size	= 1 << size;
+		break;
+	}
+
+	/* Function Pointers */
+	nvm->ops.acquire       = e1000_acquire_nvm_82571;
+	nvm->ops.read          = e1000_read_nvm_eerd;
+	nvm->ops.release       = e1000_release_nvm_82571;
+	nvm->ops.update        = e1000_update_nvm_checksum_82571;
+	nvm->ops.validate      = e1000_validate_nvm_checksum_82571;
+	nvm->ops.valid_led_default = e1000_valid_led_default_82571;
+	nvm->ops.write         = e1000_write_nvm_82571;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_init_mac_params_82571 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_mac_params_82571");
+
+	/* Set media type */
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82571EB_FIBER:
+	case E1000_DEV_ID_82572EI_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+		hw->phy.media_type = e1000_media_type_fiber;
+		break;
+	case E1000_DEV_ID_82571EB_SERDES:
+	case E1000_DEV_ID_82571EB_SERDES_DUAL:
+	case E1000_DEV_ID_82571EB_SERDES_QUAD:
+	case E1000_DEV_ID_82572EI_SERDES:
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->phy.media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+	        (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
+	                ? true : false;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_82571;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_82571;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_82571;
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_setup_copper_link_82571
+	                : e1000_setup_fiber_serdes_link_82571;
+	/* check for link */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+		break;
+	case e1000_media_type_fiber:
+		mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
+		break;
+	case e1000_media_type_internal_serdes:
+		mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
+		break;
+	default:
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+	/* check management mode */
+	switch (hw->mac.type) {
+	case e1000_82574:
+		mac->ops.check_mng_mode = e1000_check_mng_mode_82574;
+		break;
+	default:
+		mac->ops.check_mng_mode = e1000_check_mng_mode_generic;
+		break;
+	}
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_82571;
+	/* writing VFTA */
+	mac->ops.write_vfta = e1000_write_vfta_generic;
+	/* clearing VFTA */
+	mac->ops.clear_vfta = e1000_clear_vfta_82571;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_generic;
+	/* read mac address */
+	mac->ops.read_mac_addr = e1000_read_mac_addr_82571;
+	/* blink LED */
+	mac->ops.blink_led = e1000_blink_led_generic;
+	/* setup LED */
+	mac->ops.setup_led = e1000_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000_cleanup_led_generic;
+	/* turn on/off LED */
+	switch (hw->mac.type) {
+	case e1000_82574:
+		mac->ops.led_on = e1000_led_on_82574;
+		break;
+	default:
+		mac->ops.led_on = e1000_led_on_generic;
+		break;
+	}
+	mac->ops.led_off = e1000_led_off_generic;
+	/* remove device */
+	mac->ops.remove_device = e1000_remove_device_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82571;
+	/* link info */
+	mac->ops.get_link_up_info =
+	        (hw->phy.media_type == e1000_media_type_copper)
+	                ? e1000_get_speed_and_duplex_copper_generic
+	                : e1000_get_speed_and_duplex_fiber_serdes_generic;
+
+	hw->dev_spec_size = sizeof(struct e1000_dev_spec_82571);
+
+	/* Device-specific structure allocation */
+	ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_function_pointers_82571 - Init func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  The only function explicitly called by the api module to initialize
+ *  all function pointers and parameters.
+ **/
+void e1000_init_function_pointers_82571(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_82571");
+
+	e1000_init_mac_ops_generic(hw);
+	e1000_init_nvm_ops_generic(hw);
+	hw->mac.ops.init_params = e1000_init_mac_params_82571;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_82571;
+	hw->phy.ops.init_params = e1000_init_phy_params_82571;
+}
+
+/**
+ *  e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_id = 0;
+
+	DEBUGFUNC("e1000_get_phy_id_82571");
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		/*
+		 * The 82571 firmware may still be configuring the PHY.
+		 * In this case, we cannot access the PHY until the
+		 * configuration is done.  So we explicitly set the
+		 * PHY ID.
+		 */
+		phy->id = IGP01E1000_I_PHY_ID;
+		break;
+	case e1000_82573:
+		ret_val = e1000_get_phy_id(hw);
+		break;
+	case e1000_82574:
+		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id = (u32)(phy_id << 16);
+		usec_delay(20);
+		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+		if (ret_val)
+			goto out;
+
+		phy->id |= (u32)(phy_id);
+		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 ret_val = E1000_SUCCESS;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	DEBUGFUNC("e1000_get_hw_semaphore_82571");
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		e1000_put_hw_semaphore_generic(hw);
+		DEBUGOUT("Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_put_hw_semaphore_82571 - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	DEBUGFUNC("e1000_put_hw_semaphore_82571");
+
+	swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+	swsm &= ~E1000_SWSM_SWESMBI;
+
+	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ *  e1000_acquire_nvm_82571 - Request for access to the EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ *  Then for non-82573 hardware, set the EEPROM access request bit and wait
+ *  for EEPROM access grant bit.  If the access grant bit is not set, release
+ *  hardware semaphore.
+ **/
+static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_acquire_nvm_82571");
+
+	ret_val = e1000_get_hw_semaphore_82571(hw);
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
+		ret_val = e1000_acquire_nvm_generic(hw);
+
+	if (ret_val)
+		e1000_put_hw_semaphore_82571(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_nvm_82571 - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+static void e1000_release_nvm_82571(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_release_nvm_82571");
+
+	e1000_release_nvm_generic(hw);
+	e1000_put_hw_semaphore_82571(hw);
+}
+
+/**
+ *  e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
+                                 u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_nvm_82571");
+
+	switch (hw->mac.type) {
+	case e1000_82573:
+	case e1000_82574:
+		ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
+		break;
+	case e1000_82571:
+	case e1000_82572:
+		ret_val = e1000_write_nvm_spi(hw, offset, words, data);
+		break;
+	default:
+		ret_val = -E1000_ERR_NVM;
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum_82571 - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	u32 eecd;
+	s32 ret_val;
+	u16 i;
+
+	DEBUGFUNC("e1000_update_nvm_checksum_82571");
+
+	ret_val = e1000_update_nvm_checksum_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * If our nvm is an EEPROM, then we're done
+	 * otherwise, commit the checksum to the flash NVM.
+	 */
+	if (hw->nvm.type != e1000_nvm_flash_hw)
+		goto out;
+
+	/* Check for pending operations. */
+	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+		msec_delay(1);
+		if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0)
+			break;
+	}
+
+	if (i == E1000_FLASH_UPDATES) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Reset the firmware if using STM opcode. */
+	if ((E1000_READ_REG(hw, E1000_FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+		/*
+		 * The enabling of and the actual reset must be done
+		 * in two write cycles.
+		 */
+		E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET_ENABLE);
+		E1000_WRITE_FLUSH(hw);
+		E1000_WRITE_REG(hw, E1000_HICR, E1000_HICR_FW_RESET);
+	}
+
+	/* Commit the write to flash */
+	eecd = E1000_READ_REG(hw, E1000_EECD) | E1000_EECD_FLUPD;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+
+	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+		msec_delay(1);
+		if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_FLUPD) == 0)
+			break;
+	}
+
+	if (i == E1000_FLASH_UPDATES) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_validate_nvm_checksum_82571");
+
+	if (hw->nvm.type == e1000_nvm_flash_hw)
+		e1000_fix_nvm_checksum_82571(hw);
+
+	return e1000_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ *  e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  After checking for invalid values, poll the EEPROM to ensure the previous
+ *  command has completed before trying to write the next word.  After write
+ *  poll for completion.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+                                      u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eewr = 0;
+	s32 ret_val = 0;
+
+	DEBUGFUNC("e1000_write_nvm_eewr_82571");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+		       ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+		       E1000_NVM_RW_REG_START;
+
+		ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+		if (ret_val)
+			break;
+
+		E1000_WRITE_REG(hw, E1000_EEWR, eewr);
+
+		ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+		if (ret_val)
+			break;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cfg_done_82571 - Poll for configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the management control register for the config done bit to be set.
+ **/
+static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_get_cfg_done_82571");
+
+	while (timeout) {
+		if (E1000_READ_REG(hw, E1000_EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0)
+			break;
+		msec_delay(1);
+		timeout--;
+	}
+	if (!timeout) {
+		DEBUGOUT("MNG configuration cycle has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When activating LPLU
+ *  this function also disables smart speed and vice versa.  LPLU will not be
+ *  activated unless the device autonegotiation advertisement meets standards
+ *  of either 10 or 10/100 or 10/100/1000 at all duplexes.  This is a function
+ *  pointer entry point only called by PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_set_d0_lplu_state_82571");
+
+	if (!(phy->ops.read_reg))
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (active) {
+		data |= IGP02E1000_PM_D0_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+		if (ret_val)
+			goto out;
+	} else {
+		data &= ~IGP02E1000_PM_D0_LPLU;
+		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_hw_82571 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
+{
+	u32 ctrl, extcnf_ctrl, ctrl_ext, icr;
+	s32 ret_val;
+	u16 i = 0;
+
+	DEBUGFUNC("e1000_reset_hw_82571");
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000_disable_pcie_master_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("PCI-E Master disable polling has failed.\n");
+	}
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	msec_delay(10);
+
+	/*
+	 * Must acquire the MDIO ownership before MAC reset.
+	 * Ownership defaults to firmware after a reset.
+	 */
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+		do {
+			E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+			extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+
+			if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+				break;
+
+			extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+			msec_delay(2);
+			i++;
+		} while (i < MDIO_OWNERSHIP_TIMEOUT);
+	}
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	DEBUGOUT("Issuing a global reset to MAC\n");
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	if (hw->nvm.type == e1000_nvm_flash_hw) {
+		usec_delay(10);
+		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+		ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	ret_val = e1000_get_auto_rd_done_generic(hw);
+	if (ret_val)
+		/* We don't want to continue accessing MAC registers. */
+		goto out;
+
+	/*
+	 * Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+	 * Need to wait for Phy configuration completion before accessing
+	 * NVM and Phy.
+	 */
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
+		msec_delay(25);
+
+	/* Clear any pending interrupt events. */
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	icr = E1000_READ_REG(hw, E1000_ICR);
+
+	if (!(e1000_check_alt_mac_addr_generic(hw)))
+		e1000_set_laa_state_82571(hw, true);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_82571 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg_data;
+	s32 ret_val;
+	u16 i, rar_count = mac->rar_entry_count;
+
+	DEBUGFUNC("e1000_init_hw_82571");
+
+	e1000_initialize_hw_bits_82571(hw);
+
+	/* Initialize identification LED */
+	ret_val = e1000_id_led_init_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	DEBUGOUT("Initializing the IEEE VLAN\n");
+	mac->ops.clear_vfta(hw);
+
+	/* Setup the receive address. */
+	/*
+	 * If, however, a locally administered address was assigned to the
+	 * 82571, we must reserve a RAR for it to work around an issue where
+	 * resetting one port will reload the MAC on the other port.
+	 */
+	if (e1000_get_laa_state_82571(hw))
+		rar_count--;
+	e1000_init_rx_addrs_generic(hw, rar_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy */
+	reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+	           E1000_TXDCTL_FULL_TX_DESC_WB |
+	           E1000_TXDCTL_COUNT_DESC;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg_data);
+
+	/* ...for both queues. */
+	if (mac->type != e1000_82573 && mac->type != e1000_82574) {
+		reg_data = E1000_READ_REG(hw, E1000_TXDCTL(1));
+		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+		           E1000_TXDCTL_FULL_TX_DESC_WB |
+		           E1000_TXDCTL_COUNT_DESC;
+		E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg_data);
+	} else {
+		e1000_enable_tx_pkt_filtering_generic(hw);
+		reg_data = E1000_READ_REG(hw, E1000_GCR);
+		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+		E1000_WRITE_REG(hw, E1000_GCR, reg_data);
+	}
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_82571(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	DEBUGFUNC("e1000_initialize_hw_bits_82571");
+
+	if (hw->mac.disable_hw_init_bits)
+		goto out;
+
+	/* Transmit Descriptor Control 0 */
+	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = E1000_READ_REG(hw, E1000_TARC(0));
+	reg &= ~(0xF << 27); /* 30:27 */
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+		break;
+	default:
+		break;
+	}
+	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = E1000_READ_REG(hw, E1000_TARC(1));
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		reg &= ~((1 << 29) | (1 << 30));
+		reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+		if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+			reg &= ~(1 << 28);
+		else
+			reg |= (1 << 28);
+		E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+		break;
+	default:
+		break;
+	}
+
+	/* Device Control */
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+		reg = E1000_READ_REG(hw, E1000_CTRL);
+		reg &= ~(1 << 29);
+		E1000_WRITE_REG(hw, E1000_CTRL, reg);
+	}
+
+	/* Extended Device Control */
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+		reg &= ~(1 << 23);
+		reg |= (1 << 22);
+		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+	}
+
+	/* PCI-Ex Control Register */
+	if (hw->mac.type == e1000_82574) {
+		reg = E1000_READ_REG(hw, E1000_GCR);
+		reg |= (1 << 22);
+		E1000_WRITE_REG(hw, E1000_GCR, reg);        
+	}
+
+out:
+	return;
+}
+
+/**
+ *  e1000_clear_vfta_82571 - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+static void e1000_clear_vfta_82571(struct e1000_hw *hw)
+{
+	u32 offset;
+	u32 vfta_value = 0;
+	u32 vfta_offset = 0;
+	u32 vfta_bit_in_reg = 0;
+
+	DEBUGFUNC("e1000_clear_vfta_82571");
+
+	if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+		if (hw->mng_cookie.vlan_id != 0) {
+			/*
+			 * The VFTA is a 4096b bit-field, each identifying
+			 * a single VLAN ID.  The following operations
+			 * determine which 32b entry (i.e. offset) into the
+			 * array we want to set the VLAN ID (i.e. bit) of
+			 * the manageability unit.
+			 */
+			vfta_offset = (hw->mng_cookie.vlan_id >>
+			               E1000_VFTA_ENTRY_SHIFT) &
+			              E1000_VFTA_ENTRY_MASK;
+			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+			                       E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+		}
+	}
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		/*
+		 * If the offset we want to clear is the same offset of the
+		 * manageability VLAN ID, then clear all bits except that of
+		 * the manageability unit.
+		 */
+		vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
+		E1000_WRITE_FLUSH(hw);
+	}
+}
+
+/**
+ *  e1000_check_mng_mode_82574 - Check manageability is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the NVM Initialization Control Word 2 and returns true
+ *  (>0) if any manageability is enabled, else false (0).
+ **/
+static bool e1000_check_mng_mode_82574(struct e1000_hw *hw)
+{
+	u16 data;
+
+	DEBUGFUNC("e1000_check_mng_mode_82574");
+
+	hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+	return ((data & E1000_NVM_INIT_CTRL2_MNGM) != 0);
+}
+
+/**
+ *  e1000_led_on_82574 - Turn LED on
+ *  @hw: pointer to the HW structure
+ *  
+ *  Turn LED on.
+ **/
+static s32 e1000_led_on_82574(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u32 i;
+
+	DEBUGFUNC("e1000_led_on_82574");
+
+	ctrl = hw->mac.ledctl_mode2;
+	if (!(E1000_STATUS_LU & E1000_READ_REG(hw, E1000_STATUS))) {
+		/* 
+		 * If no link, then turn LED on by setting the invert bit 
+		 * for each LED that's "on" (0x0E) in ledctl_mode2.
+		 */
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
+	}
+	E1000_WRITE_REG(hw, E1000_LEDCTL, ctrl);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_update_mc_addr_list_82571 - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.
+ **/
+static void e1000_update_mc_addr_list_82571(struct e1000_hw *hw,
+                                           u8 *mc_addr_list, u32 mc_addr_count,
+                                           u32 rar_used_count, u32 rar_count)
+{
+	DEBUGFUNC("e1000_update_mc_addr_list_82571");
+
+	if (e1000_get_laa_state_82571(hw))
+		rar_count--;
+
+	e1000_update_mc_addr_list_generic(hw, mc_addr_list, mc_addr_count,
+	                                  rar_used_count, rar_count);
+}
+
+/**
+ *  e1000_setup_link_82571 - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_82571(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_setup_link_82571");
+
+	/*
+	 * 82573 does not have a word in the NVM to determine
+	 * the default flow control setting, so we explicitly
+	 * set it to full.
+	 */
+	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
+	    hw->fc.type  == e1000_fc_default)
+		hw->fc.type = e1000_fc_full;
+
+	return e1000_setup_link_generic(hw);
+}
+
+/**
+ *  e1000_setup_copper_link_82571 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
+{
+	u32 ctrl, led_ctrl;
+	s32  ret_val;
+
+	DEBUGFUNC("e1000_setup_copper_link_82571");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	switch (hw->phy.type) {
+	case e1000_phy_m88:
+	case e1000_phy_bm:
+		ret_val = e1000_copper_link_setup_m88(hw);
+		break;
+	case e1000_phy_igp_2:
+		ret_val = e1000_copper_link_setup_igp(hw);
+		/* Setup activity LED */
+		led_ctrl = E1000_READ_REG(hw, E1000_LEDCTL);
+		led_ctrl &= IGP_ACTIVITY_LED_MASK;
+		led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+		E1000_WRITE_REG(hw, E1000_LEDCTL, led_ctrl);
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		break;
+	}
+
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes links.
+ *  Upon successful setup, poll for link.
+ **/
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_setup_fiber_serdes_link_82571");
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		/*
+		 * If SerDes loopback mode is entered, there is no form
+		 * of reset to take the adapter out of that mode.  So we
+		 * have to explicitly take the adapter out of loopback
+		 * mode.  This prevents drivers from twiddling their thumbs
+		 * if another tool failed to take it out of loopback mode.
+		 */
+		E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+		break;
+	default:
+		break;
+	}
+
+	return e1000_setup_fiber_serdes_link_generic(hw);
+}
+
+/**
+ *  e1000_valid_led_default_82571 - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_valid_led_default_82571");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
+	    *data == ID_LED_RESERVED_F746)
+		*data = ID_LED_DEFAULT_82573;
+	else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_laa_state_82571 - Get locally administered address state
+ *  @hw: pointer to the HW structure
+ *
+ *  Retrieve and return the current locally administered address state.
+ **/
+bool e1000_get_laa_state_82571(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82571 *dev_spec;
+	bool state = false;
+
+	DEBUGFUNC("e1000_get_laa_state_82571");
+
+	if (hw->mac.type != e1000_82571)
+		goto out;
+
+	dev_spec = (struct e1000_dev_spec_82571 *)hw->dev_spec;
+
+	state = dev_spec->laa_is_present;
+
+out:
+	return state;
+}
+
+/**
+ *  e1000_set_laa_state_82571 - Set locally administered address state
+ *  @hw: pointer to the HW structure
+ *  @state: enable/disable locally administered address
+ *
+ *  Enable/Disable the current locally administered address state.
+ **/
+void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state)
+{
+	struct e1000_dev_spec_82571 *dev_spec;
+
+	DEBUGFUNC("e1000_set_laa_state_82571");
+
+	if (hw->mac.type != e1000_82571)
+		goto out;
+
+	dev_spec = (struct e1000_dev_spec_82571 *)hw->dev_spec;
+
+	dev_spec->laa_is_present = state;
+
+	/* If workaround is activated... */
+	if (state) {
+		/*
+		 * Hold a copy of the LAA in RAR[14] This is done so that
+		 * between the time RAR[0] gets clobbered and the time it
+		 * gets fixed, the actual LAA is in one of the RARs and no
+		 * incoming packets directed to this port are dropped.
+		 * Eventually the LAA will be in RAR[0] and RAR[14].
+		 */
+		e1000_rar_set_generic(hw, hw->mac.addr,
+		                      hw->mac.rar_entry_count - 1);
+	}
+
+out:
+	return;
+}
+
+/**
+ *  e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies that the EEPROM has completed the update.  After updating the
+ *  EEPROM, we need to check bit 15 in work 0x23 for the checksum fix.  If
+ *  the checksum fix is not implemented, we need to set the bit and update
+ *  the checksum.  Otherwise, if bit 15 is set and the checksum is incorrect,
+ *  we need to return bad checksum.
+ **/
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_fix_nvm_checksum_82571");
+
+	if (nvm->type != e1000_nvm_flash_hw)
+		goto out;
+
+	/*
+	 * Check bit 4 of word 10h.  If it is 0, firmware is done updating
+	 * 10h-12h.  Checksum may need to be fixed.
+	 */
+	ret_val = nvm->ops.read(hw, 0x10, 1, &data);
+	if (ret_val)
+		goto out;
+
+	if (!(data & 0x10)) {
+		/*
+		 * Read 0x23 and check bit 15.  This bit is a 1
+		 * when the checksum has already been fixed.  If
+		 * the checksum is still wrong and this bit is a
+		 * 1, we need to return bad checksum.  Otherwise,
+		 * we need to set this bit to a 1 and update the
+		 * checksum.
+		 */
+		ret_val = nvm->ops.read(hw, 0x23, 1, &data);
+		if (ret_val)
+			goto out;
+
+		if (!(data & 0x8000)) {
+			data |= 0x8000;
+			ret_val = nvm->ops.write(hw, 0x23, 1, &data);
+			if (ret_val)
+				goto out;
+			ret_val = nvm->ops.update(hw);
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_mac_addr_82571 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_mac_addr_82571");
+	if (e1000_check_alt_mac_addr_generic(hw))
+		ret_val = e1000_read_mac_addr_generic(hw);
+
+	return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_82571 - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!(phy->ops.check_reset_block))
+		return;
+
+	/* If the management interface is not enabled, then power down */
+	if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
+		e1000_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
+{
+	volatile u32 temp;
+
+	DEBUGFUNC("e1000_clear_hw_cntrs_82571");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+	temp = E1000_READ_REG(hw, E1000_PRC64);
+	temp = E1000_READ_REG(hw, E1000_PRC127);
+	temp = E1000_READ_REG(hw, E1000_PRC255);
+	temp = E1000_READ_REG(hw, E1000_PRC511);
+	temp = E1000_READ_REG(hw, E1000_PRC1023);
+	temp = E1000_READ_REG(hw, E1000_PRC1522);
+	temp = E1000_READ_REG(hw, E1000_PTC64);
+	temp = E1000_READ_REG(hw, E1000_PTC127);
+	temp = E1000_READ_REG(hw, E1000_PTC255);
+	temp = E1000_READ_REG(hw, E1000_PTC511);
+	temp = E1000_READ_REG(hw, E1000_PTC1023);
+	temp = E1000_READ_REG(hw, E1000_PTC1522);
+
+	temp = E1000_READ_REG(hw, E1000_ALGNERRC);
+	temp = E1000_READ_REG(hw, E1000_RXERRC);
+	temp = E1000_READ_REG(hw, E1000_TNCRS);
+	temp = E1000_READ_REG(hw, E1000_CEXTERR);
+	temp = E1000_READ_REG(hw, E1000_TSCTC);
+	temp = E1000_READ_REG(hw, E1000_TSCTFC);
+
+	temp = E1000_READ_REG(hw, E1000_MGTPRC);
+	temp = E1000_READ_REG(hw, E1000_MGTPDC);
+	temp = E1000_READ_REG(hw, E1000_MGTPTC);
+
+	temp = E1000_READ_REG(hw, E1000_IAC);
+	temp = E1000_READ_REG(hw, E1000_ICRXOC);
+
+	temp = E1000_READ_REG(hw, E1000_ICRXPTC);
+	temp = E1000_READ_REG(hw, E1000_ICRXATC);
+	temp = E1000_READ_REG(hw, E1000_ICTXPTC);
+	temp = E1000_READ_REG(hw, E1000_ICTXATC);
+	temp = E1000_READ_REG(hw, E1000_ICTXQEC);
+	temp = E1000_READ_REG(hw, E1000_ICTXQMTC);
+	temp = E1000_READ_REG(hw, E1000_ICRXDMTC);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_82571.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_82571.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_82571.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_82571.h	2008-06-23 18:27:32.000000000 +0200
@@ -0,0 +1,53 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_82571_H_
+#define _E1000_82571_H_
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+                              (ID_LED_OFF1_ON2  <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+
+/* Intr Throttling - RW */
+#define E1000_EITR_82574(_n)    (0x000E8 + (0x4 * (_n)))
+
+#define E1000_EIAC_82574        0x000DC /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAC_MASK_82574   0x01F00000
+
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
+#define E1000_RXCFGL    0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+
+bool e1000_get_laa_state_82571(struct e1000_hw *hw);
+void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_defines.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_defines.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_defines.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_defines.h	2008-06-23 18:27:32.000000000 +0200
@@ -0,0 +1,1435 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
+#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
+#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_IGNORE_TCO_BM 0x00000800 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0_BM      0x00001000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1_BM      0x00002000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2_BM      0x00004000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3_BM      0x00008000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS_BM 0x0000F0FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET_BM 12 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS_BM 0x0000F000 /* Mask for the 4 flexible filters */
+#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS  0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC         E1000_WUFC_LNKC
+#define E1000_WUS_MAG          E1000_WUFC_MAG
+#define E1000_WUS_EX           E1000_WUFC_EX
+#define E1000_WUS_MC           E1000_WUFC_MC
+#define E1000_WUS_BC           E1000_WUFC_BC
+#define E1000_WUS_ARP          E1000_WUFC_ARP
+#define E1000_WUS_IPV4         E1000_WUFC_IPV4
+#define E1000_WUS_IPV6         E1000_WUFC_IPV6
+#define E1000_WUS_FLX0_BM      E1000_WUFC_FLX0_BM
+#define E1000_WUS_FLX1_BM      E1000_WUFC_FLX1_BM
+#define E1000_WUS_FLX2_BM      E1000_WUFC_FLX2_BM
+#define E1000_WUS_FLX3_BM      E1000_WUFC_FLX3_BM
+#define E1000_WUS_FLX_FILTERS_BM        E1000_WUFC_FLX_FILTERS_BM
+#define E1000_WUS_FLX0         E1000_WUFC_FLX0
+#define E1000_WUS_FLX1         E1000_WUFC_FLX1
+#define E1000_WUS_FLX2         E1000_WUFC_FLX2
+#define E1000_WUS_FLX3         E1000_WUFC_FLX3
+#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+/* Reserved (bits 4,5) in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
+/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+#define E1000_CTRL_EXT_CANC           0x04000000 /* Interrupt delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
+/* IAME enable bit (27) was removed in >= 82575 */
+#define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
+#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error detection enabled */
+#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity error detection enable */
+#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_LSECCK         0x00001000
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_REG_ADDR         0x00FF0000
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_PHY_ADDR         0x07000000
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_RESET            0x10000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDEXT_LSECH                0x01000000
+#define E1000_RXDEXT_LSECE_MASK           0x60000000
+#define E1000_RXDEXT_LSECE_NO_ERROR       0x00000000
+#define E1000_RXDEXT_LSECE_NO_SA_MATCH    0x20000000
+#define E1000_RXDEXT_LSECE_REPLAY_DETECT  0x40000000
+#define E1000_RXDEXT_LSECE_BAD_SIG        0x60000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_ENABLE_MASK                 0x00000007
+#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x1
+#define E1000_SWFW_PHY0_SM  0x2
+#define E1000_SWFW_PHY1_SM  0x4
+#define E1000_SWFW_CSR_SM   0x8
+
+/* FACTPS Definitions */
+#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_CFG_PCS_EN             8
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_10            0
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
+#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
+#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
+#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
+#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
+#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_10          0
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
+#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
+#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
+#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
+#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion by NVM */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* Constants used to interpret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define PHY_FORCE_TIME   20
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG      ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
+                                                     ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT      8
+#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
+#define E1000_LEDCTL_LED1_IVRT            0x00004000
+#define E1000_LEDCTL_LED1_BLINK           0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT      16
+#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
+#define E1000_LEDCTL_LED2_IVRT            0x00400000
+#define E1000_LEDCTL_LED2_BLINK           0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT      24
+#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
+#define E1000_LEDCTL_LED3_IVRT            0x40000000
+#define E1000_LEDCTL_LED3_BLINK           0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+/* Extended desc bits for Linksec and timesync */
+#define E1000_TXD_CMD_LINKSEC     0x10000000 /* Apply LinkSec on packet */
+#define E1000_TXD_EXTCMD_TSTAMP   0x00000010 /* IEEE1588 Timestamp packet */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Transmit Arbitration Count */
+#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
+#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_NFS_VER_MASK        0x00000300
+#define E1000_RFCTL_NFS_VER_SHIFT       8
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_ACK_DIS             0x00001000
+#define E1000_RFCTL_ACKD_DIS            0x00002000
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define ETHERNET_FCS_SIZE       4
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
+
+#define E1000_PHY_CTRL_SPD_EN             0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS           0x00050000
+
+/* PBA constants */
+#define E1000_PBA_6K  0x0006	/* 6KB */
+#define E1000_PBA_8K  0x0008    /* 8KB */
+#define E1000_PBA_12K 0x000C    /* 12KB */
+#define E1000_PBA_16K 0x0010    /* 16KB */
+#define E1000_PBA_20K 0x0014
+#define E1000_PBA_22K 0x0016
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
+#define E1000_PBA_38K 0x0026
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB */
+#define E1000_PBA_64K 0x0040    /* 64KB */
+
+#define E1000_PBS_16K E1000_PBA_16K
+#define E1000_PBS_24K E1000_PBA_24K
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR  0x00400000 /* host arb read buffer parity error */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
+#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
+
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0    0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1    0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2    0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3    0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0    0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1    0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2    0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3    0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
+#define E1000_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+/* TCP Timer */
+#define E1000_TCPTIMER_KS       0x00000100 /* KickStart */
+#define E1000_TCPTIMER_COUNT_ENABLE       0x00000200 /* Count Enable */
+#define E1000_TCPTIMER_COUNT_FINISH       0x00000400 /* Count finish */
+#define E1000_TCPTIMER_LOOP     0x00000800 /* Loop */
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ)
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+#define E1000_IMS_RXQ0          E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
+#define E1000_IMS_RXQ1          E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
+#define E1000_IMS_TXQ0          E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
+#define E1000_IMS_TXQ1          E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
+#define E1000_IMS_OTHER         E1000_ICR_OTHER /* Other Interrupts */
+
+/* Extended Interrupt Mask Set */
+#define E1000_EIMS_RX_QUEUE0    E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EIMS_RX_QUEUE1    E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EIMS_RX_QUEUE2    E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EIMS_RX_QUEUE3    E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EIMS_TX_QUEUE0    E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EIMS_TX_QUEUE1    E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EIMS_TX_QUEUE2    E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EIMS_TX_QUEUE3    E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EIMS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EIMS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Extended Interrupt Cause Set */
+#define E1000_EICS_RX_QUEUE0    E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
+#define E1000_EICS_RX_QUEUE1    E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
+#define E1000_EICS_RX_QUEUE2    E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
+#define E1000_EICS_RX_QUEUE3    E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
+#define E1000_EICS_TX_QUEUE0    E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
+#define E1000_EICS_TX_QUEUE1    E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
+#define E1000_EICS_TX_QUEUE2    E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
+#define E1000_EICS_TX_QUEUE3    E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
+#define E1000_EICS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EICS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+/* Enable the counting of descriptors still to be processed. */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES     15
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT               50
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT      10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
+#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
+#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
+#define E1000_RXCW_CC         0x10000000        /* Receive config change */
+#define E1000_RXCW_C          0x20000000        /* Receive config */
+#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
+#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+                           E1000_GCR_RXDSCW_NO_SNOOP      | \
+                           E1000_GCR_RXDSCR_NO_SNOOP      | \
+                           E1000_GCR_TXD_NO_SNOOP         | \
+                           E1000_GCR_TXDSCW_NO_SNOOP      | \
+                           E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+
+#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Register */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+
+#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
+#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_NVM_RW_REG_DATA   16   /* Offset to data in NVM read/write registers */
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES  2000
+
+/* NVM Word Offsets */
+#define NVM_COMPAT                 0x0003
+#define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_VERSION                0x0005
+#define NVM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define NVM_PHY_CLASS_WORD         0x0007
+#define NVM_INIT_CONTROL1_REG      0x000A
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
+#define NVM_INIT_3GIO_3            0x001A
+#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_CFG                    0x0012
+#define NVM_FLASH_VERSION          0x0032
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_PAUSE            0x1000
+#define NVM_WORD0F_ASM_DIR          0x2000
+#define NVM_WORD0F_ANE              0x0800
+#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
+#define NVM_WORD0F_LPLU             0x0001
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK  0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_MAC_ADDR_OFFSET        0
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_RESERVED_WORD          0xFFFF
+#define NVM_PHY_CLASS_A            0x8000
+#define NVM_SERDES_AMPLITUDE_MASK  0x000F
+#define NVM_SIZE_MASK              0x1C00
+#define NVM_SIZE_SHIFT             10
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+#define NVM_SWDPIO_EXT_SHIFT       4
+
+/* NVM Commands - Microwire */
+#define NVM_READ_OPCODE_MICROWIRE  0x6  /* NVM read opcode */
+#define NVM_WRITE_OPCODE_MICROWIRE 0x5  /* NVM write opcode */
+#define NVM_ERASE_OPCODE_MICROWIRE 0x7  /* NVM erase opcode */
+#define NVM_EWEN_OPCODE_MICROWIRE  0x13 /* NVM erase/write enable */
+#define NVM_EWDS_OPCODE_MICROWIRE  0x10 /* NVM erase/write disable */
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+#define NVM_STATUS_WEN_SPI         0x02
+#define NVM_STATUS_BP0_SPI         0x04
+#define NVM_STATUS_BP1_SPI         0x08
+#define NVM_STATUS_WPEN_SPI        0x80
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+                              (ID_LED_OFF1_OFF2 <<  8) | \
+                              (ID_LED_DEF1_DEF2 <<  4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCIX_COMMAND_REGISTER        0xE6
+#define PCIX_STATUS_REGISTER_LO      0xE8
+#define PCIX_STATUS_REGISTER_HI      0xEA
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+
+#define PCIX_COMMAND_MMRBC_MASK      0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT     0x2
+#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
+#define PCIX_STATUS_LO_FUNC_MASK     0x7
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                 6
+#endif
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID    0x01410C50
+#define M88E1000_I_PHY_ID    0x01410C30
+#define M88E1011_I_PHY_ID    0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1011_I_REV_4     0x04
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define GG82563_E_PHY_ID     0x01410CA0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+#define BME1000_E_PHY_ID     0x01410CB0
+#define BME1000_E_PHY_ID_R2  0x01410CB1
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+ * 0=Normal 10BASE-T Rx Threshold
+ */
+#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
+
+/* BME1000 PHY Specific Control Register */
+#define BME1000_PSCR_ENABLE_DOWNSHIFT   0x0800 /* 1 = enable downshift */
+
+/*
+ * Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT        5
+#define GG82563_REG(page, reg)    \
+        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG       30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL           \
+        GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_SPEC_STATUS         \
+        GG82563_REG(0, 17) /* PHY Specific Status */
+#define GG82563_PHY_INT_ENABLE          \
+        GG82563_REG(0, 18) /* Interrupt Enable */
+#define GG82563_PHY_SPEC_STATUS_2       \
+        GG82563_REG(0, 19) /* PHY Specific Status 2 */
+#define GG82563_PHY_RX_ERR_CNTR         \
+        GG82563_REG(0, 21) /* Receive Error Counter */
+#define GG82563_PHY_PAGE_SELECT         \
+        GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2         \
+        GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT     \
+        GG82563_REG(0, 29) /* Alternate Page Select */
+#define GG82563_PHY_TEST_CLK_CTRL       \
+        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
+
+#define GG82563_PHY_MAC_SPEC_CTRL       \
+        GG82563_REG(2, 21) /* MAC Specific Control Register */
+#define GG82563_PHY_MAC_SPEC_CTRL_2     \
+        GG82563_REG(2, 26) /* MAC Specific Control 2 */
+
+#define GG82563_PHY_DSP_DISTANCE    \
+        GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL   \
+        GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PORT_RESET          \
+        GG82563_REG(193, 17) /* Port Reset */
+#define GG82563_PHY_REVISION_ID         \
+        GG82563_REG(193, 18) /* Revision ID */
+#define GG82563_PHY_DEVICE_ID           \
+        GG82563_REG(193, 19) /* Device ID */
+#define GG82563_PHY_PWR_MGMT_CTRL       \
+        GG82563_REG(193, 20) /* Power Management Control */
+#define GG82563_PHY_RATE_ADAPT_CTRL     \
+        GG82563_REG(193, 25) /* Rate Adaptation Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
+        GG82563_REG(194, 16) /* FIFO's Control/Status */
+#define GG82563_PHY_KMRN_CTRL           \
+        GG82563_REG(194, 17) /* Control */
+#define GG82563_PHY_INBAND_CTRL         \
+        GG82563_REG(194, 18) /* Inband Control */
+#define GG82563_PHY_KMRN_DIAGNOSTIC     \
+        GG82563_REG(194, 19) /* Diagnostic */
+#define GG82563_PHY_ACK_TIMEOUTS        \
+        GG82563_REG(194, 20) /* Acknowledge Timeouts */
+#define GG82563_PHY_ADV_ABILITY         \
+        GG82563_REG(194, 21) /* Advertised Ability */
+#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
+        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
+#define GG82563_PHY_ADV_NEXT_PAGE       \
+        GG82563_REG(194, 24) /* Advertised Next Page */
+#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
+        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
+#define GG82563_PHY_KMRN_MISC           \
+        GG82563_REG(194, 26) /* Misc. */
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000.h	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000.h	2008-06-23 18:27:32.000000000 +0200
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -33,36 +33,43 @@
 
 #include <linux/types.h>
 #include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
+#include <asm/io.h>
 #include <linux/netdevice.h>
 
-#include "hw.h"
+#include "kcompat.h"
+
+#include "e1000_hw.h"
 
 struct e1000_info;
 
-#define ndev_printk(level, netdev, format, arg...) \
-	printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \
-	       (netdev)->name, ## arg)
-
-#ifdef DEBUG
-#define ndev_dbg(netdev, format, arg...) \
-	ndev_printk(KERN_DEBUG , netdev, format, ## arg)
-#else
-#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0)
-#endif
+#define e_printk(level, adapter, format, arg...) \
+	printk(level "%s: %s: " format, pci_name(adapter->pdev), \
+	       (strchr(adapter->netdev->name, '%') ? "" : \
+	        adapter->netdev->name), ## arg)
+
+#define e_dbg(format, arg...) do { (void)(adapter); } while (0)
+
+#define e_err(format, arg...) \
+	e_printk(KERN_ERR, adapter, format, ## arg)
+#define e_info(format, arg...) \
+	e_printk(KERN_INFO, adapter, format, ## arg)
+#define e_warn(format, arg...) \
+	e_printk(KERN_WARNING, adapter, format, ## arg)
+#define e_notice(format, arg...) \
+	e_printk(KERN_NOTICE, adapter, format, ## arg)
+
+
+#ifdef CONFIG_E1000E_MSIX
+/* Interrupt modes, as used by the IntMode paramter */
+#define E1000E_INT_MODE_LEGACY		0
+#define E1000E_INT_MODE_MSI		1
+#define E1000E_INT_MODE_MSIX		2
 
-#define ndev_err(netdev, format, arg...) \
-	ndev_printk(KERN_ERR , netdev, format, ## arg)
-#define ndev_info(netdev, format, arg...) \
-	ndev_printk(KERN_INFO , netdev, format, ## arg)
-#define ndev_warn(netdev, format, arg...) \
-	ndev_printk(KERN_WARNING , netdev, format, ## arg)
-#define ndev_notice(netdev, format, arg...) \
-	ndev_printk(KERN_NOTICE , netdev, format, ## arg)
+#endif /* CONFIG_E1000E_MSIX */
 
+#define E1000_MAX_INTR 10
 
-/* TX/RX descriptor defines */
+/* Tx/Rx descriptor defines */
 #define E1000_DEFAULT_TXD		256
 #define E1000_MAX_TXD			4096
 #define E1000_MIN_TXD			80
@@ -71,6 +78,9 @@
 #define E1000_MAX_RXD			4096
 #define E1000_MIN_RXD			80
 
+#define E1000_MIN_ITR_USECS		10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS		10000 /* 100    irq/sec */
+
 /* Early Receive defines */
 #define E1000_ERT_2048			0x100
 
@@ -92,9 +102,11 @@
 	board_82571,
 	board_82572,
 	board_82573,
+	board_82574,
 	board_80003es2lan,
 	board_ich8lan,
 	board_ich9lan,
+	board_ich10lan,
 };
 
 struct e1000_queue_stats {
@@ -115,17 +127,17 @@
 	dma_addr_t dma;
 	struct sk_buff *skb;
 	union {
-		/* TX */
+		/* Tx */
 		struct {
 			unsigned long time_stamp;
 			u16 length;
 			u16 next_to_watch;
 		};
-		/* RX */
+		/* Rx */
 		/* arrays of page information for packet split */
 		struct e1000_ps_page *ps_pages;
 	};
-
+	struct page *page;
 };
 
 struct e1000_ring {
@@ -143,11 +155,33 @@
 	/* array of buffer information structs */
 	struct e1000_buffer *buffer_info;
 
+#ifdef CONFIG_E1000E_MSIX
+	char name[IFNAMSIZ + 5];
+	u32 ims_val;
+	u32 itr_val;
+	u16 itr_register;
+	int set_itr;
+
+#endif /* CONFIG_E1000E_MSIX */
 	struct sk_buff *rx_skb_top;
 
 	struct e1000_queue_stats stats;
 };
 
+#ifdef SIOCGMIIPHY
+/* PHY register snapshot values */
+struct e1000_phy_regs {
+	u16 bmcr;		/* basic mode control register    */
+	u16 bmsr;		/* basic mode status register     */
+	u16 advertise;		/* auto-negotiation advertisement */
+	u16 lpa;		/* link partner ability register  */
+	u16 expansion;		/* auto-negotiation expansion reg */
+	u16 ctrl1000;		/* 1000BASE-T control register    */
+	u16 stat1000;		/* 1000BASE-T status register     */
+	u16 estatus;		/* extended status register       */
+};
+#endif
+
 /* board specific private data structure */
 struct e1000_adapter {
 	struct timer_list watchdog_timer;
@@ -168,9 +202,6 @@
 
 	spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
 
-	/* this is still needed for 82571 and above */
-	atomic_t irq_sem;
-
 	/* track device up/down/testing state */
 	unsigned long state;
 
@@ -181,12 +212,14 @@
 	u16 rx_itr;
 
 	/*
-	 * TX
+	 * Tx
 	 */
 	struct e1000_ring *tx_ring /* One per active queue */
 						____cacheline_aligned_in_smp;
 
+#ifdef CONFIG_E1000E_NAPI
 	struct napi_struct napi;
+#endif
 
 	unsigned long tx_queue_len;
 	unsigned int restart_queue;
@@ -203,11 +236,11 @@
 	unsigned int total_rx_bytes;
 	unsigned int total_rx_packets;
 
-	/* TX stats */
+	/* Tx stats */
 	u64 tpt_old;
 	u64 colc_old;
-	u64 gotcl_old;
-	u32 gotcl;
+	u32 gotc;
+	u64 gotc_old;
 	u32 tx_timeout_count;
 	u32 tx_fifo_head;
 	u32 tx_head_addr;
@@ -215,11 +248,16 @@
 	u32 tx_dma_failed;
 
 	/*
-	 * RX
+	 * Rx
 	 */
+#ifdef CONFIG_E1000E_NAPI
 	bool (*clean_rx) (struct e1000_adapter *adapter,
 			  int *work_done, int work_to_do)
 						____cacheline_aligned_in_smp;
+#else
+	bool (*clean_rx) (struct e1000_adapter *adapter)
+						____cacheline_aligned_in_smp;
+#endif
 	void (*alloc_rx_buf) (struct e1000_adapter *adapter,
 			      int cleaned_count);
 	struct e1000_ring *rx_ring;
@@ -227,17 +265,19 @@
 	u32 rx_int_delay;
 	u32 rx_abs_int_delay;
 
-	/* RX stats */
+	/* Rx stats */
 	u64 hw_csum_err;
 	u64 hw_csum_good;
 	u64 rx_hdr_split;
-	u64 gorcl_old;
-	u32 gorcl;
+	u32 gorc;
+	u64 gorc_old;
 	u32 alloc_rx_buff_failed;
 	u32 rx_dma_failed;
 
 	unsigned int rx_ps_pages;
 	u16 rx_ps_bsize0;
+	u32 max_frame_size;
+	u32 min_frame_size;
 
 	/* OS defined structs */
 	struct net_device *netdev;
@@ -252,31 +292,41 @@
 	struct e1000_phy_info phy_info;
 	struct e1000_phy_stats phy_stats;
 
+#ifdef SIOCGMIIPHY
+	/* Snapshot of PHY registers */
+	struct e1000_phy_regs phy_regs;
+#endif
+
 	struct e1000_ring test_tx_ring;
 	struct e1000_ring test_rx_ring;
 	u32 test_icr;
 
 	u32 msg_enable;
+#ifdef CONFIG_E1000E_MSIX
+	struct msix_entry *msix_entries;
+	int int_mode;
+	u32 eiac_mask;
+#endif /* CONFIG_E1000E_MSIX */
 
 	u32 eeprom_wol;
 	u32 wol;
 	u32 pba;
 
-	u8 fc_autoneg;
+	bool fc_autoneg;
 
 	unsigned long led_status;
 
 	unsigned int flags;
+	u32 *config_space;
+	u32 stats_freq_us;		/* stats update freq (microseconds) */
 };
 
 struct e1000_info {
-	enum e1000_mac_type	mac;
+	e1000_mac_type		mac;
 	unsigned int		flags;
 	u32			pba;
-	s32			(*get_invariants)(struct e1000_adapter *);
-	struct e1000_mac_operations *mac_ops;
-	struct e1000_phy_operations *phy_ops;
-	struct e1000_nvm_operations *nvm_ops;
+	void			(*init_ops)(struct e1000_hw *);
+	s32			(*get_variants)(struct e1000_adapter *);
 };
 
 /* hardware capability, feature, and workaround flags */
@@ -289,8 +339,8 @@
 #define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
 #define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
 #define FLAG_HAS_ASPM                     (1 << 8)
-#define FLAG_HAS_STATS_ICR_ICT            (1 << 9)
-#define FLAG_HAS_STATS_PTC_PRC            (1 << 10)
+#define FLAG_IS_ICH                       (1 << 9)
+#define FLAG_HAS_MSIX                     (1 << 10)
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
 #define FLAG_IS_QUAD_PORT_A               (1 << 12)
 #define FLAG_IS_QUAD_PORT                 (1 << 13)
@@ -310,6 +360,9 @@
 #define FLAG_MSI_ENABLED                  (1 << 27)
 #define FLAG_RX_CSUM_ENABLED              (1 << 28)
 #define FLAG_TSO_FORCE                    (1 << 29)
+#define FLAG_MSI_TEST_FAILED              (1 << 30)
+#define FLAG_RX_RESTART_NOW               (1 << 31)
+
 
 #define E1000_RX_DESC_PS(R, i)	    \
 	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -334,180 +387,58 @@
 extern char e1000e_driver_name[];
 extern const char e1000e_driver_version[];
 
-extern void e1000e_check_options(struct e1000_adapter *adapter);
-extern void e1000e_set_ethtool_ops(struct net_device *netdev);
+extern void e1000_check_options(struct e1000_adapter *adapter);
+extern void e1000_set_ethtool_ops(struct net_device *netdev);
+#ifdef ETHTOOL_OPS_COMPAT
+extern int ethtool_ioctl(struct ifreq *ifr);
+#endif
 
-extern int e1000e_up(struct e1000_adapter *adapter);
-extern void e1000e_down(struct e1000_adapter *adapter);
-extern void e1000e_reinit_locked(struct e1000_adapter *adapter);
-extern void e1000e_reset(struct e1000_adapter *adapter);
-extern void e1000e_power_up_phy(struct e1000_adapter *adapter);
-extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter);
-extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
-extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
-extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
-extern void e1000e_update_stats(struct e1000_adapter *adapter);
+extern int e1000_up(struct e1000_adapter *adapter);
+extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reinit_locked(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
+extern int e1000_setup_rx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_rx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_update_stats(struct e1000_adapter *adapter);
+#ifdef CONFIG_E1000E_MSIX
+extern void e1000_set_interrupt_capability(struct e1000_adapter *adapter);
+extern void e1000_reset_interrupt_capability(struct e1000_adapter *adapter);
+#endif
 
 extern unsigned int copybreak;
 
-extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
-
-extern struct e1000_info e1000_82571_info;
-extern struct e1000_info e1000_82572_info;
-extern struct e1000_info e1000_82573_info;
-extern struct e1000_info e1000_ich8_info;
-extern struct e1000_info e1000_ich9_info;
-extern struct e1000_info e1000_es2_info;
-
-extern s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num);
-
-extern s32  e1000e_commit_phy(struct e1000_hw *hw);
-
-extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
-
-extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
-extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
-
-extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
-						 bool state);
-extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
-
-extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
-extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
-extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
-extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
-extern s32 e1000e_id_led_init(struct e1000_hw *hw);
-extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
-extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
-extern s32 e1000e_setup_link(struct e1000_hw *hw);
-extern void e1000e_clear_vfta(struct e1000_hw *hw);
-extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
-extern void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
-				       u8 *mc_addr_list, u32 mc_addr_count,
-				       u32 rar_used_count, u32 rar_count);
-extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
-extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
-extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
-extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
-extern void e1000e_config_collision_dist(struct e1000_hw *hw);
-extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
-extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
-extern s32 e1000e_blink_led(struct e1000_hw *hw);
-extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
-extern void e1000e_reset_adaptive(struct e1000_hw *hw);
-extern void e1000e_update_adaptive(struct e1000_hw *hw);
-
-extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_id(struct e1000_hw *hw);
-extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
-extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
-extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
-extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
-extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
-extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
-extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-			       u32 usec_interval, bool *success);
-extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
-extern s32 e1000e_check_downshift(struct e1000_hw *hw);
-
-static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
-{
-	return hw->phy.ops.reset_phy(hw);
-}
-
-static inline s32 e1000_check_reset_block(struct e1000_hw *hw)
-{
-	return hw->phy.ops.check_reset_block(hw);
-}
-
-static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return hw->phy.ops.read_phy_reg(hw, offset, data);
-}
-
-static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return hw->phy.ops.write_phy_reg(hw, offset, data);
-}
-
-static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
-{
-	return hw->phy.ops.get_cable_length(hw);
-}
-
-extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
-extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
-extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-extern s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
-extern void e1000e_release_nvm(struct e1000_hw *hw);
-extern void e1000e_reload_nvm(struct e1000_hw *hw);
-extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
-
-static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
-{
-	return hw->nvm.ops.validate_nvm(hw);
-}
-
-static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
+static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
 {
-	return hw->nvm.ops.update_nvm(hw);
+	return readl(hw->hw_addr + reg);
 }
 
-static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
 {
-	return hw->nvm.ops.read_nvm(hw, offset, words, data);
+	writel(val, hw->hw_addr + reg);
 }
+#define er32(reg)	E1000_READ_REG(hw, E1000_##reg)
+#define ew32(reg,val)	E1000_WRITE_REG(hw, E1000_##reg, (val))
+#define e1e_flush()	er32(STATUS)
 
-static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	return hw->nvm.ops.write_nvm(hw, offset, words, data);
-}
+extern void e1000_init_function_pointers_82571(struct e1000_hw *hw);
+extern void e1000_init_function_pointers_80003es2lan(struct e1000_hw *hw);
+extern void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw);
 
-static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
+static inline s32 e1000_read_mac_addr(struct e1000_hw *hw)
 {
-	return hw->phy.ops.get_phy_info(hw);
-}
+        if (hw->mac.ops.read_mac_addr)
+                return hw->mac.ops.read_mac_addr(hw);
 
-extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
-extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
-extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
-
-static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
-{
-	return readl(hw->hw_addr + reg);
+        return e1000_read_mac_addr_generic(hw);
 }
 
-static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
+static inline void e1000_power_up_phy(struct e1000_hw *hw)
 {
-	writel(val, hw->hw_addr + reg);
+	if(hw->phy.ops.power_up) 
+		hw->phy.ops.power_up(hw);
+	hw->mac.ops.setup_link(hw);
 }
 
 #endif /* _E1000_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_hw.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_hw.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_hw.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_hw.h	2008-06-23 18:27:32.000000000 +0200
@@ -0,0 +1,670 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+#include "e1000_regs.h"
+#include "e1000_defines.h"
+
+struct e1000_hw;
+
+#define E1000_DEV_ID_82571EB_COPPER           0x105E
+#define E1000_DEV_ID_82571EB_FIBER            0x105F
+#define E1000_DEV_ID_82571EB_SERDES           0x1060
+#define E1000_DEV_ID_82571EB_SERDES_DUAL      0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD      0x10DA
+#define E1000_DEV_ID_82571EB_QUAD_COPPER      0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER      0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER       0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP   0x10BC
+#define E1000_DEV_ID_82572EI_COPPER           0x107D
+#define E1000_DEV_ID_82572EI_FIBER            0x107E
+#define E1000_DEV_ID_82572EI_SERDES           0x107F
+#define E1000_DEV_ID_82572EI                  0x10B9
+#define E1000_DEV_ID_82573E                   0x108B
+#define E1000_DEV_ID_82573E_IAMT              0x108C
+#define E1000_DEV_ID_82573L                   0x109A
+#define E1000_DEV_ID_82574L                   0x10D3
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT   0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT   0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT   0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT   0x10BB
+#define E1000_DEV_ID_ICH8_IGP_M_AMT           0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT             0x104A
+#define E1000_DEV_ID_ICH8_IGP_C               0x104B
+#define E1000_DEV_ID_ICH8_IFE                 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT              0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G               0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M               0x104D
+#define E1000_DEV_ID_ICH9_IGP_M               0x10BF
+#define E1000_DEV_ID_ICH9_IGP_M_AMT           0x10F5
+#define E1000_DEV_ID_ICH9_IGP_M_V             0x10CB
+#define E1000_DEV_ID_ICH9_IGP_AMT             0x10BD
+#define E1000_DEV_ID_ICH9_BM                  0x10E5
+#define E1000_DEV_ID_ICH9_IGP_C               0x294C
+#define E1000_DEV_ID_ICH9_IFE                 0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT              0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G               0x10C2
+#define E1000_DEV_ID_ICH10_R_BM_LM            0x10CC
+#define E1000_DEV_ID_ICH10_R_BM_LF            0x10CD
+#define E1000_DEV_ID_ICH10_R_BM_V             0x10CE
+#define E1000_DEV_ID_ICH10_D_BM_LM            0x10DE
+#define E1000_DEV_ID_ICH10_D_BM_LF            0x10DF
+
+#define E1000_REVISION_0 0
+#define E1000_REVISION_1 1
+#define E1000_REVISION_2 2
+#define E1000_REVISION_3 3
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_0     0
+#define E1000_FUNC_1     1
+
+typedef enum {
+	e1000_undefined = 0,
+	e1000_82571,
+	e1000_82572,
+	e1000_82573,
+	e1000_82574,
+	e1000_80003es2lan,
+	e1000_ich8lan,
+	e1000_ich9lan,
+	e1000_ich10lan,
+	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+} e1000_mac_type;
+
+typedef enum {
+	e1000_media_type_unknown = 0,
+	e1000_media_type_copper = 1,
+	e1000_media_type_fiber = 2,
+	e1000_media_type_internal_serdes = 3,
+	e1000_num_media_types
+} e1000_media_type;
+
+typedef enum {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_none,
+	e1000_nvm_eeprom_spi,
+	e1000_nvm_eeprom_microwire,
+	e1000_nvm_flash_hw,
+	e1000_nvm_flash_sw
+} e1000_nvm_type;
+
+typedef enum {
+	e1000_nvm_override_none = 0,
+	e1000_nvm_override_spi_small,
+	e1000_nvm_override_spi_large,
+	e1000_nvm_override_microwire_small,
+	e1000_nvm_override_microwire_large
+} e1000_nvm_override;
+
+typedef enum {
+	e1000_phy_unknown = 0,
+	e1000_phy_none,
+	e1000_phy_m88,
+	e1000_phy_igp,
+	e1000_phy_igp_2,
+	e1000_phy_gg82563,
+	e1000_phy_igp_3,
+	e1000_phy_ife,
+	e1000_phy_bm,
+} e1000_phy_type;
+
+typedef enum {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix,
+	e1000_bus_type_pci_express,
+	e1000_bus_type_reserved
+} e1000_bus_type;
+
+typedef enum {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_120,
+	e1000_bus_speed_133,
+	e1000_bus_speed_2500,
+	e1000_bus_speed_5000,
+	e1000_bus_speed_reserved
+} e1000_bus_speed;
+
+typedef enum {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_pcie_x8 = 8,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+} e1000_bus_width;
+
+typedef enum {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+typedef enum {
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
+
+typedef enum {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+} e1000_fc_type;
+
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	u64 buffer_addr; /* Address of the descriptor's data buffer */
+	u16 length;      /* Length of data DMAed into data buffer */
+	u16 csum;        /* Packet checksum */
+	u8  status;      /* Descriptor status */
+	u8  errors;      /* Descriptor Errors */
+	u16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+	struct {
+		u64 buffer_addr;
+		u64 reserved;
+	} read;
+	struct {
+		struct {
+			u32 mrq;              /* Multiple Rx Queues */
+			union {
+				u32 rss;            /* RSS Hash */
+				struct {
+					u16 ip_id;  /* IP id */
+					u16 csum;   /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length;
+			u16 vlan;             /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+	struct {
+		/* one buffer for protocol header(s), three data buffers */
+		u64 buffer_addr[MAX_PS_BUFFERS];
+	} read;
+	struct {
+		struct {
+			u32 mrq;              /* Multiple Rx Queues */
+			union {
+				u32 rss;              /* RSS Hash */
+				struct {
+					u16 ip_id;    /* IP id */
+					u16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length0;          /* length of buffer 0 */
+			u16 vlan;             /* VLAN tag */
+		} middle;
+		struct {
+			u16 header_status;
+			u16 length[3];        /* length of buffers 1-3 */
+		} upper;
+		u64 reserved;
+	} wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	u64 buffer_addr;      /* Address of the descriptor's data buffer */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 cso;        /* Checksum offset */
+			u8 cmd;        /* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 css;        /* Checksum start */
+			u16 special;
+		} fields;
+	} upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		u32 ip_config;
+		struct {
+			u8 ipcss;      /* IP checksum start */
+			u8 ipcso;      /* IP checksum offset */
+			u16 ipcse;     /* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		u32 tcp_config;
+		struct {
+			u8 tucss;      /* TCP checksum start */
+			u8 tucso;      /* TCP checksum offset */
+			u16 tucse;     /* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	u32 cmd_and_length;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 hdr_len;    /* Header length */
+			u16 mss;       /* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	u64 buffer_addr;   /* Address of the descriptor's buffer address */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 typ_len_ext;
+			u8 cmd;
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 popts;      /* Packet Options */
+			u16 special;
+		} fields;
+	} upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	u64 crcerrs;
+	u64 algnerrc;
+	u64 symerrs;
+	u64 rxerrc;
+	u64 mpc;
+	u64 scc;
+	u64 ecol;
+	u64 mcc;
+	u64 latecol;
+	u64 colc;
+	u64 dc;
+	u64 tncrs;
+	u64 sec;
+	u64 cexterr;
+	u64 rlec;
+	u64 xonrxc;
+	u64 xontxc;
+	u64 xoffrxc;
+	u64 xofftxc;
+	u64 fcruc;
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc;
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mgprc;
+	u64 mgpdc;
+	u64 mgptc;
+	u64 tor;
+	u64 tot;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 tsctc;
+	u64 tsctfc;
+	u64 iac;
+	u64 icrxptc;
+	u64 icrxatc;
+	u64 ictxptc;
+	u64 ictxatc;
+	u64 ictxqec;
+	u64 ictxqmtc;
+	u64 icrxdmtc;
+	u64 icrxoc;
+	u64 cbtmpc;
+	u64 htdpmc;
+	u64 cbrdpc;
+	u64 cbrmpc;
+	u64 rpthc;
+	u64 hgptc;
+	u64 htcbdpc;
+	u64 hgorc;
+	u64 hgotc;
+	u64 lenerrs;
+	u64 scvpc;
+	u64 hrmpc;
+};
+
+struct e1000_phy_stats {
+	u32 idle_errors;
+	u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+	u32 signature;
+	u8  status;
+	u8  reserved0;
+	u16 vlan_id;
+	u32 reserved1;
+	u16 reserved2;
+	u8  reserved3;
+	u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+	u8 command_id;
+	u8 command_length;
+	u8 command_options;
+	u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+	struct e1000_host_command_header command_header;
+	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+	u8  command_id;
+	u8  checksum;
+	u16 reserved1;
+	u16 reserved2;
+	u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+	struct e1000_host_mng_command_header command_header;
+	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+#include "e1000_manage.h"
+
+struct e1000_mac_operations {
+	/* Function pointers for the MAC. */
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*blink_led)(struct e1000_hw *);
+	s32  (*check_for_link)(struct e1000_hw *);
+	bool (*check_mng_mode)(struct e1000_hw *hw);
+	s32  (*cleanup_led)(struct e1000_hw *);
+	void (*clear_hw_cntrs)(struct e1000_hw *);
+	void (*clear_vfta)(struct e1000_hw *);
+	s32  (*get_bus_info)(struct e1000_hw *);
+	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+	s32  (*led_on)(struct e1000_hw *);
+	s32  (*led_off)(struct e1000_hw *);
+	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32,
+	                            u32);
+	void (*remove_device)(struct e1000_hw *);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	s32  (*setup_link)(struct e1000_hw *);
+	s32  (*setup_physical_interface)(struct e1000_hw *);
+	s32  (*setup_led)(struct e1000_hw *);
+	void (*write_vfta)(struct e1000_hw *, u32, u32);
+	void (*mta_set)(struct e1000_hw *, u32);
+	void (*config_collision_dist)(struct e1000_hw*);
+	void (*rar_set)(struct e1000_hw*, u8*, u32);
+	s32  (*read_mac_addr)(struct e1000_hw*);
+	s32  (*validate_mdi_setting)(struct e1000_hw*);
+	s32  (*mng_host_if_write)(struct e1000_hw*, u8*, u16, u16, u8*);
+	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
+                      struct e1000_host_mng_command_header*);
+	s32  (*mng_enable_host_if)(struct e1000_hw*);
+	s32  (*wait_autoneg)(struct e1000_hw*);
+};
+
+struct e1000_phy_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*check_polarity)(struct e1000_hw *);
+	s32  (*check_reset_block)(struct e1000_hw *);
+	s32  (*commit)(struct e1000_hw *);
+	s32  (*force_speed_duplex)(struct e1000_hw *);
+	s32  (*get_cfg_done)(struct e1000_hw *hw);
+	s32  (*get_cable_length)(struct e1000_hw *);
+	s32  (*get_info)(struct e1000_hw *);
+	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
+	void (*release)(struct e1000_hw *);
+	s32  (*reset)(struct e1000_hw *);
+	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+	s32  (*write_reg)(struct e1000_hw *, u32, u16);
+	void (*power_up)(struct e1000_hw *);
+	void (*power_down)(struct e1000_hw *);
+};
+
+struct e1000_nvm_operations {
+	s32  (*init_params)(struct e1000_hw *);
+	s32  (*acquire)(struct e1000_hw *);
+	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
+	void (*release)(struct e1000_hw *);
+	void (*reload)(struct e1000_hw *);
+	s32  (*update)(struct e1000_hw *);
+	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
+	s32  (*validate)(struct e1000_hw *);
+	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	e1000_mac_type type;
+
+	u32 collision_delta;
+	u32 ledctl_default;
+	u32 ledctl_mode1;
+	u32 ledctl_mode2;
+	u32 mc_filter_type;
+	u32 tx_packet_delta;
+	u32 txcw;
+
+	u16 current_ifs_val;
+	u16 ifs_max_val;
+	u16 ifs_min_val;
+	u16 ifs_ratio;
+	u16 ifs_step_size;
+	u16 mta_reg_count;
+	u16 rar_entry_count;
+
+	u8  forced_speed_duplex;
+
+	bool adaptive_ifs;
+	bool arc_subsystem_valid;
+	bool asf_firmware_present;
+	bool autoneg;
+	bool autoneg_failed;
+	bool disable_av;
+	bool disable_hw_init_bits;
+	bool get_link_status;
+	bool ifs_params_forced;
+	bool in_ifs_mode;
+	bool report_tx_early;
+	bool serdes_has_link;
+	bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+	struct e1000_phy_operations ops;
+	e1000_phy_type type;
+
+	e1000_1000t_rx_status local_rx;
+	e1000_1000t_rx_status remote_rx;
+	e1000_ms_type ms_type;
+	e1000_ms_type original_ms_type;
+	e1000_rev_polarity cable_polarity;
+	e1000_smart_speed smart_speed;
+
+	u32 addr;
+	u32 id;
+	u32 reset_delay_us; /* in usec */
+	u32 revision;
+
+	e1000_media_type media_type;
+
+	u16 autoneg_advertised;
+	u16 autoneg_mask;
+	u16 cable_length;
+	u16 max_cable_length;
+	u16 min_cable_length;
+
+	u8 mdix;
+
+	bool disable_polarity_correction;
+	bool is_mdix;
+	bool polarity_correction;
+	bool reset_disable;
+	bool speed_downgraded;
+	bool autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+	e1000_nvm_type type;
+	e1000_nvm_override override;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+	u32 semaphore_delay;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
+struct e1000_bus_info {
+	e1000_bus_type type;
+	e1000_bus_speed speed;
+	e1000_bus_width width;
+
+	u32 snoop;
+
+	u16 func;
+	u16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+	u32 high_water;     /* Flow control high-water mark */
+	u32 low_water;      /* Flow control low-water mark */
+	u16 pause_time;     /* Flow control pause timer */
+	bool send_xon;      /* Flow control send XON */
+	bool strict_ieee;   /* Strict IEEE mode */
+	e1000_fc_type type; /* Type of flow control */
+	e1000_fc_type original_type;
+};
+
+struct e1000_hw {
+	void *back;
+	void *dev_spec;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+	unsigned long io_base;
+
+	struct e1000_mac_info  mac;
+	struct e1000_fc_info   fc;
+	struct e1000_phy_info  phy;
+	struct e1000_nvm_info  nvm;
+	struct e1000_bus_info  bus;
+	struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+	u32 dev_spec_size;
+
+	u16 device_id;
+	u16 subsystem_vendor_id;
+	u16 subsystem_device_id;
+	u16 vendor_id;
+
+	u8  revision_id;
+};
+
+#include "e1000_82571.h"
+#include "e1000_80003es2lan.h"
+#include "e1000_ich8lan.h"
+
+/* These functions must be implemented by drivers */
+s32  e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size);
+s32  e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+void e1000_free_dev_spec_struct(struct e1000_hw *hw);
+void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_ich8lan.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_ich8lan.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_ich8lan.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_ich8lan.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,2713 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_ich8lan
+ * e1000_ich9lan
+ */
+
+#include "e1000_hw.h"
+
+static s32  e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
+static s32  e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
+static s32  e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
+static s32  e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
+static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
+static s32  e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
+static s32  e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
+static s32  e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw);
+static s32  e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
+static s32  e1000_get_phy_info_ich8lan(struct e1000_hw *hw);
+static s32  e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
+                                            bool active);
+static s32  e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
+                                            bool active);
+static s32  e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
+                                   u16 words, u16 *data);
+static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
+                                    u16 words, u16 *data);
+static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
+static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
+static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
+                                            u16 *data);
+static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
+static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
+static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
+static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
+static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
+static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
+                                           u16 *speed, u16 *duplex);
+static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
+static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
+static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
+static s32  e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
+static s32  e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
+static s32  e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
+                                          u32 offset, u8* data);
+static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                          u8 size, u16* data);
+static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
+                                          u32 offset, u16 *data);
+static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+                                                 u32 offset, u8 byte);
+static s32  e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
+                                           u32 offset, u8 data);
+static s32  e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                           u8 size, u16 data);
+static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
+static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+	struct ich8_hsfsts {
+		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
+		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
+		u16 dael       :1; /* bit 2 Direct Access error Log */
+		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
+		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
+		u16 reserved1  :2; /* bit 13:6 Reserved */
+		u16 reserved2  :6; /* bit 13:6 Reserved */
+		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
+	} hsf_status;
+	u16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+	struct ich8_hsflctl {
+		u16 flcgo      :1;   /* 0 Flash Cycle Go */
+		u16 flcycle    :2;   /* 2:1 Flash Cycle */
+		u16 reserved   :5;   /* 7:3 Reserved  */
+		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
+		u16 flockdn    :6;   /* 15:10 Reserved */
+	} hsf_ctrl;
+	u16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+	struct ich8_flracc {
+		u32 grra      :8; /* 0:7 GbE region Read Access */
+		u32 grwa      :8; /* 8:15 GbE region Write Access */
+		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
+		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
+	} hsf_flregacc;
+	u16 regval;
+};
+
+struct e1000_shadow_ram {
+	u16  value;
+	bool modified;
+};
+
+struct e1000_dev_spec_ich8lan {
+	bool kmrn_lock_loss_workaround_enabled;
+	struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS];
+};
+
+/**
+ *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i = 0;
+
+	DEBUGFUNC("e1000_init_phy_params_ich8lan");
+
+	phy->addr                     = 1;
+	phy->reset_delay_us           = 100;
+
+	phy->ops.acquire              = e1000_acquire_swflag_ich8lan;
+	phy->ops.check_polarity       = e1000_check_polarity_ife_ich8lan;
+	phy->ops.check_reset_block    = e1000_check_reset_block_ich8lan;
+	phy->ops.force_speed_duplex   = e1000_phy_force_speed_duplex_ich8lan;
+	phy->ops.get_cable_length     = e1000_get_cable_length_igp_2;
+	phy->ops.get_cfg_done         = e1000_get_cfg_done_ich8lan;
+	phy->ops.get_info             = e1000_get_phy_info_ich8lan;
+	phy->ops.read_reg             = e1000_read_phy_reg_igp;
+	phy->ops.release              = e1000_release_swflag_ich8lan;
+	phy->ops.reset                = e1000_phy_hw_reset_ich8lan;
+	phy->ops.set_d0_lplu_state    = e1000_set_d0_lplu_state_ich8lan;
+	phy->ops.set_d3_lplu_state    = e1000_set_d3_lplu_state_ich8lan;
+	phy->ops.write_reg            = e1000_write_phy_reg_igp;
+	phy->ops.power_up             = e1000_power_up_phy_copper;
+	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
+
+	/*
+	 * We may need to do this twice - once for IGP and if that fails,
+	 * we'll set BM func pointers and try again
+	 */
+	ret_val = e1000_determine_phy_address(hw);
+	if (ret_val) {
+		phy->ops.write_reg = e1000_write_phy_reg_bm;
+		phy->ops.read_reg  = e1000_read_phy_reg_bm;
+		ret_val = e1000_determine_phy_address(hw);
+		if (ret_val) {
+			DEBUGOUT("Cannot determine PHY address. Erroring out\n");
+			goto out;
+		}
+	}
+
+	phy->id = 0;
+	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
+	       (i++ < 100)) {
+		msec_delay(1);
+		ret_val = e1000_get_phy_id(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Verify phy id */
+	switch (phy->id) {
+	case IGP03E1000_E_PHY_ID:
+		phy->type = e1000_phy_igp_3;
+		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy->type = e1000_phy_ife;
+		phy->autoneg_mask = E1000_ALL_NOT_GIG;
+		break;
+	case BME1000_E_PHY_ID:
+		phy->type = e1000_phy_bm;
+		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+		phy->ops.read_reg = e1000_read_phy_reg_bm;
+		phy->ops.write_reg = e1000_write_phy_reg_bm;
+		phy->ops.commit = e1000_phy_sw_reset_generic;
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific NVM parameters and function
+ *  pointers.
+ **/
+static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec;
+	u32 gfpreg, sector_base_addr, sector_end_addr;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i;
+
+	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
+
+	/* Can't read flash registers if the register set isn't mapped. */
+	if (!hw->flash_address) {
+		DEBUGOUT("ERROR: Flash registers not mapped\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	nvm->type               = e1000_nvm_flash_sw;
+
+	gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
+
+	/*
+	 * sector_X_addr is a "sector"-aligned address (4096 bytes)
+	 * Add 1 to sector_end_addr since this sector is included in
+	 * the overall size.
+	 */
+	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+	/* flash_base_addr is byte-aligned */
+	nvm->flash_base_addr    = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+	/*
+	 * find total size of the NVM, then cut in half since the total
+	 * size represents two separate NVM banks.
+	 */
+	nvm->flash_bank_size    = (sector_end_addr - sector_base_addr)
+	                          << FLASH_SECTOR_ADDR_SHIFT;
+	nvm->flash_bank_size    /= 2;
+	/* Adjust to word count */
+	nvm->flash_bank_size    /= sizeof(u16);
+
+	nvm->word_size          = E1000_SHADOW_RAM_WORDS;
+
+	dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec;
+
+	if (!dev_spec) {
+		DEBUGOUT("dev_spec pointer is set to NULL.\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/* Clear shadow ram */
+	for (i = 0; i < nvm->word_size; i++) {
+		dev_spec->shadow_ram[i].modified = false;
+		dev_spec->shadow_ram[i].value    = 0xFFFF;
+	}
+
+	/* Function Pointers */
+	nvm->ops.acquire       = e1000_acquire_swflag_ich8lan;
+	nvm->ops.read          = e1000_read_nvm_ich8lan;
+	nvm->ops.release       = e1000_release_swflag_ich8lan;
+	nvm->ops.update        = e1000_update_nvm_checksum_ich8lan;
+	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
+	nvm->ops.validate      = e1000_validate_nvm_checksum_ich8lan;
+	nvm->ops.write         = e1000_write_nvm_ich8lan;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific MAC parameters and function
+ *  pointers.
+ **/
+static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_init_mac_params_ich8lan");
+
+	/* Set media type function pointer */
+	hw->phy.media_type = e1000_media_type_copper;
+
+	/* Set mta register count */
+	mac->mta_reg_count = 32;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+	if (mac->type == e1000_ich8lan)
+		mac->rar_entry_count--;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid = true;
+
+	/* Function pointers */
+
+	/* bus type/speed/width */
+	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
+	/* reset */
+	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
+	/* hw initialization */
+	mac->ops.init_hw = e1000_init_hw_ich8lan;
+	/* link setup */
+	mac->ops.setup_link = e1000_setup_link_ich8lan;
+	/* physical interface setup */
+	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
+	/* check for link */
+	mac->ops.check_for_link = e1000_check_for_copper_link_generic;
+	/* check management mode */
+	mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
+	/* link info */
+	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
+	/* multicast address update */
+	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
+	/* setting MTA */
+	mac->ops.mta_set = e1000_mta_set_generic;
+	/* blink LED */
+	mac->ops.blink_led = e1000_blink_led_generic;
+	/* setup LED */
+	mac->ops.setup_led = e1000_setup_led_generic;
+	/* cleanup LED */
+	mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
+	/* turn on/off LED */
+	mac->ops.led_on = e1000_led_on_ich8lan;
+	mac->ops.led_off = e1000_led_off_ich8lan;
+	/* remove device */
+	mac->ops.remove_device = e1000_remove_device_generic;
+	/* clear hardware counters */
+	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
+
+	hw->dev_spec_size = sizeof(struct e1000_dev_spec_ich8lan);
+
+	/* Device-specific structure allocation */
+	ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size);
+	if (ret_val)
+		goto out;
+
+	/* Enable PCS Lock-loss workaround for ICH8 */
+	if (mac->type == e1000_ich8lan)
+		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
+
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific function pointers for PHY, MAC, and NVM.
+ **/
+void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
+
+	e1000_init_mac_ops_generic(hw);
+	e1000_init_nvm_ops_generic(hw);
+	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
+	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
+	hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
+}
+
+/**
+ *  e1000_acquire_swflag_ich8lan - Acquire software control flag
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquires the software control flag for performing NVM and PHY
+ *  operations.  This is a function pointer entry point only called by
+ *  read/write routines for the PHY and NVM parts.
+ **/
+static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
+
+	while (timeout) {
+		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+			break;
+		msec_delay_irq(1);
+		timeout--;
+	}
+
+	if (!timeout) {
+		DEBUGOUT("FW or HW has locked the resource for too long.\n");
+		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_swflag_ich8lan - Release software control flag
+ *  @hw: pointer to the HW structure
+ *
+ *  Releases the software control flag for performing NVM and PHY operations.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+	u32 extcnf_ctrl;
+
+	DEBUGFUNC("e1000_release_swflag_ich8lan");
+
+	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
+
+	return;
+}
+
+/**
+ *  e1000_check_mng_mode_ich8lan - Checks management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  This checks if the adapter has manageability enabled.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
+
+	fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+	return ((fwsm & E1000_FWSM_MODE_MASK) ==
+	        (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks if firmware is blocking the reset of the PHY.
+ *  This is a function pointer entry point only called by
+ *  reset routines.
+ **/
+static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	DEBUGFUNC("e1000_check_reset_block_ich8lan");
+
+	fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
+	                                        : E1000_BLK_PHY_RESET;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan");
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = e1000_phy_force_speed_duplex_igp(hw);
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IFE PMC: %X\n", data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			DEBUGOUT("Link taking longer than expected.\n");
+		}
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
+	s32 ret_val;
+	u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+	u16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
+
+	ret_val = e1000_phy_hw_reset_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the PHY from the NVM on ICH platforms.  This
+	 * is needed due to an issue where the NVM configuration is
+	 * not properly autoloaded after power transitions.
+	 * Therefore, after each PHY reset, we will load the
+	 * configuration data out of the NVM manually.
+	 */
+	if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
+		/* Check if SW needs configure the PHY */
+		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M))
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+		else
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+
+		data = E1000_READ_REG(hw, E1000_FEXTNVM);
+		if (!(data & sw_cfg_mask))
+			goto out;
+
+		/* Wait for basic configuration completes before proceeding*/
+		do {
+			data = E1000_READ_REG(hw, E1000_STATUS);
+			data &= E1000_STATUS_LAN_INIT_DONE;
+			usec_delay(100);
+		} while ((!data) && --loop);
+
+		/*
+		 * If basic configuration is incomplete before the above loop
+		 * count reaches 0, loading the configuration from NVM will
+		 * leave the PHY in a bad state possibly resulting in no link.
+		 */
+		if (loop == 0) {
+			DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
+		}
+
+		/* Clear the Init Done bit for the next init event */
+		data = E1000_READ_REG(hw, E1000_STATUS);
+		data &= ~E1000_STATUS_LAN_INIT_DONE;
+		E1000_WRITE_REG(hw, E1000_STATUS, data);
+
+		/*
+		 * Make sure HW does not configure LCD from PHY
+		 * extended configuration before SW configuration
+		 */
+		data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
+		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+			goto out;
+
+		cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
+		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+		if (!cnf_size)
+			goto out;
+
+		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+		/*
+		 * Configure LCD from extended configuration
+		 * region.
+		 */
+
+		/* cnf_base_addr is in DWORD */
+		word_addr = (u16)(cnf_base_addr << 1);
+
+		for (i = 0; i < cnf_size; i++) {
+			ret_val = nvm->ops.read(hw,
+			                        (word_addr + i * 2),
+			                        1,
+			                        &reg_data);
+			if (ret_val)
+				goto out;
+
+			ret_val = nvm->ops.read(hw,
+			                        (word_addr + i * 2 + 1),
+			                        1,
+			                        &reg_addr);
+			if (ret_val)
+				goto out;
+
+			/* Save off the PHY page for future writes. */
+			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+				phy_page = reg_data;
+				continue;
+			}
+
+			reg_addr |= phy_page;
+
+			ret_val = phy->ops.write_reg(hw,
+			                             (u32)reg_addr,
+			                             reg_data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
+ *  @hw: pointer to the HW structure
+ *
+ *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = -E1000_ERR_PHY_TYPE;
+
+	DEBUGFUNC("e1000_get_phy_info_ich8lan");
+
+	switch (hw->phy.type) {
+	case e1000_phy_ife:
+		ret_val = e1000_get_phy_info_ife_ich8lan(hw);
+		break;
+	case e1000_phy_igp_3:
+	case e1000_phy_bm:
+		ret_val = e1000_get_phy_info_igp(hw);
+		break;
+	default:
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
+ *  @hw: pointer to the HW structure
+ *
+ *  Populates "phy" structure with various feature states.
+ *  This function is only called by other family-specific
+ *  routines.
+ **/
+static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_get_phy_info_ife_ich8lan");
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+	if (ret_val)
+		goto out;
+	phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
+	                           ? false : true;
+
+	if (phy->polarity_correction) {
+		ret_val = e1000_check_polarity_ife_ich8lan(hw);
+		if (ret_val)
+			goto out;
+	} else {
+		/* Polarity is forced */
+		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+	}
+
+	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false;
+
+	/* The following parameters are undefined for 10/100 operation. */
+	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+	phy->local_rx = e1000_1000t_rx_status_undefined;
+	phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Polarity is determined on the polarity reversal feature being enabled.
+ *  This function is only called by other family-specific
+ *  routines.
+ **/
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("e1000_check_polarity_ife_ich8lan");
+
+	/*
+	 * Polarity is determined based on the reversal feature
+	 * being enabled.
+	 */
+	if (phy->polarity_correction) {
+		offset	= IFE_PHY_EXTENDED_STATUS_CONTROL;
+		mask	= IFE_PESC_POLARITY_REVERSED;
+	} else {
+		offset	= IFE_PHY_SPECIAL_CONTROL;
+		mask	= IFE_PSC_FORCE_POLARITY;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->cable_polarity = (phy_data & mask)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
+                                           bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 phy_ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
+
+	if (phy->type == e1000_phy_ife)
+		goto out;
+
+	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+	if (active) {
+		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+		/*
+		 * Call gig speed drop workaround on LPLU before accessing
+		 * any PHY registers
+		 */
+		if ((hw->mac.type == e1000_ich8lan) &&
+		    (hw->phy.type == e1000_phy_igp_3))
+			e1000_gig_downshift_workaround_ich8lan(hw);
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw,
+		                            IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw,
+		                             IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+		if (ret_val)
+			goto out;
+	} else {
+		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D3 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
+                                           bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 phy_ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
+
+	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+
+	if (!active) {
+		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+		/*
+		 * Call gig speed drop workaround on LPLU before accessing
+		 * any PHY registers
+		 */
+		if ((hw->mac.type == e1000_ich8lan) &&
+		    (hw->phy.type == e1000_phy_igp_3))
+			e1000_gig_downshift_workaround_ich8lan(hw);
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw,
+		                            IGP01E1000_PHY_PORT_CONFIG,
+		                            &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw,
+		                             IGP01E1000_PHY_PORT_CONFIG,
+		                             data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
+ *  @hw: pointer to the HW structure
+ *  @bank:  pointer to the variable that returns the active bank
+ *
+ *  Reads signature byte from the NVM using the flash access registers.
+ **/
+static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
+{
+	s32 ret_val = E1000_SUCCESS;
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	/* flash bank size is in words */
+	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
+	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
+	u8 bank_high_byte = 0;
+
+	if (hw->mac.type != e1000_ich10lan) {
+		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_SEC1VAL)
+			*bank = 1;
+		else
+			*bank = 0;
+	} else if (hw->dev_spec != NULL) {
+		/*
+		 * Make sure the signature for bank 0 is valid,
+		 * if not check for bank1
+		 */
+		e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte);
+		if ((bank_high_byte & 0xC0) == 0x80) {
+			*bank = 0;
+		} else {
+			/*
+			 * find if segment 1 is valid by verifying
+			 * bit 15:14 = 10b in word 0x13
+			 */
+			e1000_read_flash_byte_ich8lan(hw,
+			                              act_offset + bank1_offset,
+			                              &bank_high_byte);
+			
+			/* bank1 has a valid signature equivalent to SEC1V */
+			if ((bank_high_byte & 0xC0) == 0x80) {
+				*bank = 1;
+			} else {
+				DEBUGOUT("ERROR: EEPROM not present\n");
+				ret_val = -E1000_ERR_NVM;
+			}
+		}
+	} else {
+		DEBUGOUT("DEV SPEC is NULL\n");
+		ret_val = -E1000_ERR_NVM;
+	}
+	
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the word(s) to read.
+ *  @words: Size of data to read in words
+ *  @data: Pointer to the word(s) to read at offset.
+ *
+ *  Reads a word(s) from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+                                  u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec;
+	u32 act_offset;
+	s32 ret_val = E1000_SUCCESS;
+	u32 bank = 0;
+	u16 i, word;
+
+	DEBUGFUNC("e1000_read_nvm_ich8lan");
+
+	dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec;
+
+	if (!dev_spec) {
+		DEBUGOUT("dev_spec pointer is set to NULL.\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+	if (ret_val != E1000_SUCCESS)
+		goto out;
+
+	act_offset = (bank) ? nvm->flash_bank_size : 0;
+	act_offset += offset;
+
+	for (i = 0; i < words; i++) {
+		if ((dev_spec->shadow_ram) &&
+		    (dev_spec->shadow_ram[offset+i].modified)) {
+			data[i] = dev_spec->shadow_ram[offset+i].value;
+		} else {
+			ret_val = e1000_read_flash_word_ich8lan(hw,
+			                                        act_offset + i,
+			                                        &word);
+			if (ret_val)
+				break;
+			data[i] = word;
+		}
+	}
+
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_flash_cycle_init_ich8lan - Initialize flash
+ *  @hw: pointer to the HW structure
+ *
+ *  This function does initial flash setup so that a new read/write/erase cycle
+ *  can be started.
+ **/
+static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+	union ich8_hws_flash_status hsfsts;
+	s32 ret_val = -E1000_ERR_NVM;
+	s32 i = 0;
+
+	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
+
+	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+	/* Check if the flash descriptor is valid */
+	if (hsfsts.hsf_status.fldesvalid == 0) {
+		DEBUGOUT("Flash descriptor invalid.  "
+		         "SW Sequencing must be used.");
+		goto out;
+	}
+
+	/* Clear FCERR and DAEL in hw status by writing 1 */
+	hsfsts.hsf_status.flcerr = 1;
+	hsfsts.hsf_status.dael = 1;
+
+	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+
+	/*
+	 * Either we should have a hardware SPI cycle in progress
+	 * bit to check against, in order to start a new cycle or
+	 * FDONE bit should be changed in the hardware so that it
+	 * is 1 after hardware reset, which can then be used as an
+	 * indication whether a cycle is in progress or has been
+	 * completed.
+	 */
+
+	if (hsfsts.hsf_status.flcinprog == 0) {
+		/*
+		 * There is no cycle running at present,
+		 * so we can start a cycle.
+		 * Begin by setting Flash Cycle Done.
+		 */
+		hsfsts.hsf_status.flcdone = 1;
+		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+		ret_val = E1000_SUCCESS;
+	} else {
+		/*
+		 * Otherwise poll for sometime so the current
+		 * cycle has a chance to end before giving up.
+		 */
+		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+			                                      ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcinprog == 0) {
+				ret_val = E1000_SUCCESS;
+				break;
+			}
+			usec_delay(1);
+		}
+		if (ret_val == E1000_SUCCESS) {
+			/*
+			 * Successful in waiting for previous cycle to timeout,
+			 * now set the Flash Cycle Done.
+			 */
+			hsfsts.hsf_status.flcdone = 1;
+			E1000_WRITE_FLASH_REG16(hw,
+			                        ICH_FLASH_HSFSTS,
+			                        hsfsts.regval);
+		} else {
+			DEBUGOUT("Flash controller busy, cannot get access");
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ *  @hw: pointer to the HW structure
+ *  @timeout: maximum time to wait for completion
+ *
+ *  This function starts a flash cycle and waits for its completion.
+ **/
+static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
+{
+	union ich8_hws_flash_ctrl hsflctl;
+	union ich8_hws_flash_status hsfsts;
+	s32 ret_val = -E1000_ERR_NVM;
+	u32 i = 0;
+
+	DEBUGFUNC("e1000_flash_cycle_ich8lan");
+
+	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+	hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+	hsflctl.hsf_ctrl.flcgo = 1;
+	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+	/* wait till FDONE bit is set to 1 */
+	do {
+		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+		if (hsfsts.hsf_status.flcdone == 1)
+			break;
+		usec_delay(1);
+	} while (i++ < timeout);
+
+	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+		ret_val = E1000_SUCCESS;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_read_flash_word_ich8lan - Read word from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: offset to data location
+ *  @data: pointer to the location for storing the data
+ *
+ *  Reads the flash word at offset into data.  Offset is converted
+ *  to bytes before read.
+ **/
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+                                         u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_read_flash_word_ich8lan");
+
+	if (!data) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Must convert offset into bytes. */
+	offset <<= 1;
+
+	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_flash_byte_ich8lan - Read byte from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to read.
+ *  @data: Pointer to a byte to store the value read.
+ *
+ *  Reads a single byte from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+                                         u8* data)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 word = 0;
+
+	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+	if (ret_val)
+		goto out;
+
+	*data = (u8)word;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the byte or word to read.
+ *  @size: Size of data to read, 1=byte 2=word
+ *  @data: Pointer to the word to store the value read.
+ *
+ *  Reads a byte or word from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                         u8 size, u16* data)
+{
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	u32 flash_data = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+	u8 count = 0;
+
+	DEBUGFUNC("e1000_read_flash_data_ich8lan");
+
+	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+		goto out;
+
+	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+	                    hw->nvm.flash_base_addr;
+
+	do {
+		usec_delay(1);
+		/* Steps */
+		ret_val = e1000_flash_cycle_init_ich8lan(hw);
+		if (ret_val != E1000_SUCCESS)
+			break;
+
+		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+		hsflctl.hsf_ctrl.fldbcount = size - 1;
+		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+		ret_val = e1000_flash_cycle_ich8lan(hw,
+		                                ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+		/*
+		 * Check if FCERR is set to 1, if set to 1, clear it
+		 * and try the whole sequence a few more times, else
+		 * read in (shift in) the Flash Data0, the order is
+		 * least significant byte first msb to lsb
+		 */
+		if (ret_val == E1000_SUCCESS) {
+			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
+			if (size == 1) {
+				*data = (u8)(flash_data & 0x000000FF);
+			} else if (size == 2) {
+				*data = (u16)(flash_data & 0x0000FFFF);
+			}
+			break;
+		} else {
+			/*
+			 * If we've gotten here, then things are probably
+			 * completely hosed, but if the error condition is
+			 * detected, it won't hurt to give it another try...
+			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+			 */
+			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+			                                      ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcerr == 1) {
+				/* Repeat for some time before giving up. */
+				continue;
+			} else if (hsfsts.hsf_status.flcdone == 0) {
+				DEBUGOUT("Timeout error - flash cycle "
+				         "did not complete.");
+				break;
+			}
+		}
+	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the word(s) to write.
+ *  @words: Size of data to write in words
+ *  @data: Pointer to the word(s) to write at offset.
+ *
+ *  Writes a byte or word to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+                                   u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i;
+
+	DEBUGFUNC("e1000_write_nvm_ich8lan");
+
+	dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec;
+
+	if (!dev_spec) {
+		DEBUGOUT("dev_spec pointer is set to NULL.\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	for (i = 0; i < words; i++) {
+		dev_spec->shadow_ram[offset+i].modified = true;
+		dev_spec->shadow_ram[offset+i].value = data[i];
+	}
+
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  The NVM checksum is updated by calling the generic update_nvm_checksum,
+ *  which writes the checksum to the shadow ram.  The changes in the shadow
+ *  ram are then committed to the EEPROM by processing each bank at a time
+ *  checking for the modified bit and writing only the pending changes.
+ *  After a successful commit, the shadow ram is cleared and is ready for
+ *  future writes.
+ **/
+static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec;
+	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
+
+	dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec;
+
+	ret_val = e1000_update_nvm_checksum_generic(hw);
+	if (ret_val)
+		goto out;
+
+	if (nvm->type != e1000_nvm_flash_sw)
+		goto out;
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * We're writing to the opposite bank so if we're on bank 1,
+	 * write to bank 0 etc.  We also need to erase the segment that
+	 * is going to be written
+	 */
+	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+	if (ret_val != E1000_SUCCESS)
+		goto out;
+
+	if (bank == 0) {
+		new_bank_offset = nvm->flash_bank_size;
+		old_bank_offset = 0;
+		e1000_erase_flash_bank_ich8lan(hw, 1);
+	} else {
+		old_bank_offset = nvm->flash_bank_size;
+		new_bank_offset = 0;
+		e1000_erase_flash_bank_ich8lan(hw, 0);
+	}
+
+	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+		/*
+		 * Determine whether to write the value stored
+		 * in the other NVM bank or a modified value stored
+		 * in the shadow RAM
+		 */
+		if (dev_spec->shadow_ram[i].modified) {
+			data = dev_spec->shadow_ram[i].value;
+		} else {
+			e1000_read_flash_word_ich8lan(hw,
+			                              i + old_bank_offset,
+			                              &data);
+		}
+
+		/*
+		 * If the word is 0x13, then make sure the signature bits
+		 * (15:14) are 11b until the commit has completed.
+		 * This will allow us to write 10b which indicates the
+		 * signature is valid.  We want to do this after the write
+		 * has completed so that we don't mark the segment valid
+		 * while the write is still in progress
+		 */
+		if (i == E1000_ICH_NVM_SIG_WORD)
+			data |= E1000_ICH_NVM_SIG_MASK;
+
+		/* Convert offset to bytes. */
+		act_offset = (i + new_bank_offset) << 1;
+
+		usec_delay(100);
+		/* Write the bytes to the new bank. */
+		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+		                                               act_offset,
+		                                               (u8)data);
+		if (ret_val)
+			break;
+
+		usec_delay(100);
+		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+		                                          act_offset + 1,
+		                                          (u8)(data >> 8));
+		if (ret_val)
+			break;
+	}
+
+	/*
+	 * Don't bother writing the segment valid bits if sector
+	 * programming failed.
+	 */
+	if (ret_val) {
+		DEBUGOUT("Flash commit failed.\n");
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	/*
+	 * Finally validate the new segment by setting bit 15:14
+	 * to 10b in word 0x13 , this can be done without an
+	 * erase as well since these bits are 11 to start with
+	 * and we need to change bit 14 to 0b
+	 */
+	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+	e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+	data &= 0xBFFF;
+	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+	                                               act_offset * 2 + 1,
+	                                               (u8)(data >> 8));
+	if (ret_val) {
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	/*
+	 * And invalidate the previously valid segment by setting
+	 * its signature word (0x13) high_byte to 0b. This can be
+	 * done without an erase because flash erase sets all bits
+	 * to 1's. We can write 1's to 0's without an erase
+	 */
+	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+	if (ret_val) {
+		nvm->ops.release(hw);
+		goto out;
+	}
+
+	/* Great!  Everything worked, we can now clear the cached entries. */
+	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+		dev_spec->shadow_ram[i].modified = false;
+		dev_spec->shadow_ram[i].value = 0xFFFF;
+	}
+
+	nvm->ops.release(hw);
+
+	/*
+	 * Reload the EEPROM, or else modifications will not appear
+	 * until after the next adapter reset.
+	 */
+	nvm->ops.reload(hw);
+	msec_delay(10);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ *  If the bit is 0, that the EEPROM had been modified, but the checksum was
+ *  not calculated, in which case we need to calculate the checksum and set
+ *  bit 6.
+ **/
+static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
+
+	/*
+	 * Read 0x19 and check bit 6.  If this bit is 0, the checksum
+	 * needs to be fixed.  This bit is an indication that the NVM
+	 * was prepared by OEM software and did not calculate the
+	 * checksum...a likely scenario.
+	 */
+	ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & 0x40) == 0) {
+		data |= 0x40;
+		ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
+		if (ret_val)
+			goto out;
+		ret_val = hw->nvm.ops.update(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = e1000_validate_nvm_checksum_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the byte/word to read.
+ *  @size: Size of data to read, 1=byte 2=word
+ *  @data: The byte(s) to write to the NVM.
+ *
+ *  Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+                                          u8 size, u16 data)
+{
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	u32 flash_data = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+	u8 count = 0;
+
+	DEBUGFUNC("e1000_write_ich8_data");
+
+	if (size < 1 || size > 2 || data > size * 0xff ||
+	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
+		goto out;
+
+	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+	                    hw->nvm.flash_base_addr;
+
+	do {
+		usec_delay(1);
+		/* Steps */
+		ret_val = e1000_flash_cycle_init_ich8lan(hw);
+		if (ret_val != E1000_SUCCESS)
+			break;
+
+		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+		hsflctl.hsf_ctrl.fldbcount = size -1;
+		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+
+		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+		if (size == 1)
+			flash_data = (u32)data & 0x00FF;
+		else
+			flash_data = (u32)data;
+
+		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
+
+		/*
+		 * check if FCERR is set to 1 , if set to 1, clear it
+		 * and try the whole sequence a few more times else done
+		 */
+		ret_val = e1000_flash_cycle_ich8lan(hw,
+		                               ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+		if (ret_val == E1000_SUCCESS) {
+			break;
+		} else {
+			/*
+			 * If we're here, then things are most likely
+			 * completely hosed, but if the error condition
+			 * is detected, it won't hurt to give it another
+			 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+			 */
+			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+			                                      ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcerr == 1) {
+				/* Repeat for some time before giving up. */
+				continue;
+			} else if (hsfsts.hsf_status.flcdone == 0) {
+				DEBUGOUT("Timeout error - flash cycle "
+				         "did not complete.");
+				break;
+			}
+		}
+	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The index of the byte to read.
+ *  @data: The byte to write to the NVM.
+ *
+ *  Writes a single byte to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+                                          u8 data)
+{
+	u16 word = (u16)data;
+
+	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
+
+	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to write.
+ *  @byte: The byte to write to the NVM.
+ *
+ *  Writes a single byte to the NVM using the flash access registers.
+ *  Goes through a retry algorithm before giving up.
+ **/
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+                                                u32 offset, u8 byte)
+{
+	s32 ret_val;
+	u16 program_retries;
+
+	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
+
+	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+	if (ret_val == E1000_SUCCESS)
+		goto out;
+
+	for (program_retries = 0; program_retries < 100; program_retries++) {
+		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
+		usec_delay(100);
+		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+		if (ret_val == E1000_SUCCESS)
+			break;
+	}
+	if (program_retries == 100) {
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ *  @hw: pointer to the HW structure
+ *  @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ *  bank N is 4096 * N + flash_reg_addr.
+ **/
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	/* bank size is in 16bit words - adjust to bytes */
+	u32 flash_bank_size = nvm->flash_bank_size * 2;
+	s32  ret_val = E1000_SUCCESS;
+	s32  count = 0;
+	s32  j, iteration, sector_size;
+
+	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
+
+	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+	/*
+	 * Determine HW Sector size: Read BERASE bits of hw flash status
+	 * register
+	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
+	 *     consecutive sectors.  The start index for the nth Hw sector
+	 *     can be calculated as = bank * 4096 + n * 256
+	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+	 *     The start index for the nth Hw sector can be calculated
+	 *     as = bank * 4096
+	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+	 *     (ich9 only, otherwise error condition)
+	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+	 */
+	switch (hsfsts.hsf_status.berasesz) {
+	case 0:
+		/* Hw sector size 256 */
+		sector_size = ICH_FLASH_SEG_SIZE_256;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+		break;
+	case 1:
+		sector_size = ICH_FLASH_SEG_SIZE_4K;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+		break;
+	case 2:
+		if (hw->mac.type == e1000_ich9lan) {
+			sector_size = ICH_FLASH_SEG_SIZE_8K;
+			iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
+		} else {
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+		break;
+	case 3:
+		sector_size = ICH_FLASH_SEG_SIZE_64K;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+		break;
+	default:
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Start with the base address, then add the sector offset. */
+	flash_linear_addr = hw->nvm.flash_base_addr;
+	flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
+
+	for (j = 0; j < iteration ; j++) {
+		do {
+			/* Steps */
+			ret_val = e1000_flash_cycle_init_ich8lan(hw);
+			if (ret_val)
+				goto out;
+
+			/*
+			 * Write a value 11 (block Erase) in Flash
+			 * Cycle field in hw flash control
+			 */
+			hsflctl.regval = E1000_READ_FLASH_REG16(hw,
+			                                      ICH_FLASH_HSFCTL);
+			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+			E1000_WRITE_FLASH_REG16(hw,
+			                        ICH_FLASH_HSFCTL,
+			                        hsflctl.regval);
+
+			/*
+			 * Write the last 24 bits of an index within the
+			 * block into Flash Linear address field in Flash
+			 * Address.
+			 */
+			flash_linear_addr += (j * sector_size);
+			E1000_WRITE_FLASH_REG(hw,
+			                      ICH_FLASH_FADDR,
+			                      flash_linear_addr);
+
+			ret_val = e1000_flash_cycle_ich8lan(hw,
+			                       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+			if (ret_val == E1000_SUCCESS) {
+				break;
+			} else {
+				/*
+				 * Check if FCERR is set to 1.  If 1,
+				 * clear it and try the whole sequence
+				 * a few more times else Done
+				 */
+				hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+				                              ICH_FLASH_HSFSTS);
+				if (hsfsts.hsf_status.flcerr == 1) {
+					/*
+					 * repeat for some time before
+					 * giving up
+					 */
+					continue;
+				} else if (hsfsts.hsf_status.flcdone == 0)
+					goto out;
+			}
+		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_valid_led_default_ich8lan - Set the default LED settings
+ *  @hw: pointer to the HW structure
+ *  @data: Pointer to the LED settings
+ *
+ *  Reads the LED default settings from the NVM to data.  If the NVM LED
+ *  settings is all 0's or F's, set the LED default to a valid LED default
+ *  setting.
+ **/
+static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_valid_led_default_ich8lan");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 ||
+	    *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT_ICH8LAN;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
+ *  @hw: pointer to the HW structure
+ *
+ *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ *  register, so the the bus width is hard coded.
+ **/
+static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_get_bus_info_ich8lan");
+
+	ret_val = e1000_get_bus_info_pcie_generic(hw);
+
+	/*
+	 * ICH devices are "PCI Express"-ish.  They have
+	 * a configuration space, but do not contain
+	 * PCI Express Capability registers, so bus width
+	 * must be hardcoded.
+	 */
+	if (bus->width == e1000_bus_width_unknown)
+		bus->width = e1000_bus_width_pcie_x1;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_hw_ich8lan - Reset the hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a full reset of the hardware which includes a reset of the PHY and
+ *  MAC.
+ **/
+static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+	u32 ctrl, icr, kab;
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_reset_hw_ich8lan");
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000_disable_pcie_master_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("PCI-E Master disable polling has failed.\n");
+	}
+
+	DEBUGOUT("Masking off all interrupts\n");
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+
+	/*
+	 * Disable the Transmit and Receive units.  Then delay to allow
+	 * any pending transactions to complete before we hit the MAC
+	 * with the global reset.
+	 */
+	E1000_WRITE_REG(hw, E1000_RCTL, 0);
+	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
+	E1000_WRITE_FLUSH(hw);
+
+	msec_delay(10);
+
+	/* Workaround for ICH8 bit corruption issue in FIFO memory */
+	if (hw->mac.type == e1000_ich8lan) {
+		/* Set Tx and Rx buffer allocation to 8k apiece. */
+		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
+		/* Set Packet Buffer Size to 16k. */
+		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
+	}
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
+		/*
+		 * PHY HW reset requires MAC CORE reset at the same
+		 * time to make sure the interface between MAC and the
+		 * external PHY is reset.
+		 */
+		ctrl |= E1000_CTRL_PHY_RST;
+	}
+	ret_val = e1000_acquire_swflag_ich8lan(hw);
+	DEBUGOUT("Issuing a global reset to ich8lan");
+	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
+	msec_delay(20);
+
+	ret_val = e1000_get_auto_rd_done_generic(hw);
+	if (ret_val) {
+		/*
+		 * When auto config read does not complete, do not
+		 * return with an error. This can happen in situations
+		 * where there is no eeprom and prevents getting link.
+		 */
+		DEBUGOUT("Auto Read Done did not complete\n");
+	}
+
+	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	icr = E1000_READ_REG(hw, E1000_ICR);
+
+	kab = E1000_READ_REG(hw, E1000_KABGTXD);
+	kab |= E1000_KABGTXD_BGSQLBIAS;
+	E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_ich8lan - Initialize the hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  Prepares the hardware for transmit and receive by doing the following:
+ *   - initialize hardware bits
+ *   - initialize LED identification
+ *   - setup receive address registers
+ *   - setup flow control
+ *   - setup transmit descriptors
+ *   - clear statistics
+ **/
+static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl_ext, txdctl, snoop;
+	s32 ret_val;
+	u16 i;
+
+	DEBUGFUNC("e1000_init_hw_ich8lan");
+
+	e1000_initialize_hw_bits_ich8lan(hw);
+
+	/* Initialize identification LED */
+	ret_val = e1000_id_led_init_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Setup the receive address. */
+	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	DEBUGOUT("Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = mac->ops.setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy for both queues */
+	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+		 E1000_TXDCTL_FULL_TX_DESC_WB;
+	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
+	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+		 E1000_TXDCTL_FULL_TX_DESC_WB;
+	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
+
+	/*
+	 * ICH8 has opposite polarity of no_snoop bits.
+	 * By default, we should use snoop behavior.
+	 */
+	if (mac->type == e1000_ich8lan)
+		snoop = PCIE_ICH8_SNOOP_ALL;
+	else
+		snoop = (u32)~(PCIE_NO_SNOOP_ALL);
+	e1000_set_pcie_no_snoop_generic(hw, snoop);
+
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_ich8lan(hw);
+
+	return ret_val;
+}
+/**
+ *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets/Clears required hardware bits necessary for correctly setting up the
+ *  hardware for transmit and receive.
+ **/
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
+
+	if (hw->mac.disable_hw_init_bits)
+		goto out;
+
+	/* Extended Device Control */
+	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
+
+	/* Transmit Descriptor Control 0 */
+	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
+	reg |= (1 << 22);
+	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = E1000_READ_REG(hw, E1000_TARC(0));
+	if (hw->mac.type == e1000_ich8lan)
+		reg |= (1 << 28) | (1 << 29);
+	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = E1000_READ_REG(hw, E1000_TARC(1));
+	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
+		reg &= ~(1 << 28);
+	else
+		reg |= (1 << 28);
+	reg |= (1 << 24) | (1 << 26) | (1 << 30);
+	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
+
+	/* Device Status */
+	if (hw->mac.type == e1000_ich8lan) {
+		reg = E1000_READ_REG(hw, E1000_STATUS);
+		reg &= ~(1 << 31);
+		E1000_WRITE_REG(hw, E1000_STATUS, reg);
+	}
+
+out:
+	return;
+}
+
+/**
+ *  e1000_setup_link_ich8lan - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_link_ich8lan");
+
+	if (hw->phy.ops.check_reset_block(hw))
+		goto out;
+
+	/*
+	 * ICH parts do not have a word in the NVM to determine
+	 * the default flow control setting, so we explicitly
+	 * set it to full.
+	 */
+	if (hw->fc.type == e1000_fc_default)
+		hw->fc.type = e1000_fc_full;
+
+	hw->fc.original_type = hw->fc.type;
+
+	DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc.type);
+
+	/* Continue to configure the copper link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the kumeran interface to the PHY to wait the appropriate time
+ *  when polling the PHY, then call the generic setup_copper_link to finish
+ *  configuring the copper link.
+ **/
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+	u16 reg_data;
+
+	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	/*
+	 * Set the mac to wait the maximum time between each iteration
+	 * and increase the max iterations when polling the phy;
+	 * this fixes erroneous timeouts at 10Mbps.
+	 */
+	ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 4),
+	                                       0xFFFF);
+	if (ret_val)
+		goto out;
+	ret_val = e1000_read_kmrn_reg_generic(hw, GG82563_REG(0x34, 9),
+	                                      &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= 0x3F;
+	ret_val = e1000_write_kmrn_reg_generic(hw, GG82563_REG(0x34, 9),
+	                                       reg_data);
+	if (ret_val)
+		goto out;
+
+	if (hw->phy.type == e1000_phy_igp_3) {
+		ret_val = e1000_copper_link_setup_igp(hw);
+		if (ret_val)
+			goto out;
+	} else if (hw->phy.type == e1000_phy_bm) {
+		ret_val = e1000_copper_link_setup_m88(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	if (hw->phy.type == e1000_phy_ife) {
+		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
+		                               &reg_data);
+		if (ret_val)
+			goto out;
+
+		reg_data &= ~IFE_PMC_AUTO_MDIX;
+
+		switch (hw->phy.mdix) {
+		case 1:
+			reg_data &= ~IFE_PMC_FORCE_MDIX;
+			break;
+		case 2:
+			reg_data |= IFE_PMC_FORCE_MDIX;
+			break;
+		case 0:
+		default:
+			reg_data |= IFE_PMC_AUTO_MDIX;
+			break;
+		}
+		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
+		                                reg_data);
+		if (ret_val)
+			goto out;
+	}
+	ret_val = e1000_setup_copper_link_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to store current link speed
+ *  @duplex: pointer to store the current link duplex
+ *
+ *  Calls the generic get_speed_and_duplex to retrieve the current link
+ *  information and then calls the Kumeran lock loss workaround for links at
+ *  gigabit speeds.
+ **/
+static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
+                                          u16 *duplex)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
+
+	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
+	if (ret_val)
+		goto out;
+
+	if ((hw->mac.type == e1000_ich8lan) &&
+	    (hw->phy.type == e1000_phy_igp_3) &&
+	    (*speed == SPEED_1000)) {
+		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ *  @hw: pointer to the HW structure
+ *
+ *  Work-around for 82566 Kumeran PCS lock loss:
+ *  On link status change (i.e. PCI reset, speed change) and link is up and
+ *  speed is gigabit-
+ *    0) if workaround is optionally disabled do nothing
+ *    1) wait 1ms for Kumeran link to come up
+ *    2) check Kumeran Diagnostic register PCS lock loss bit
+ *    3) if not set the link is locked (all is good), otherwise...
+ *    4) reset the PHY
+ *    5) repeat up to 10 times
+ *  Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec;
+	u32 phy_ctrl;
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, data;
+	bool link;
+
+	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
+
+	dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec;
+
+	if (!dev_spec) {
+		DEBUGOUT("dev_spec pointer is set to NULL.\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
+		goto out;
+
+	/*
+	 * Make sure link is up before proceeding.  If not just return.
+	 * Attempting this while link is negotiating fouled up link
+	 * stability
+	 */
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (!link) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	for (i = 0; i < 10; i++) {
+		/* read once to clear */
+		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
+		if (ret_val)
+			goto out;
+		/* and again to get new status */
+		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
+		if (ret_val)
+			goto out;
+
+		/* check for PCS lock */
+		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
+			ret_val = E1000_SUCCESS;
+			goto out;
+		}
+
+		/* Issue PHY reset */
+		hw->phy.ops.reset(hw);
+		msec_delay_irq(5);
+	}
+	/* Disable GigE link negotiation */
+	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+	             E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+
+	/*
+	 * Call gig speed drop workaround on Gig disable before accessing
+	 * any PHY registers
+	 */
+	e1000_gig_downshift_workaround_ich8lan(hw);
+
+	/* unable to acquire PCS lock */
+	ret_val = -E1000_ERR_PHY;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
+ *  @hw: pointer to the HW structure
+ *  @state: boolean value used to set the current Kumeran workaround state
+ *
+ *  If ICH8, set the current Kumeran workaround state (enabled - true
+ *  /disabled - false).
+ **/
+void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+                                                 bool state)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec;
+
+	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
+
+	if (hw->mac.type != e1000_ich8lan) {
+		DEBUGOUT("Workaround applies to ICH8 only.\n");
+		goto out;
+	}
+
+	dev_spec = (struct e1000_dev_spec_ich8lan *)hw->dev_spec;
+
+	if (!dev_spec) {
+		DEBUGOUT("dev_spec pointer is set to NULL.\n");
+		goto out;
+	}
+
+	dev_spec->kmrn_lock_loss_workaround_enabled = state;
+
+out:
+	return;
+}
+
+/**
+ *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ *  @hw: pointer to the HW structure
+ *
+ *  Workaround for 82566 power-down on D3 entry:
+ *    1) disable gigabit link
+ *    2) write VR power-down enable
+ *    3) read it back
+ *  Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+	u32 reg;
+	u16 data;
+	u8  retry = 0;
+
+	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
+
+	if (hw->phy.type != e1000_phy_igp_3)
+		goto out;
+
+	/* Try the workaround twice (if needed) */
+	do {
+		/* Disable link */
+		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
+		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+		        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
+
+		/*
+		 * Call gig speed drop workaround on Gig disable before
+		 * accessing any PHY registers
+		 */
+		if (hw->mac.type == e1000_ich8lan)
+			e1000_gig_downshift_workaround_ich8lan(hw);
+
+		/* Write VR power-down enable */
+		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
+		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		hw->phy.ops.write_reg(hw,
+		                   IGP3_VR_CTRL,
+		                   data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+		/* Read it back and test */
+		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
+		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+			break;
+
+		/* Issue PHY reset and repeat at most one more time */
+		reg = E1000_READ_REG(hw, E1000_CTRL);
+		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
+		retry++;
+	} while (retry);
+
+out:
+	return;
+}
+
+/**
+ *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ *  @hw: pointer to the HW structure
+ *
+ *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ *  LPLU, Gig disable, MDIC PHY reset):
+ *    1) Set Kumeran Near-end loopback
+ *    2) Clear Kumeran Near-end loopback
+ *  Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 reg_data;
+
+	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
+
+	if ((hw->mac.type != e1000_ich8lan) ||
+	    (hw->phy.type != e1000_phy_igp_3))
+		goto out;
+
+	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+	                                      &reg_data);
+	if (ret_val)
+		goto out;
+	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
+	                                       reg_data);
+	if (ret_val)
+		goto out;
+	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+	ret_val = e1000_write_kmrn_reg_generic(hw,
+	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
+	                                       reg_data);
+out:
+	return;
+}
+
+/**
+ *  e1000_disable_gig_wol_ich8lan - disable gig during WoL
+ *  @hw: pointer to the HW structure
+ *
+ *  During S0 to Sx transition, it is possible the link remains at gig
+ *  instead of negotiating to a lower speed.  Before going to Sx, set
+ *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
+ *  to a lower speed.
+ *
+ *  Should only be called for ICH9 and ICH10 devices.
+ **/
+void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
+{
+	u32 phy_ctrl;
+
+	if ((hw->mac.type == e1000_ich10lan) ||
+	    (hw->mac.type == e1000_ich9lan)) {
+		phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
+		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
+		            E1000_PHY_CTRL_GBE_DISABLE;
+		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
+	}
+
+	return;
+}
+
+/**
+ *  e1000_cleanup_led_ich8lan - Restore the default LED operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the LED back to the default configuration.
+ **/
+static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_cleanup_led_ich8lan");
+
+	if (hw->phy.type == e1000_phy_ife)
+		ret_val = hw->phy.ops.write_reg(hw,
+		                              IFE_PHY_SPECIAL_CONTROL_LED,
+		                              0);
+	else
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_led_on_ich8lan - Turn LEDs on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn on the LEDs.
+ **/
+static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_led_on_ich8lan");
+
+	if (hw->phy.type == e1000_phy_ife)
+		ret_val = hw->phy.ops.write_reg(hw,
+		                IFE_PHY_SPECIAL_CONTROL_LED,
+		                (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+	else
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_led_off_ich8lan - Turn LEDs off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn off the LEDs.
+ **/
+static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_led_off_ich8lan");
+
+	if (hw->phy.type == e1000_phy_ife)
+		ret_val = hw->phy.ops.write_reg(hw,
+		               IFE_PHY_SPECIAL_CONTROL_LED,
+		               (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+	else
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cfg_done_ich8lan - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 bank = 0;
+
+	e1000_get_cfg_done_generic(hw);
+
+	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
+	if (hw->mac.type != e1000_ich10lan) {
+		if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
+    		    (hw->phy.type == e1000_phy_igp_3)) {
+			e1000_phy_init_script_igp3(hw);
+		}
+	} else {
+		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
+			/* Maybe we should do a basic Boazman config */
+			DEBUGOUT("EEPROM not present\n");
+			ret_val = -E1000_ERR_CONFIG;
+		}
+	}
+
+	return ret_val;
+}
+
+/**
+ * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, remove the link.
+ **/
+static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_mac_info *mac = &hw->mac;
+
+	/* If the management interface is not enabled, then power down */
+	if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
+		e1000_power_down_phy_copper(hw);
+
+	return;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears hardware counters specific to the silicon family and calls
+ *  clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
+{
+	volatile u32 temp;
+
+	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
+
+	e1000_clear_hw_cntrs_base_generic(hw);
+
+	temp = E1000_READ_REG(hw, E1000_ALGNERRC);
+	temp = E1000_READ_REG(hw, E1000_RXERRC);
+	temp = E1000_READ_REG(hw, E1000_TNCRS);
+	temp = E1000_READ_REG(hw, E1000_CEXTERR);
+	temp = E1000_READ_REG(hw, E1000_TSCTC);
+	temp = E1000_READ_REG(hw, E1000_TSCTFC);
+
+	temp = E1000_READ_REG(hw, E1000_MGTPRC);
+	temp = E1000_READ_REG(hw, E1000_MGTPDC);
+	temp = E1000_READ_REG(hw, E1000_MGTPTC);
+
+	temp = E1000_READ_REG(hw, E1000_IAC);
+	temp = E1000_READ_REG(hw, E1000_ICRXOC);
+}
+
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_ich8lan.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_ich8lan.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_ich8lan.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_ich8lan.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,128 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_ICH8LAN_H_
+#define _E1000_ICH8LAN_H_
+
+#define ICH_FLASH_GFPREG                 0x0000
+#define ICH_FLASH_HSFSTS                 0x0004
+#define ICH_FLASH_HSFCTL                 0x0006
+#define ICH_FLASH_FADDR                  0x0008
+#define ICH_FLASH_FDATA0                 0x0010
+
+#define ICH_FLASH_READ_COMMAND_TIMEOUT   500
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT  500
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT  3000000
+#define ICH_FLASH_LINEAR_ADDR_MASK       0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT     10
+
+#define ICH_CYCLE_READ                   0
+#define ICH_CYCLE_WRITE                  2
+#define ICH_CYCLE_ERASE                  3
+
+#define FLASH_GFPREG_BASE_MASK           0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT          12
+
+#define E1000_SHADOW_RAM_WORDS           2048
+
+#define ICH_FLASH_SEG_SIZE_256           256
+#define ICH_FLASH_SEG_SIZE_4K            4096
+#define ICH_FLASH_SEG_SIZE_8K            8192
+#define ICH_FLASH_SEG_SIZE_64K           65536
+#define ICH_FLASH_SECTOR_SIZE            4096
+
+#define ICH_FLASH_REG_MAPSIZE            0x00A0
+
+#define E1000_ICH_FWSM_RSPCIPHY          0x00000040 /* Reset PHY on PCI Reset */
+#define E1000_ICH_FWSM_DISSW             0x10000000 /* FW Disables SW Writes */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID          0x00008000
+
+#define E1000_ICH_MNG_IAMT_MODE          0x2
+
+#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
+                                 (ID_LED_DEF1_OFF2 <<  8) | \
+                                 (ID_LED_DEF1_ON2  <<  4) | \
+                                 (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD           0x13
+#define E1000_ICH_NVM_SIG_MASK           0xC000
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT      1500
+
+#define E1000_FEXTNVM_SW_CONFIG        1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
+
+#define PCIE_ICH8_SNOOP_ALL   PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES            7
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+                           ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG  PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL    PHY_REG(776, 18) /* Voltage Regulator Control */
+#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */
+#define IGP3_PM_CTRL    PHY_REG(769, 20) /* Power Management Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS         0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN           0x0200
+#define IGP3_PM_CTRL_FORCE_PWR_DOWN          0x0020
+
+/*
+ * Additional interrupts need to be handled for ICH family:
+ *  DSW = The FW changed the status of the DISSW bit in FWSM
+ *  PHYINT = The LAN connected device generates an interrupt
+ *  EPRST = Manageability reset event
+ */
+#define IMS_ICH_ENABLE_MASK (\
+    E1000_IMS_DSW   | \
+    E1000_IMS_PHYINT | \
+    E1000_IMS_EPRST)
+
+/* Additional interrupt register bit definitions */
+#define E1000_ICR_LSECPNC       0x00004000          /* PN threshold - client */
+#define E1000_IMS_LSECPNC       E1000_ICR_LSECPNC   /* PN threshold - client */
+#define E1000_ICS_LSECPNC       E1000_ICR_LSECPNC   /* PN threshold - client */
+
+/* Security Processing bit Indication */
+#define E1000_RXDEXT_LINKSEC_STATUS_LSECH       0x01000000
+#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK     0x60000000
+#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH  0x20000000
+#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000
+#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG      0x60000000
+
+
+void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+                                                 bool state);
+void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw);
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_mac.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_mac.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_mac.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_mac.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,1968 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000_hw.h"
+
+/**
+ *  e1000_init_mac_ops_generic - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000_init_mac_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	DEBUGFUNC("e1000_init_mac_ops_generic");
+
+	/* General Setup */
+	mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
+	mac->ops.remove_device = e1000_remove_device_generic;
+	mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
+	/* LINK */
+	mac->ops.wait_autoneg = e1000_wait_autoneg_generic;
+	/* Management */
+	mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic;
+	mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic;
+	mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic;
+	/* VLAN, MC, etc. */
+	mac->ops.rar_set = e1000_rar_set_generic;
+	mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic;
+}
+
+/**
+ *  e1000_remove_device_generic - Free device specific structure
+ *  @hw: pointer to the HW structure
+ *
+ *  If a device specific structure was allocated, this function will
+ *  free it.
+ **/
+void e1000_remove_device_generic(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_remove_device_generic");
+
+	/* Freeing the dev_spec member of e1000_hw structure */
+	e1000_free_dev_spec_struct(hw);
+}
+
+/**
+ *  e1000_get_bus_info_pcie_generic - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	s32 ret_val;
+	u32 status;
+	u16 pcie_link_status, pci_header_type;
+
+	DEBUGFUNC("e1000_get_bus_info_pcie_generic");
+
+	bus->type = e1000_bus_type_pci_express;
+	bus->speed = e1000_bus_speed_2500;
+
+	ret_val = e1000_read_pcie_cap_reg(hw,
+	                                  PCIE_LINK_STATUS,
+	                                  &pcie_link_status);
+	if (ret_val)
+		bus->width = e1000_bus_width_unknown;
+	else
+		bus->width = (e1000_bus_width)((pcie_link_status &
+		                                PCIE_LINK_WIDTH_MASK) >>
+		                               PCIE_LINK_WIDTH_SHIFT);
+
+	e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
+	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		bus->func = (status & E1000_STATUS_FUNC_MASK)
+		            >> E1000_STATUS_FUNC_SHIFT;
+	} else {
+		bus->func = 0;
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_clear_vfta_generic - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void e1000_clear_vfta_generic(struct e1000_hw *hw)
+{
+	u32 offset;
+
+	DEBUGFUNC("e1000_clear_vfta_generic");
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
+		E1000_WRITE_FLUSH(hw);
+	}
+}
+
+/**
+ *  e1000_write_vfta_generic - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	DEBUGFUNC("e1000_write_vfta_generic");
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_init_rx_addrs_generic - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+
+	DEBUGFUNC("e1000_init_rx_addrs_generic");
+
+	/* Setup the receive address */
+	DEBUGOUT("Programming MAC Address into RAR[0]\n");
+
+	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
+	for (i = 1; i < rar_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0);
+		E1000_WRITE_FLUSH(hw);
+		E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0);
+		E1000_WRITE_FLUSH(hw);
+	}
+}
+
+/**
+ *  e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address.  If an
+ *  alternate MAC address is found it is saved in the hw struct and
+ *  programmed into RAR0 and the function returns success, otherwise the
+ *  function returns an error.
+ **/
+s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
+{
+	u32 i;
+	s32 ret_val = E1000_SUCCESS;
+	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+	u8 alt_mac_addr[ETH_ADDR_LEN];
+
+	DEBUGFUNC("e1000_check_alt_mac_addr_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+	                         &nvm_alt_mac_addr_offset);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (nvm_alt_mac_addr_offset == 0xFFFF) {
+		ret_val = -(E1000_NOT_IMPLEMENTED);
+		goto out;
+	}
+
+	if (hw->bus.func == E1000_FUNC_1)
+		nvm_alt_mac_addr_offset += ETH_ADDR_LEN/sizeof(u16);
+
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = nvm_alt_mac_addr_offset + (i >> 1);
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+
+		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+	}
+
+	/* if multicast bit is set, the alternate address will not be used */
+	if (alt_mac_addr[0] & 0x01) {
+		ret_val = -(E1000_NOT_IMPLEMENTED);
+		goto out;
+	}
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i];
+
+	hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_rar_set_generic - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	DEBUGFUNC("e1000_rar_set_generic");
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+	           ((u32) addr[1] << 8) |
+	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	/* If MAC address zero, no need to set the AV bit */
+	if (rar_low || rar_high) {
+		if (!hw->mac.disable_av)
+			rar_high |= E1000_RAH_AV;
+	}
+
+	E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
+	E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
+}
+
+/**
+ *  e1000_mta_set_generic - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta;
+
+	DEBUGFUNC("e1000_mta_set_generic");
+	/*
+	 * The MTA is a register array of 32-bit registers. It is
+	 * treated like an array of (32*mta_reg_count) bits.  We want to
+	 * set bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
+	 * mask to bits 31:5 of the hash value which gives us the
+	 * register we're modifying.  The hash bit within that register
+	 * is determined by the lower 5 bits of the hash value.
+	 */
+	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+	hash_bit = hash_value & 0x1F;
+
+	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_update_mc_addr_list_generic - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.
+ **/
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+                                       u8 *mc_addr_list, u32 mc_addr_count,
+                                       u32 rar_used_count, u32 rar_count)
+{
+	u32 hash_value;
+	u32 i;
+
+	DEBUGFUNC("e1000_update_mc_addr_list_generic");
+
+	/*
+	 * Load the first set of multicast addresses into the exact
+	 * filters (RAR).  If there are not enough to fill the RAR
+	 * array, clear the filters.
+	 */
+	for (i = rar_used_count; i < rar_count; i++) {
+		if (mc_addr_count) {
+			hw->mac.ops.rar_set(hw, mc_addr_list, i);
+			mc_addr_count--;
+			mc_addr_list += ETH_ADDR_LEN;
+		} else {
+			E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
+			E1000_WRITE_FLUSH(hw);
+			E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
+			E1000_WRITE_FLUSH(hw);
+		}
+	}
+
+	/* Clear the old settings from the MTA */
+	DEBUGOUT("Clearing MTA\n");
+	for (i = 0; i < hw->mac.mta_reg_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	/* Load any remaining multicast addresses into the hash table. */
+	for (; mc_addr_count > 0; mc_addr_count--) {
+		hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
+		DEBUGOUT1("Hash value = 0x%03X\n", hash_value);
+		hw->mac.ops.mta_set(hw, hash_value);
+		mc_addr_list += ETH_ADDR_LEN;
+	}
+}
+
+/**
+ *  e1000_hash_mc_addr_generic - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  e1000_mta_set_generic()
+ **/
+u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	DEBUGFUNC("e1000_hash_mc_addr_generic");
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/*
+	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask.
+	 */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	/*
+	 * The portion of the address that is used for the hash table
+	 * is determined by the mc_filter_type setting.
+	 * The algorithm is such that there is a total of 8 bits of shifting.
+	 * The bit_shift for a mc_filter_type of 0 represents the number of
+	 * left-shifts where the MSB of mc_addr[5] would still fall within
+	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
+	 * of 8 bits of shifting, then mc_addr[4] will shift right the
+	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+	 * cases are a variation of this algorithm...essentially raising the
+	 * number of bits to shift mc_addr[5] left, while still keeping the
+	 * 8-bit shifting total.
+	 *
+	 * For example, given the following Destination MAC Address and an
+	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+	 * we can see that the bit_shift for case 0 is 4.  These are the hash
+	 * values resulting from each mc_filter_type...
+	 * [0] [1] [2] [3] [4] [5]
+	 * 01  AA  00  12  34  56
+	 * LSB                 MSB
+	 *
+	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+	 */
+	switch (hw->mac.mc_filter_type) {
+		default:
+		case 0:
+			break;
+		case 1:
+			bit_shift += 1;
+			break;
+		case 2:
+			bit_shift += 2;
+			break;
+		case 3:
+			bit_shift += 4;
+			break;
+	}
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+	                          (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_base_generic - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw)
+{
+	volatile u32 temp;
+
+	DEBUGFUNC("e1000_clear_hw_cntrs_base_generic");
+
+	temp = E1000_READ_REG(hw, E1000_CRCERRS);
+	temp = E1000_READ_REG(hw, E1000_SYMERRS);
+	temp = E1000_READ_REG(hw, E1000_MPC);
+	temp = E1000_READ_REG(hw, E1000_SCC);
+	temp = E1000_READ_REG(hw, E1000_ECOL);
+	temp = E1000_READ_REG(hw, E1000_MCC);
+	temp = E1000_READ_REG(hw, E1000_LATECOL);
+	temp = E1000_READ_REG(hw, E1000_COLC);
+	temp = E1000_READ_REG(hw, E1000_DC);
+	temp = E1000_READ_REG(hw, E1000_SEC);
+	temp = E1000_READ_REG(hw, E1000_RLEC);
+	temp = E1000_READ_REG(hw, E1000_XONRXC);
+	temp = E1000_READ_REG(hw, E1000_XONTXC);
+	temp = E1000_READ_REG(hw, E1000_XOFFRXC);
+	temp = E1000_READ_REG(hw, E1000_XOFFTXC);
+	temp = E1000_READ_REG(hw, E1000_FCRUC);
+	temp = E1000_READ_REG(hw, E1000_GPRC);
+	temp = E1000_READ_REG(hw, E1000_BPRC);
+	temp = E1000_READ_REG(hw, E1000_MPRC);
+	temp = E1000_READ_REG(hw, E1000_GPTC);
+	temp = E1000_READ_REG(hw, E1000_GORCL);
+	temp = E1000_READ_REG(hw, E1000_GORCH);
+	temp = E1000_READ_REG(hw, E1000_GOTCL);
+	temp = E1000_READ_REG(hw, E1000_GOTCH);
+	temp = E1000_READ_REG(hw, E1000_RNBC);
+	temp = E1000_READ_REG(hw, E1000_RUC);
+	temp = E1000_READ_REG(hw, E1000_RFC);
+	temp = E1000_READ_REG(hw, E1000_ROC);
+	temp = E1000_READ_REG(hw, E1000_RJC);
+	temp = E1000_READ_REG(hw, E1000_TORL);
+	temp = E1000_READ_REG(hw, E1000_TORH);
+	temp = E1000_READ_REG(hw, E1000_TOTL);
+	temp = E1000_READ_REG(hw, E1000_TOTH);
+	temp = E1000_READ_REG(hw, E1000_TPR);
+	temp = E1000_READ_REG(hw, E1000_TPT);
+	temp = E1000_READ_REG(hw, E1000_MPTC);
+	temp = E1000_READ_REG(hw, E1000_BPTC);
+}
+
+/**
+ *  e1000_check_for_copper_link_generic - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_check_for_copper_link");
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	e1000_check_downshift_generic(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000_config_collision_dist_generic(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000_config_fc_after_link_up_generic(hw);
+	if (ret_val) {
+		DEBUGOUT("Error configuring flow control\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_fiber_link_generic - Check for link (Fiber)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_check_for_fiber_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), the cable is plugged in (we have signal),
+	 * and our link partner is not trying to auto-negotiate with us (we
+	 * are receiving idles or data), we need to force link up. We also
+	 * need to give auto-negotiation time to complete, in case the cable
+	 * was just plugged in. The autoneg_failed flag does this.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+	    (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_serdes_link_generic - Check for link (Serdes)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_check_for_serdes_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	rxcw = E1000_READ_REG(hw, E1000_RXCW);
+
+	/*
+	 * If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), and our link partner is not trying to
+	 * auto-negotiate with us (we are receiving idles or data),
+	 * we need to force link up. We also need to give auto-negotiation
+	 * time to complete.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			goto out;
+		}
+		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error configuring flow control\n");
+			goto out;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/*
+		 * If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
+		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = true;
+	} else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
+		/*
+		 * If we force link for non-auto-negotiation switch, check
+		 * link status based on MAC synchronization for internal
+		 * serdes media type.
+		 */
+		/* SYNCH bit and IV bit are sticky. */
+		usec_delay(10);
+		if (E1000_RXCW_SYNCH & E1000_READ_REG(hw, E1000_RXCW)) {
+			if (!(rxcw & E1000_RXCW_IV)) {
+				mac->serdes_has_link = true;
+				DEBUGOUT("SERDES: Link is up.\n");
+			}
+		} else {
+			mac->serdes_has_link = false;
+			DEBUGOUT("SERDES: Link is down.\n");
+		}
+	}
+
+	if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		mac->serdes_has_link = (status & E1000_STATUS_LU)
+					? true
+					: false;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_link_generic - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 e1000_setup_link_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_link_generic");
+
+	/*
+	 * In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+	if (hw->phy.ops.check_reset_block)
+		if (hw->phy.ops.check_reset_block(hw))
+			goto out;
+
+	/*
+	 * If flow control is set to default, set flow control based on
+	 * the EEPROM flow control settings.
+	 */
+	if (hw->fc.type == e1000_fc_default) {
+		ret_val = e1000_set_default_fc_generic(hw);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * We want to save off the original Flow Control configuration just
+	 * in case we get disconnected and then reconnected into a different
+	 * hub or switch with different Flow Control capabilities.
+	 */
+	hw->fc.original_type = hw->fc.type;
+
+	DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc.type);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
+	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = e1000_set_fc_watermarks_generic(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes
+ *  links.  Upon successful setup, poll for link.
+ **/
+s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/* Take the link out of reset */
+	ctrl &= ~E1000_CTRL_LRST;
+
+	e1000_config_collision_dist_generic(hw);
+
+	ret_val = e1000_commit_fc_settings_generic(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Since auto-negotiation is enabled, take the link out of reset (the
+	 * link will be in reset, because we previously reset the chip). This
+	 * will restart auto-negotiation.  If auto-negotiation is successful
+	 * then the link-up status bit will be set and the flow control enable
+	 * bits (RFCE and TFCE) will be set according to their negotiated value.
+	 */
+	DEBUGOUT("Auto-negotiation enabled\n");
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+	msec_delay(1);
+
+	/*
+	 * For these adapters, the SW definable pin 1 is set when the optics
+	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
+	 * indication.
+	 */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
+	    (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
+		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+	} else {
+		DEBUGOUT("No signal detected\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_collision_dist_generic - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void e1000_config_collision_dist_generic(struct e1000_hw *hw)
+{
+	u32 tctl;
+
+	DEBUGFUNC("e1000_config_collision_dist_generic");
+
+	tctl = E1000_READ_REG(hw, E1000_TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+	E1000_WRITE_FLUSH(hw);
+}
+
+/**
+ *  e1000_poll_fiber_serdes_link_generic - Poll for link up
+ *  @hw: pointer to the HW structure
+ *
+ *  Polls for link up by reading the status register, if link fails to come
+ *  up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 i, status;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
+
+	/*
+	 * If we have a signal (the cable is plugged in, or assumed true for
+	 * serdes media) then poll for a "Link-Up" indication in the Device
+	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
+	 * seconds (Auto-negotiation should complete in less than 500
+	 * milliseconds even if the other end is doing it in SW).
+	 */
+	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+		msec_delay(10);
+		status = E1000_READ_REG(hw, E1000_STATUS);
+		if (status & E1000_STATUS_LU)
+			break;
+	}
+	if (i == FIBER_LINK_UP_LIMIT) {
+		DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+		mac->autoneg_failed = 1;
+		/*
+		 * AutoNeg failed to achieve a link, so we'll call
+		 * mac->check_for_link. This routine will force the
+		 * link up if we detect a signal. This will allow us to
+		 * communicate with non-autonegotiating link partners.
+		 */
+		ret_val = hw->mac.ops.check_for_link(hw);
+		if (ret_val) {
+			DEBUGOUT("Error while checking for link\n");
+			goto out;
+		}
+		mac->autoneg_failed = 0;
+	} else {
+		mac->autoneg_failed = 0;
+		DEBUGOUT("Valid Link Found\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_commit_fc_settings_generic - Configure flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Write the flow control settings to the Transmit Config Word Register (TXCW)
+ *  base on the flow control settings in e1000_mac_info.
+ **/
+s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 txcw;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_commit_fc_settings_generic");
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the device accordingly.  If auto-negotiation is enabled, then
+	 * software will have to set the "PAUSE" bits to the correct value in
+	 * the Transmit Config Word Register (TXCW) and re-start auto-
+	 * negotiation.  However, if auto-negotiation is disabled, then
+	 * software will have to manually configure the two flow control enable
+	 * bits in the CTRL register.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames,
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames but we
+	 *          do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 */
+	switch (hw->fc.type) {
+	case e1000_fc_none:
+		/* Flow control completely disabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled and Tx Flow control is disabled
+		 * by a software over-ride. Since there really isn't a way to
+		 * advertise that we are capable of Rx Pause ONLY, we will
+		 * advertise that we support both symmetric and asymmetric RX
+		 * PAUSE.  Later, we will disable the adapter's ability to send
+		 * PAUSE frames.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+		break;
+	}
+
+	E1000_WRITE_REG(hw, E1000_TXCW, txcw);
+	mac->txcw = txcw;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_fc_watermarks_generic - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  transmission as well.
+ **/
+s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u32 fcrtl = 0, fcrth = 0;
+
+	DEBUGFUNC("e1000_set_fc_watermarks_generic");
+
+	/*
+	 * Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (hw->fc.type & e1000_fc_tx_pause) {
+		/*
+		 * We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = hw->fc.low_water;
+		if (hw->fc.send_xon)
+			fcrtl |= E1000_FCRTL_XONE;
+
+		fcrth = hw->fc.high_water;
+	}
+	E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
+	E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_set_default_fc_generic - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 nvm_data;
+
+	DEBUGFUNC("e1000_set_default_fc_generic");
+
+	/*
+	 * Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+		hw->fc.type = e1000_fc_none;
+	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+		 NVM_WORD0F_ASM_DIR)
+		hw->fc.type = e1000_fc_tx_pause;
+	else
+		hw->fc.type = e1000_fc_full;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_force_mac_fc_generic - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_force_mac_fc_generic");
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+
+	/*
+	 * Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "hw->fc.type" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *          frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          frames but we do not receive pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+	DEBUGOUT1("hw->fc.type = %u\n", hw->fc.type);
+
+	switch (hw->fc.type) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_fc_after_link_up_generic - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+	u16 speed, duplex;
+
+	DEBUGFUNC("e1000_config_fc_after_link_up_generic");
+
+	/*
+	 * Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if (mac->autoneg_failed) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes)
+			ret_val = e1000_force_mac_fc_generic(hw);
+	} else {
+		if (hw->phy.media_type == e1000_media_type_copper)
+			ret_val = e1000_force_mac_fc_generic(hw);
+	}
+
+	if (ret_val) {
+		DEBUGOUT("Error forcing flow control settings\n");
+		goto out;
+	}
+
+	/*
+	 * Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+		/*
+		 * Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		ret_val = phy->ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+		ret_val = phy->ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+			DEBUGOUT("Copper PHY and Auto Neg "
+			         "has not completed.\n");
+			goto out;
+		}
+
+		/*
+		 * The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (Address 4) and the Auto_Negotiation Base
+		 * Page Ability Register (Address 5) to determine how
+		 * flow control was negotiated.
+		 */
+		ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV,
+		                             &mii_nway_adv_reg);
+		if (ret_val)
+			goto out;
+		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY,
+		                             &mii_nway_lp_ability_reg);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Two bits in the Auto Negotiation Advertisement Register
+		 * (Address 4) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (Address 5) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
+		 *
+		 */
+		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+			/*
+			 * Now we need to check if the user selected Rx ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise RX
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF  the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.original_type == e1000_fc_full) {
+				hw->fc.type = e1000_fc_full;
+				DEBUGOUT("Flow Control = FULL.\r\n");
+			} else {
+				hw->fc.type = e1000_fc_rx_pause;
+				DEBUGOUT("Flow Control = "
+				         "RX PAUSE frames only.\r\n");
+			}
+		}
+		/*
+		 * For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.type = e1000_fc_tx_pause;
+			DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+		}
+		/*
+		 * For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.type = e1000_fc_rx_pause;
+			DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+		} else {
+			/*
+			 * Per the IEEE spec, at this point flow control
+			 * should be disabled.
+			 */
+			hw->fc.type = e1000_fc_none;
+			DEBUGOUT("Flow Control = NONE.\r\n");
+		}
+
+		/*
+		 * Now we need to do one last check...  If we auto-
+		 * negotiated to HALF DUPLEX, flow control should not be
+		 * enabled per IEEE 802.3 spec.
+		 */
+		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			DEBUGOUT("Error getting link speed and duplex\n");
+			goto out;
+		}
+
+		if (duplex == HALF_DUPLEX)
+			hw->fc.type = e1000_fc_none;
+
+		/*
+		 * Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		ret_val = e1000_force_mac_fc_generic(hw);
+		if (ret_val) {
+			DEBUGOUT("Error forcing flow control settings\n");
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
+                                              u16 *duplex)
+{
+	u32 status;
+
+	DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic");
+
+	status = E1000_READ_REG(hw, E1000_STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		DEBUGOUT("1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		DEBUGOUT("100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		DEBUGOUT("10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Sets the speed and duplex to gigabit full duplex (the only possible option)
+ *  for fiber/serdes links.
+ **/
+s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+                                                    u16 *speed, u16 *duplex)
+{
+	DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
+
+	*speed = SPEED_1000;
+	*duplex = FULL_DUPLEX;
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_hw_semaphore_generic - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 ret_val = E1000_SUCCESS;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	DEBUGFUNC("e1000_get_hw_semaphore_generic");
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		e1000_put_hw_semaphore_generic(hw);
+		DEBUGOUT("Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_put_hw_semaphore_generic - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	DEBUGFUNC("e1000_put_hw_semaphore_generic");
+
+	swsm = E1000_READ_REG(hw, E1000_SWSM);
+
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
+}
+
+/**
+ *  e1000_get_auto_rd_done_generic - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
+{
+	s32 i = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_get_auto_rd_done_generic");
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
+			break;
+		msec_delay(1);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		DEBUGOUT("Auto read by HW from NVM has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_valid_led_default_generic - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	DEBUGFUNC("e1000_valid_led_default_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_id_led_init_generic -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000_id_led_init_generic(struct e1000_hw * hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_mask = 0x000000FF;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+	u16 data, i, temp;
+	const u16 led_mask = 0x0F;
+
+	DEBUGFUNC("e1000_id_led_init_generic");
+
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & led_mask;
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_led_generic - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored.
+ **/
+s32 e1000_setup_led_generic(struct e1000_hw *hw)
+{
+	u32 ledctl;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_setup_led_generic");
+
+	if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
+		hw->mac.ledctl_default = ledctl;
+		/* Turn off LED0 */
+		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+		            E1000_LEDCTL_LED0_BLINK |
+		            E1000_LEDCTL_LED0_MODE_MASK);
+		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+		           E1000_LEDCTL_LED0_MODE_SHIFT);
+		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
+	} else if (hw->phy.media_type == e1000_media_type_copper) {
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_cleanup_led_generic - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 e1000_cleanup_led_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_cleanup_led_generic");
+
+	if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_blink_led_generic - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the LEDs which are set to be on.
+ **/
+s32 e1000_blink_led_generic(struct e1000_hw *hw)
+{
+	u32 ledctl_blink = 0;
+	u32 i;
+
+	DEBUGFUNC("e1000_blink_led_generic");
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		/* always blink LED0 for PCI-E fiber */
+		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+	} else {
+		/*
+		 * set the blink bit for each LED that's "on" (0x0E)
+		 * in ledctl_mode2
+		 */
+		ledctl_blink = hw->mac.ledctl_mode2;
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+				                 (i * 8));
+	}
+
+	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_led_on_generic - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+s32 e1000_led_on_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_led_on_generic");
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
+		break;
+	default:
+		break;
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_led_off_generic - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 e1000_led_off_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_led_off_generic");
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = E1000_READ_REG(hw, E1000_CTRL);
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
+		break;
+	default:
+		break;
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities
+ *  @hw: pointer to the HW structure
+ *  @no_snoop: bitmap of snoop events
+ *
+ *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
+{
+	u32 gcr;
+
+	DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	if (no_snoop) {
+		gcr = E1000_READ_REG(hw, E1000_GCR);
+		gcr &= ~(PCIE_NO_SNOOP_ALL);
+		gcr |= no_snoop;
+		E1000_WRITE_REG(hw, E1000_GCR, gcr);
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000_disable_pcie_master_generic - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_disable_pcie_master_generic");
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+
+	while (timeout) {
+		if (!(E1000_READ_REG(hw, E1000_STATUS) &
+		      E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		usec_delay(100);
+		timeout--;
+	}
+
+	if (!timeout) {
+		DEBUGOUT("Master requests are pending.\n");
+		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000_reset_adaptive_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_reset_adaptive_generic");
+
+	if (!mac->adaptive_ifs) {
+		DEBUGOUT("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if (!mac->ifs_params_forced) {
+		mac->current_ifs_val = 0;
+		mac->ifs_min_val = IFS_MIN;
+		mac->ifs_max_val = IFS_MAX;
+		mac->ifs_step_size = IFS_STEP;
+		mac->ifs_ratio = IFS_RATIO;
+	}
+
+	mac->in_ifs_mode = false;
+	E1000_WRITE_REG(hw, E1000_AIT, 0);
+out:
+	return;
+}
+
+/**
+ *  e1000_update_adaptive_generic - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void e1000_update_adaptive_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	DEBUGFUNC("e1000_update_adaptive_generic");
+
+	if (!mac->adaptive_ifs) {
+		DEBUGOUT("Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+			mac->in_ifs_mode = true;
+			if (mac->current_ifs_val < mac->ifs_max_val) {
+				if (!mac->current_ifs_val)
+					mac->current_ifs_val = mac->ifs_min_val;
+				else
+					mac->current_ifs_val +=
+						mac->ifs_step_size;
+				E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val);
+			}
+		}
+	} else {
+		if (mac->in_ifs_mode &&
+		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+			mac->current_ifs_val = 0;
+			mac->in_ifs_mode = false;
+			E1000_WRITE_REG(hw, E1000_AIT, 0);
+		}
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
+ *  set, which is forced to MDI mode only.
+ **/
+s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_validate_mdi_setting_generic");
+
+	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+		DEBUGOUT("Invalid MDI setting detected\n");
+		hw->phy.mdix = 1;
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register
+ *  @hw: pointer to the HW structure
+ *  @reg: 32bit register offset such as E1000_SCTL
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes an address/data control type register.  There are several of these
+ *  and they all have the format address << 8 | data and bit 31 is polled for
+ *  completion.
+ **/
+s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
+                                      u32 offset, u8 data)
+{
+	u32 i, regvalue = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_8bit_ctrl_reg_generic");
+
+	/* Set up the address and data */
+	regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
+	E1000_WRITE_REG(hw, reg, regvalue);
+
+	/* Poll the ready bit to see if the MDI read completed */
+	for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+		usec_delay(5);
+		regvalue = E1000_READ_REG(hw, reg);
+		if (regvalue & E1000_GEN_CTL_READY)
+			break;
+	}
+	if (!(regvalue & E1000_GEN_CTL_READY)) {
+		DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_mac.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_mac.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_mac.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_mac.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_MAC_H_
+#define _E1000_MAC_H_
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+void e1000_init_mac_ops_generic(struct e1000_hw *hw);
+s32  e1000_blink_led_generic(struct e1000_hw *hw);
+s32  e1000_check_for_copper_link_generic(struct e1000_hw *hw);
+s32  e1000_check_for_fiber_link_generic(struct e1000_hw *hw);
+s32  e1000_check_for_serdes_link_generic(struct e1000_hw *hw);
+s32  e1000_cleanup_led_generic(struct e1000_hw *hw);
+s32  e1000_commit_fc_settings_generic(struct e1000_hw *hw);
+s32  e1000_config_fc_after_link_up_generic(struct e1000_hw *hw);
+s32  e1000_disable_pcie_master_generic(struct e1000_hw *hw);
+s32  e1000_force_mac_fc_generic(struct e1000_hw *hw);
+s32  e1000_get_auto_rd_done_generic(struct e1000_hw *hw);
+s32  e1000_get_bus_info_pcie_generic(struct e1000_hw *hw);
+s32  e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
+s32  e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
+                                               u16 *duplex);
+s32  e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
+                                                     u16 *speed, u16 *duplex);
+s32  e1000_id_led_init_generic(struct e1000_hw *hw);
+s32  e1000_led_on_generic(struct e1000_hw *hw);
+s32  e1000_led_off_generic(struct e1000_hw *hw);
+void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
+	                               u8 *mc_addr_list, u32 mc_addr_count,
+	                               u32 rar_used_count, u32 rar_count);
+s32  e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
+s32  e1000_set_default_fc_generic(struct e1000_hw *hw);
+s32  e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
+s32  e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
+s32  e1000_setup_led_generic(struct e1000_hw *hw);
+s32  e1000_setup_link_generic(struct e1000_hw *hw);
+s32  e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
+s32  e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
+                                       u32 offset, u8 data);
+
+u32  e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
+
+void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
+void e1000_clear_vfta_generic(struct e1000_hw *hw);
+void e1000_config_collision_dist_generic(struct e1000_hw *hw);
+void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count);
+void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
+void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
+void e1000_put_hw_semaphore_generic(struct e1000_hw *hw);
+void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
+s32  e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
+void e1000_remove_device_generic(struct e1000_hw *hw);
+void e1000_reset_adaptive_generic(struct e1000_hw *hw);
+void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
+void e1000_update_adaptive_generic(struct e1000_hw *hw);
+void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_manage.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_manage.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_manage.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_manage.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,383 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000_hw.h"
+
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
+
+/**
+ *  e1000_calculate_checksum - Calculate checksum for buffer
+ *  @buffer: pointer to EEPROM
+ *  @length: size of EEPROM to calculate a checksum for
+ *
+ *  Calculates the checksum for some buffer on a specified length.  The
+ *  checksum calculated is returned.
+ **/
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
+{
+	u32 i;
+	u8  sum = 0;
+
+	DEBUGFUNC("e1000_calculate_checksum");
+
+	if (!buffer)
+		return 0;
+
+	for (i = 0; i < length; i++)
+		sum += buffer[i];
+
+	return (u8) (0 - sum);
+}
+
+/**
+ *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operation
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+s32 e1000_mng_enable_host_if_generic(struct e1000_hw * hw)
+{
+	u32 hicr;
+	s32 ret_val = E1000_SUCCESS;
+	u8  i;
+
+	DEBUGFUNC("e1000_mng_enable_host_if_generic");
+
+	/* Check that the host interface is enabled. */
+	hicr = E1000_READ_REG(hw, E1000_HICR);
+	if ((hicr & E1000_HICR_EN) == 0) {
+		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+	/* check the previous command is completed */
+	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+		hicr = E1000_READ_REG(hw, E1000_HICR);
+		if (!(hicr & E1000_HICR_C))
+			break;
+		msec_delay_irq(1);
+	}
+
+	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+		DEBUGOUT("Previous command timeout failed .\n");
+		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_mng_mode_generic - Generic check management mode
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the firmware semaphore register and returns true (>0) if
+ *  manageability is enabled, else false (0).
+ **/
+bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	DEBUGFUNC("e1000_check_mng_mode_generic");
+
+	fwsm = E1000_READ_REG(hw, E1000_FWSM);
+
+	return ((fwsm & E1000_FWSM_MODE_MASK) ==
+	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+}
+
+/**
+ *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ **/
+bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
+{
+	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+	u32 *buffer = (u32 *)&hw->mng_cookie;
+	u32 offset;
+	s32 ret_val, hdr_csum, csum;
+	u8 i, len;
+	bool tx_filter = true;
+
+	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
+
+	/* No manageability, no filtering */
+	if (!hw->mac.ops.check_mng_mode(hw)) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/*
+	 * If we can't read from the host interface for whatever
+	 * reason, disable filtering.
+	 */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val != E1000_SUCCESS) {
+		tx_filter = false;
+		goto out;
+	}
+
+	/* Read in the header.  Length and offset are in dwords. */
+	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+	for (i = 0; i < len; i++) {
+		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
+		                                           E1000_HOST_IF,
+		                                           offset + i);
+	}
+	hdr_csum = hdr->checksum;
+	hdr->checksum = 0;
+	csum = e1000_calculate_checksum((u8 *)hdr,
+	                                E1000_MNG_DHCP_COOKIE_LENGTH);
+	/*
+	 * If either the checksums or signature don't match, then
+	 * the cookie area isn't considered valid, in which case we
+	 * take the safe route of assuming Tx filtering is enabled.
+	 */
+	if (hdr_csum != csum)
+		goto out;
+	if (hdr->signature != E1000_IAMT_SIGNATURE)
+		goto out;
+
+	/* Cookie area is valid, make the final check for filtering. */
+	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
+		tx_filter = false;
+
+out:
+	hw->mac.tx_pkt_filtering = tx_filter;
+	return tx_filter;
+}
+
+/**
+ *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw * hw, u8 *buffer,
+                                      u16 length)
+{
+	struct e1000_host_mng_command_header hdr;
+	s32 ret_val;
+	u32 hicr;
+
+	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
+
+	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+	hdr.command_length = length;
+	hdr.reserved1 = 0;
+	hdr.reserved2 = 0;
+	hdr.checksum = 0;
+
+	/* Enable the host interface */
+	ret_val = hw->mac.ops.mng_enable_host_if(hw);
+	if (ret_val)
+		goto out;
+
+	/* Populate the host interface with the contents of "buffer". */
+	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
+	                                  sizeof(hdr), &(hdr.checksum));
+	if (ret_val)
+		goto out;
+
+	/* Write the manageability command header */
+	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
+	if (ret_val)
+		goto out;
+
+	/* Tell the ARC a new command is pending. */
+	hicr = E1000_READ_REG(hw, E1000_HICR);
+	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_mng_write_cmd_header_generic - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+s32 e1000_mng_write_cmd_header_generic(struct e1000_hw * hw,
+                                    struct e1000_host_mng_command_header * hdr)
+{
+	u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
+
+	/* Write the whole command header structure with new checksum. */
+
+	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
+
+	length >>= 2;
+	/* Write the relevant command block into the ram area. */
+	for (i = 0; i < length; i++) {
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
+		                            *((u32 *) hdr + i));
+		E1000_WRITE_FLUSH(hw);
+	}
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_mng_host_if_write_generic - Write to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+s32 e1000_mng_host_if_write_generic(struct e1000_hw * hw, u8 *buffer,
+                                    u16 length, u16 offset, u8 *sum)
+{
+	u8 *tmp;
+	u8 *bufptr = buffer;
+	u32 data = 0;
+	s32 ret_val = E1000_SUCCESS;
+	u16 remaining, i, j, prev_bytes;
+
+	DEBUGFUNC("e1000_mng_host_if_write_generic");
+
+	/* sum = only sum of the data and it is not checksum */
+
+	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	tmp = (u8 *)&data;
+	prev_bytes = offset & 0x3;
+	offset >>= 2;
+
+	if (prev_bytes) {
+		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
+		for (j = prev_bytes; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
+		length -= j - prev_bytes;
+		offset++;
+	}
+
+	remaining = length & 0x3;
+	length -= remaining;
+
+	/* Calculate length in DWORDs */
+	length >>= 2;
+
+	/*
+	 * The device driver writes the relevant command block into the
+	 * ram area.
+	 */
+	for (i = 0; i < length; i++) {
+		for (j = 0; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+	}
+	if (remaining) {
+		for (j = 0; j < sizeof(u32); j++) {
+			if (j < remaining)
+				*(tmp + j) = *bufptr++;
+			else
+				*(tmp + j) = 0;
+
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+	u32 manc;
+	u32 fwsm, factps;
+	bool ret_val = false;
+
+	DEBUGFUNC("e1000_enable_mng_pass_thru");
+
+	if (!hw->mac.asf_firmware_present)
+		goto out;
+
+	manc = E1000_READ_REG(hw, E1000_MANC);
+
+	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+		goto out;
+
+	if (hw->mac.arc_subsystem_valid) {
+		fwsm = E1000_READ_REG(hw, E1000_FWSM);
+		factps = E1000_READ_REG(hw, E1000_FACTPS);
+
+		if (!(factps & E1000_FACTPS_MNGCG) &&
+		    ((fwsm & E1000_FWSM_MODE_MASK) ==
+		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+			ret_val = true;
+			goto out;
+		}
+	} else {
+		if ((manc & E1000_MANC_SMBUS_EN) &&
+		    !(manc & E1000_MANC_ASF_EN)) {
+			ret_val = true;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_manage.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_manage.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_manage.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_manage.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,82 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_MANAGE_H_
+#define _E1000_MANAGE_H_
+
+bool e1000_check_mng_mode_generic(struct e1000_hw *hw);
+bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
+s32  e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
+s32  e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
+                                     u16 length, u16 offset, u8 *sum);
+s32  e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
+                                    struct e1000_host_mng_command_header *hdr);
+s32  e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
+                                       u8 *buffer, u16 length);
+bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
+
+typedef enum {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+} e1000_mng_mode;
+
+#define E1000_FACTPS_MNGCG    0x20000000
+
+#define E1000_FWSM_MODE_MASK  0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE                  0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
+
+#define E1000_VFTA_ENTRY_SHIFT               5
+#define E1000_VFTA_ENTRY_MASK                0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
+
+#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
+#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
+#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
+
+#define E1000_HICR_EN              0x01  /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C               0x02
+#define E1000_HICR_SV              0x04  /* Status Validity */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET        0x80
+
+/* Intel(R) Active Management Technology signature */
+#define E1000_IAMT_SIGNATURE  0x544D4149
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_nvm.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_nvm.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_nvm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_nvm.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,875 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000_hw.h"
+
+/**
+ *  e1000_init_nvm_ops_generic - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	DEBUGFUNC("e1000_init_nvm_ops_generic");
+
+	/* Initialize function pointers */
+	nvm->ops.reload = e1000_reload_nvm_generic;
+}
+
+/**
+ *  e1000_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd | E1000_EECD_SK;
+	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd & ~E1000_EECD_SK;
+	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
+	E1000_WRITE_FLUSH(hw);
+	usec_delay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	u32 mask;
+
+	DEBUGFUNC("e1000_shift_out_eec_bits");
+
+	mask = 0x01 << (count - 1);
+	if (nvm->type == e1000_nvm_eeprom_microwire)
+		eecd &= ~E1000_EECD_DO;
+	else if (nvm->type == e1000_nvm_eeprom_spi)
+		eecd |= E1000_EECD_DO;
+
+	do {
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+
+		usec_delay(nvm->delay_usec);
+
+		e1000_raise_eec_clk(hw, &eecd);
+		e1000_lower_eec_clk(hw, &eecd);
+
+		mask >>= 1;
+	} while (mask);
+
+	eecd &= ~E1000_EECD_DI;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+	u32 eecd;
+	u32 i;
+	u16 data;
+
+	DEBUGFUNC("e1000_shift_in_eec_bits");
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < count; i++) {
+		data <<= 1;
+		e1000_raise_eec_clk(hw, &eecd);
+
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+
+		eecd &= ~E1000_EECD_DI;
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		e1000_lower_eec_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/**
+ *  e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+	u32 attempts = 100000;
+	u32 i, reg = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+
+	DEBUGFUNC("e1000_poll_eerd_eewr_done");
+
+	for (i = 0; i < attempts; i++) {
+		if (ee_reg == E1000_NVM_POLL_READ)
+			reg = E1000_READ_REG(hw, E1000_EERD);
+		else
+			reg = E1000_READ_REG(hw, E1000_EEWR);
+
+		if (reg & E1000_NVM_RW_REG_DONE) {
+			ret_val = E1000_SUCCESS;
+			break;
+		}
+
+		usec_delay(5);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_acquire_nvm_generic - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 e1000_acquire_nvm_generic(struct e1000_hw *hw)
+{
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_acquire_nvm_generic");
+
+	E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	while (timeout) {
+		if (eecd & E1000_EECD_GNT)
+			break;
+		usec_delay(5);
+		eecd = E1000_READ_REG(hw, E1000_EECD);
+		timeout--;
+	}
+
+	if (!timeout) {
+		eecd &= ~E1000_EECD_REQ;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		DEBUGOUT("Could not acquire NVM grant\n");
+		ret_val = -E1000_ERR_NVM;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+
+	DEBUGFUNC("e1000_standby_nvm");
+
+	if (nvm->type == e1000_nvm_eeprom_microwire) {
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+
+		e1000_raise_eec_clk(hw, &eecd);
+
+		/* Select EEPROM */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+
+		e1000_lower_eec_clk(hw, &eecd);
+	} else if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Toggle CS to flush commands */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+		eecd &= ~E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		E1000_WRITE_FLUSH(hw);
+		usec_delay(nvm->delay_usec);
+	}
+}
+
+/**
+ *  e1000_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+void e1000_stop_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	DEBUGFUNC("e1000_stop_nvm");
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		/* Pull CS high */
+		eecd |= E1000_EECD_CS;
+		e1000_lower_eec_clk(hw, &eecd);
+	} else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
+		/* CS on Microwire is active-high */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		e1000_raise_eec_clk(hw, &eecd);
+		e1000_lower_eec_clk(hw, &eecd);
+	}
+}
+
+/**
+ *  e1000_release_nvm_generic - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000_release_nvm_generic(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	DEBUGFUNC("e1000_release_nvm_generic");
+
+	e1000_stop_nvm(hw);
+
+	eecd = E1000_READ_REG(hw, E1000_EECD);
+	eecd &= ~E1000_EECD_REQ;
+	E1000_WRITE_REG(hw, E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
+	s32 ret_val = E1000_SUCCESS;
+	u16 timeout = 0;
+	u8 spi_stat_reg;
+
+	DEBUGFUNC("e1000_ready_nvm_eeprom");
+
+	if (nvm->type == e1000_nvm_eeprom_microwire) {
+		/* Clear SK and DI */
+		eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		/* Set CS */
+		eecd |= E1000_EECD_CS;
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+	} else if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Clear SK and CS */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		E1000_WRITE_REG(hw, E1000_EECD, eecd);
+		usec_delay(1);
+		timeout = NVM_MAX_RETRY_SPI;
+
+		/*
+		 * Read "Status Register" repeatedly until the LSB is cleared.
+		 * The EEPROM will signal that the command has been completed
+		 * by clearing bit 0 of the internal status register.  If it's
+		 * not cleared within 'timeout', then error out.
+		 */
+		while (timeout) {
+			e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+			                         hw->nvm.opcode_bits);
+			spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
+			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+				break;
+
+			usec_delay(5);
+			e1000_standby_nvm(hw);
+			timeout--;
+		}
+
+		if (!timeout) {
+			DEBUGOUT("SPI NVM Status error\n");
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_spi - Read EEPROM's using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i = 0;
+	s32 ret_val;
+	u16 word_in;
+	u8 read_opcode = NVM_READ_OPCODE_SPI;
+
+	DEBUGFUNC("e1000_read_nvm_spi");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val)
+		goto release;
+
+	e1000_standby_nvm(hw);
+
+	if ((nvm->address_bits == 8) && (offset >= 128))
+		read_opcode |= NVM_A8_OPCODE_SPI;
+
+	/* Send the READ command (opcode + addr) */
+	e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+	e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
+
+	/*
+	 * Read the data.  SPI NVMs increment the address with each byte
+	 * read and will roll over if reading beyond the end.  This allows
+	 * us to read the whole NVM from any offset
+	 */
+	for (i = 0; i < words; i++) {
+		word_in = e1000_shift_in_eec_bits(hw, 16);
+		data[i] = (word_in >> 8) | (word_in << 8);
+	}
+
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_microwire - Reads EEPROM's using microwire
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
+                             u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i = 0;
+	s32 ret_val;
+	u8 read_opcode = NVM_READ_OPCODE_MICROWIRE;
+
+	DEBUGFUNC("e1000_read_nvm_microwire");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val)
+		goto release;
+
+	for (i = 0; i < words; i++) {
+		/* Send the READ command (opcode + addr) */
+		e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+		e1000_shift_out_eec_bits(hw, (u16)(offset + i),
+					nvm->address_bits);
+
+		/*
+		 * Read the data.  For microwire, each word requires the
+		 * overhead of setup and tear-down.
+		 */
+		data[i] = e1000_shift_in_eec_bits(hw, 16);
+		e1000_standby_nvm(hw);
+	}
+
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eerd = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_nvm_eerd");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * too many words for the offset, and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+		       E1000_NVM_RW_REG_START;
+
+		E1000_WRITE_REG(hw, E1000_EERD, eerd);
+		ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+		if (ret_val)
+			break;
+
+		data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
+		           E1000_NVM_RW_REG_DATA);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 widx = 0;
+
+	DEBUGFUNC("e1000_write_nvm_spi");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	while (widx < words) {
+		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+		ret_val = e1000_ready_nvm_eeprom(hw);
+		if (ret_val)
+			goto release;
+
+		e1000_standby_nvm(hw);
+
+		/* Send the WRITE ENABLE command (8 bit opcode) */
+		e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+		                         nvm->opcode_bits);
+
+		e1000_standby_nvm(hw);
+
+		/*
+		 * Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
+		if ((nvm->address_bits == 8) && (offset >= 128))
+			write_opcode |= NVM_A8_OPCODE_SPI;
+
+		/* Send the Write command (8-bit opcode + addr) */
+		e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+		e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+		                         nvm->address_bits);
+
+		/* Loop to allow for up to whole page write of eeprom */
+		while (widx < words) {
+			u16 word_out = data[widx];
+			word_out = (word_out >> 8) | (word_out << 8);
+			e1000_shift_out_eec_bits(hw, word_out, 16);
+			widx++;
+
+			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+				e1000_standby_nvm(hw);
+				break;
+			}
+		}
+	}
+
+	msec_delay(nvm->semaphore_delay);
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_microwire - Writes EEPROM using microwire
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using microwire interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
+                              u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32  ret_val;
+	u32 eecd;
+	u16 words_written = 0;
+	u16 widx = 0;
+
+	DEBUGFUNC("e1000_write_nvm_microwire");
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		DEBUGOUT("nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = nvm->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val)
+		goto release;
+
+	e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE,
+	                         (u16)(nvm->opcode_bits + 2));
+
+	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
+
+	e1000_standby_nvm(hw);
+
+	while (words_written < words) {
+		e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE,
+		                         nvm->opcode_bits);
+
+		e1000_shift_out_eec_bits(hw, (u16)(offset + words_written),
+		                         nvm->address_bits);
+
+		e1000_shift_out_eec_bits(hw, data[words_written], 16);
+
+		e1000_standby_nvm(hw);
+
+		for (widx = 0; widx < 200; widx++) {
+			eecd = E1000_READ_REG(hw, E1000_EECD);
+			if (eecd & E1000_EECD_DO)
+				break;
+			usec_delay(50);
+		}
+
+		if (widx == 200) {
+			DEBUGOUT("NVM Write did not complete\n");
+			ret_val = -E1000_ERR_NVM;
+			goto release;
+		}
+
+		e1000_standby_nvm(hw);
+
+		words_written++;
+	}
+
+	e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE,
+	                         (u16)(nvm->opcode_bits + 2));
+
+	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
+
+release:
+	nvm->ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_pba_num_generic - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @pba_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in pba_num.
+ **/
+s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
+{
+	s32  ret_val;
+	u16 nvm_data;
+
+	DEBUGFUNC("e1000_read_pba_num_generic");
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num = (u32)(nvm_data << 16);
+
+	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+	if (ret_val) {
+		DEBUGOUT("NVM Read Error\n");
+		goto out;
+	}
+	*pba_num |= nvm_data;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_mac_addr_generic - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ **/
+s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
+{
+	s32  ret_val = E1000_SUCCESS;
+	u16 offset, nvm_data, i;
+
+	DEBUGFUNC("e1000_read_mac_addr");
+
+	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
+		offset = i >> 1;
+		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+	}
+
+	/* Flip last bit of mac address if we're on second port */
+	if (hw->bus.func == E1000_FUNC_1)
+		hw->mac.perm_addr[5] ^= 1;
+
+	for (i = 0; i < ETH_ADDR_LEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_validate_nvm_checksum_generic - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("e1000_validate_nvm_checksum_generic");
+
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		DEBUGOUT("NVM Checksum Invalid\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum_generic - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32  ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	DEBUGFUNC("e1000_update_nvm_checksum");
+
+	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			DEBUGOUT("NVM Read Error while updating checksum.\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
+	if (ret_val) {
+		DEBUGOUT("NVM Write Error while updating checksum.\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reload_nvm_generic - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+void e1000_reload_nvm_generic(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+
+	DEBUGFUNC("e1000_reload_nvm_generic");
+
+	usec_delay(10);
+	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+	E1000_WRITE_FLUSH(hw);
+}
+
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_nvm.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_nvm.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_nvm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_nvm.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,58 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_NVM_H_
+#define _E1000_NVM_H_
+
+void e1000_init_nvm_ops_generic(struct e1000_hw *hw);
+s32  e1000_acquire_nvm_generic(struct e1000_hw *hw);
+
+s32  e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+s32  e1000_read_mac_addr_generic(struct e1000_hw *hw);
+s32  e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
+s32  e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset,
+                              u16 words, u16 *data);
+s32  e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data);
+s32  e1000_validate_nvm_checksum_generic(struct e1000_hw *hw);
+s32  e1000_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
+                          u16 words, u16 *data);
+s32  e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset,
+                               u16 words, u16 *data);
+s32  e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
+                         u16 *data);
+s32  e1000_update_nvm_checksum_generic(struct e1000_hw *hw);
+void e1000_stop_nvm(struct e1000_hw *hw);
+void e1000_release_nvm_generic(struct e1000_hw *hw);
+void e1000_reload_nvm_generic(struct e1000_hw *hw);
+
+#define E1000_STM_OPCODE  0xDB00
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_osdep.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_osdep.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_osdep.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_osdep.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,116 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* glue for the OS-dependent part of e1000
+ * includes register access macros
+ */
+
+#ifndef _E1000_OSDEP_H_
+#define _E1000_OSDEP_H_
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+
+#include "kcompat.h"
+
+#define usec_delay(x) udelay(x)
+#ifndef msec_delay
+#define msec_delay(x)	do { if(in_interrupt()) { \
+				/* Don't sleep in interrupt context! */ \
+	                	BUG(); \
+			} else { \
+				msleep(x); \
+			} } while (0)
+
+/* Some workarounds require millisecond delays and are run during interrupt
+ * context.  Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+#define msec_delay_irq(x) mdelay(x)
+#endif
+
+#define PCI_COMMAND_REGISTER   PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+#define ETH_ADDR_LEN           ETH_ALEN
+
+
+#define DEBUGOUT(S)
+#define DEBUGOUT1(S, A...)
+
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT7 DEBUGOUT3
+
+#define E1000_WRITE_REG(a, reg, value) ( \
+    writel((value), ((a)->hw_addr + reg)))
+
+#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+    writel((value), ((a)->hw_addr + reg + ((offset) << 2))))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    readl((a)->hw_addr + reg + ((offset) << 2)))
+
+#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
+#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
+
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+    writew((value), ((a)->hw_addr + reg + ((offset) << 1))))
+
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+    readw((a)->hw_addr + reg + ((offset) << 1)))
+
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+    writeb((value), ((a)->hw_addr + reg + (offset))))
+
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+    readb((a)->hw_addr + reg + (offset)))
+
+#define E1000_WRITE_REG_IO(a, reg, offset) do { \
+    outl(reg, ((a)->io_base));                  \
+    outl(offset, ((a)->io_base + 4));      } while(0)
+
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
+
+#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
+    writel((value), ((a)->flash_address + reg)))
+
+#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
+    writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
+
+#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
+
+#endif /* _E1000_OSDEP_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_phy.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_phy.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_phy.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_phy.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,2489 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000_hw.h"
+
+static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_m88_cable_length_table) / \
+                 sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+                (sizeof(e1000_igp_2_cable_length_table) / \
+                 sizeof(e1000_igp_2_cable_length_table[0]))
+
+/**
+ *  e1000_check_reset_block_generic - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 e1000_check_reset_block_generic(struct e1000_hw *hw)
+{
+	u32 manc;
+
+	DEBUGFUNC("e1000_check_reset_block");
+
+	manc = E1000_READ_REG(hw, E1000_MANC);
+
+	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 e1000_get_phy_id(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_id;
+
+	DEBUGFUNC("e1000_get_phy_id");
+
+	if (!(phy->ops.read_reg))
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
+	if (ret_val)
+		goto out;
+
+	phy->id = (u32)(phy_id << 16);
+	usec_delay(20);
+	ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
+	if (ret_val)
+		goto out;
+
+	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_reset_dsp_generic - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_phy_reset_dsp_generic");
+
+	if (!(hw->phy.ops.write_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_mdic - Read MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the MDI control register in the PHY at offset and stores the
+ *  information read to data.
+ **/
+s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_mdic");
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_READ));
+
+	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = E1000_READ_REG(hw, E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		DEBUGOUT("MDI Read did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		DEBUGOUT("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	*data = (u16) mdic;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_mdic - Write MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write to register at offset
+ *
+ *  Writes data to MDI control register in the PHY at offset.
+ **/
+s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_mdic");
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = (((u32)data) |
+	        (offset << E1000_MDIC_REG_SHIFT) |
+	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
+	        (E1000_MDIC_OP_WRITE));
+
+	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		usec_delay(50);
+		mdic = E1000_READ_REG(hw, E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		DEBUGOUT("MDI Write did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		DEBUGOUT("MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_m88 - Read m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_m88");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_read_phy_reg_mdic(hw,
+	                                  MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_m88 - Write m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_m88");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = e1000_write_phy_reg_mdic(hw,
+	                                   MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_phy_reg_igp");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_read_phy_reg_mdic(hw,
+	                                  MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_phy_reg_igp");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+		                                   IGP01E1000_PHY_PAGE_SELECT,
+		                                   (u16)offset);
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_write_phy_reg_mdic(hw,
+	                                   MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_kmrn_reg_generic - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_read_kmrn_reg_generic");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+	usec_delay(2);
+
+	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_kmrn_reg_generic - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary.  Then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release any acquired semaphores
+ *  before exiting.
+ **/
+s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val = E1000_SUCCESS;
+
+	DEBUGFUNC("e1000_write_kmrn_reg_generic");
+
+	if (!(hw->phy.ops.acquire))
+		goto out;
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+	               E1000_KMRNCTRLSTA_OFFSET) | data;
+	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
+
+	usec_delay(2);
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	DEBUGFUNC("e1000_copper_link_setup_m88");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/* For newer PHYs this bit is downshift enable */
+	if (phy->type == e1000_phy_m88)
+		phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+	/*
+	 * Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+	switch (phy->mdix) {
+		case 1:
+			phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+			break;
+		case 2:
+			phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+			break;
+		case 3:
+			phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+			break;
+		case 0:
+		default:
+			phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+			break;
+	}
+
+	/*
+	 * Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (phy->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+	/* Enable downshift on BM (disabled by default) */
+	if (phy->type == e1000_phy_bm)
+		phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
+
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	if ((phy->type == e1000_phy_m88) &&
+	    (phy->revision < E1000_REVISION_4) &&
+	    (phy->id != BME1000_E_PHY_ID_R2)) {
+		/*
+		 * Force TX_CLK in the Extended PHY Specific Control Register
+		 * to 25MHz clock.
+		 */
+		ret_val = phy->ops.read_reg(hw,
+		                             M88E1000_EXT_PHY_SPEC_CTRL,
+		                             &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+		if ((phy->revision == E1000_REVISION_2) &&
+		    (phy->id == M88E1111_I_PHY_ID)) {
+			/* 82573L PHY - set the downshift counter to 5x. */
+			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+		} else {
+			/* Configure Master and Slave downshift values */
+			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+		}
+		ret_val = phy->ops.write_reg(hw,
+		                             M88E1000_EXT_PHY_SPEC_CTRL,
+		                             phy_data);
+		if (ret_val)
+			goto out;
+	}
+
+	if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
+		/* Set PHY page 0, register 29 to 0x0003 */
+		ret_val = phy->ops.write_reg(hw, 29, 0x0003);
+		if (ret_val)
+			goto out;
+
+		/* Set PHY page 0, register 30 to 0x0000 */
+		ret_val = phy->ops.write_reg(hw, 30, 0x0000);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Commit the changes. */
+	ret_val = phy->ops.commit(hw);
+	if (ret_val) {
+		DEBUGOUT("Error committing the PHY changes\n");
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_copper_link_setup_igp");
+
+	if (phy->reset_disable) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.reset(hw);
+	if (ret_val) {
+		DEBUGOUT("Error resetting the PHY.\n");
+		goto out;
+	}
+
+	/*
+	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+	 * timeout issues when LFS is enabled.
+	 */
+	msec_delay(100);
+
+	/*
+	 * The NVM settings will configure LPLU in D3 for
+	 * non-IGP1 PHYs.
+	 */
+	if (phy->type == e1000_phy_igp) {
+		/* disable lplu d3 during driver init */
+		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
+		if (ret_val) {
+			DEBUGOUT("Error Disabling LPLU D3\n");
+			goto out;
+		}
+	}
+
+	/* disable lplu d0 during driver init */
+	if (hw->phy.ops.set_d0_lplu_state) {
+		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+		if (ret_val) {
+			DEBUGOUT("Error Disabling LPLU D0\n");
+			goto out;
+		}
+	}
+	/* Configure mdi-mdix settings */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+	switch (phy->mdix) {
+	case 1:
+		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 2:
+		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 0:
+	default:
+		data |= IGP01E1000_PSCR_AUTO_MDIX;
+		break;
+	}
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+	if (ret_val)
+		goto out;
+
+	/* set auto-master slave resolution settings */
+	if (hw->mac.autoneg) {
+		/*
+		 * when autonegotiation advertisement is only 1000Mbps then we
+		 * should disable SmartSpeed and enable Auto MasterSlave
+		 * resolution as hardware default.
+		 */
+		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+			/* Disable SmartSpeed */
+			ret_val = phy->ops.read_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+
+			/* Set auto Master/Slave resolution process */
+			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~CR_1000T_MS_ENABLE;
+			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+			if (ret_val)
+				goto out;
+		}
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		/* load defaults for future use */
+		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+			((data & CR_1000T_MS_VALUE) ?
+			e1000_ms_force_master :
+			e1000_ms_force_slave) :
+			e1000_ms_auto;
+
+		switch (phy->ms_type) {
+		case e1000_ms_force_master:
+			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_force_slave:
+			data |= CR_1000T_MS_ENABLE;
+			data &= ~(CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_auto:
+			data &= ~CR_1000T_MS_ENABLE;
+		default:
+			break;
+		}
+		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	DEBUGFUNC("e1000_copper_link_autoneg");
+
+	/*
+	 * Perform some bounds checking on the autoneg advertisement
+	 * parameter.
+	 */
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/*
+	 * If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (phy->autoneg_advertised == 0)
+		phy->autoneg_advertised = phy->autoneg_mask;
+
+	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+	ret_val = e1000_phy_setup_autoneg(hw);
+	if (ret_val) {
+		DEBUGOUT("Error Setting up Auto-Negotiation\n");
+		goto out;
+	}
+	DEBUGOUT("Restarting Auto-Neg\n");
+
+	/*
+	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (phy->autoneg_wait_to_complete) {
+		ret_val = hw->mac.ops.wait_autoneg(hw);
+		if (ret_val) {
+			DEBUGOUT("Error while waiting for "
+			         "autoneg to complete\n");
+			goto out;
+		}
+	}
+
+	hw->mac.get_link_status = true;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg = 0;
+
+	DEBUGFUNC("e1000_phy_setup_autoneg");
+
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		/* Read the MII 1000Base-T Control Register (Address 9). */
+		ret_val = phy->ops.read_reg(hw,
+		                            PHY_1000T_CTRL,
+		                            &mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+	                         NWAY_AR_100TX_HD_CAPS |
+	                         NWAY_AR_10T_FD_CAPS   |
+	                         NWAY_AR_10T_HD_CAPS);
+	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+		DEBUGOUT("Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+		DEBUGOUT("Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+		DEBUGOUT("Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+		DEBUGOUT("Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (phy->autoneg_advertised & ADVERTISE_1000_HALF) {
+		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
+	}
+
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+		DEBUGOUT("Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          but we do not support receiving pause frames).
+	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *          in the EEPROM is used.
+	 */
+	switch (hw->fc.type) {
+	case e1000_fc_none:
+		/*
+		 * Flow control (Rx & Tx) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * Rx Flow control is enabled, and Tx Flow control is
+		 * disabled, by a software over-ride.
+		 *
+		 * Since there really isn't a way to advertise that we are
+		 * capable of Rx Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric Rx PAUSE.  Later
+		 * (in e1000_config_fc_after_link_up) we will disable the
+		 * hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * Tx Flow control is enabled, and Rx Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both Rx and Tx) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		DEBUGOUT("Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		ret_val = phy->ops.write_reg(hw,
+		                              PHY_1000T_CTRL,
+		                              mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_generic - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	bool link;
+
+	DEBUGFUNC("e1000_setup_copper_link_generic");
+
+	if (hw->mac.autoneg) {
+		/*
+		 * Setup autoneg and flow control advertisement and perform
+		 * autonegotiation.
+		 */
+		ret_val = e1000_copper_link_autoneg(hw);
+		if (ret_val)
+			goto out;
+	} else {
+		/*
+		 * PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings.
+		 */
+		DEBUGOUT("Forcing Speed and Duplex\n");
+		ret_val = hw->phy.ops.force_speed_duplex(hw);
+		if (ret_val) {
+			DEBUGOUT("Error Forcing Speed and Duplex\n");
+			goto out;
+		}
+	}
+
+	/*
+	 * Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = e1000_phy_has_link_generic(hw,
+	                                     COPPER_LINK_UP_LIMIT,
+	                                     10,
+	                                     &link);
+	if (ret_val)
+		goto out;
+
+	if (link) {
+		DEBUGOUT("Valid link established!!!\n");
+		e1000_config_collision_dist_generic(hw);
+		ret_val = e1000_config_fc_after_link_up_generic(hw);
+	} else {
+		DEBUGOUT("Unable to establish link!!!\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			DEBUGOUT("Link taking longer than expected.\n");
+		}
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+
+	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	/* Reset the phy to commit changes. */
+	phy_data |= MII_CR_RESET;
+
+	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	usec_delay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
+
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = phy->ops.write_reg(hw,
+			                              M88E1000_PHY_PAGE_SELECT,
+			                              0x001d);
+			if (ret_val)
+				goto out;
+			ret_val = e1000_phy_reset_dsp_generic(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = e1000_phy_has_link_generic(hw,
+		                                     PHY_FORCE_LIMIT,
+		                                     100000,
+		                                     &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to re-force TX_CLK in the
+	 * Extended PHY Specific Control Register to 25MHz clock from
+	 * the reset value of 2.5MHz.
+	 */
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
+
+	/* Turn off flow control when forcing speed/duplex */
+	hw->fc.type = e1000_fc_none;
+
+	/* Force speed/duplex on the mac */
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~E1000_CTRL_SPD_SEL;
+
+	/* Disable Auto Speed Detection */
+	ctrl &= ~E1000_CTRL_ASDE;
+
+	/* Disable autoneg on the phy */
+	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+	/* Forcing Full or Half Duplex? */
+	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+		ctrl &= ~E1000_CTRL_FD;
+		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		DEBUGOUT("Half Duplex\n");
+	} else {
+		ctrl |= E1000_CTRL_FD;
+		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		DEBUGOUT("Full Duplex\n");
+	}
+
+	/* Forcing 10mb or 100mb? */
+	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+		ctrl |= E1000_CTRL_SPD_100;
+		*phy_ctrl |= MII_CR_SPEED_100;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		DEBUGOUT("Forcing 100mb\n");
+	} else {
+		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+		*phy_ctrl |= MII_CR_SPEED_10;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		DEBUGOUT("Forcing 10mb\n");
+	}
+
+	e1000_config_collision_dist_generic(hw);
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+}
+
+/**
+ *  e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 data;
+
+	DEBUGFUNC("e1000_set_d3_lplu_state_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		goto out;
+
+	if (!active) {
+		data &= ~IGP02E1000_PM_D3_LPLU;
+		ret_val = phy->ops.write_reg(hw,
+		                             IGP02E1000_PHY_POWER_MGMT,
+		                             data);
+		if (ret_val)
+			goto out;
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = phy->ops.read_reg(hw,
+			                            IGP01E1000_PHY_PORT_CONFIG,
+			                            &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = phy->ops.read_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = phy->ops.write_reg(hw,
+			                             IGP01E1000_PHY_PORT_CONFIG,
+			                             data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP02E1000_PM_D3_LPLU;
+		ret_val = phy->ops.write_reg(hw,
+		                              IGP02E1000_PHY_POWER_MGMT,
+		                              data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = phy->ops.read_reg(hw,
+		                             IGP01E1000_PHY_PORT_CONFIG,
+		                             &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = phy->ops.write_reg(hw,
+		                              IGP01E1000_PHY_PORT_CONFIG,
+		                              data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_downshift_generic - Checks whether a downshift in speed occurred
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 e1000_check_downshift_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	DEBUGFUNC("e1000_check_downshift_generic");
+
+	switch (phy->type) {
+	case e1000_phy_m88:
+	case e1000_phy_gg82563:
+	case e1000_phy_bm:
+		offset	= M88E1000_PHY_SPEC_STATUS;
+		mask	= M88E1000_PSSR_DOWNSHIFT;
+		break;
+	case e1000_phy_igp_2:
+	case e1000_phy_igp:
+	case e1000_phy_igp_3:
+		offset	= IGP01E1000_PHY_LINK_HEALTH;
+		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
+		break;
+	default:
+		/* speed downshift not supported */
+		phy->speed_downgraded = false;
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+s32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	DEBUGFUNC("e1000_check_polarity_m88");
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+s32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data, offset, mask;
+
+	DEBUGFUNC("e1000_check_polarity_igp");
+
+	/*
+	 * Polarity is determined based on the speed of
+	 * our connection.
+	 */
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		offset	= IGP01E1000_PHY_PCS_INIT_REG;
+		mask	= IGP01E1000_PHY_POLARITY_MASK;
+	} else {
+		/*
+		 * This really only applies to 10Mbps since
+		 * there is no polarity for 100Mbps (always 0).
+		 */
+		offset	= IGP01E1000_PHY_PORT_STATUS;
+		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
+	}
+
+	ret_val = phy->ops.read_reg(hw, offset, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & mask)
+		                      ? e1000_rev_polarity_reversed
+		                      : e1000_rev_polarity_normal;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_wait_autoneg_generic - Wait for auto-neg completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+s32 e1000_wait_autoneg_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	DEBUGFUNC("e1000_wait_autoneg_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+			break;
+		msec_delay(100);
+	}
+
+	/*
+	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+	 * has completed.
+	 */
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_has_link_generic - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                               u32 usec_interval, bool *success)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 i, phy_status;
+
+	DEBUGFUNC("e1000_phy_has_link_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		return E1000_SUCCESS;
+
+	for (i = 0; i < iterations; i++) {
+		/*
+		 * Some PHYs require the PHY_STATUS register to be read
+		 * twice due to the link bit being sticky.  No harm doing
+		 * it across the board.
+		 */
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_LINK_STATUS)
+			break;
+		if (usec_interval >= 1000)
+			msec_delay_irq(usec_interval/1000);
+		else
+			usec_delay(usec_interval);
+	}
+
+	*success = (i < iterations) ? true : false;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *	Register Value		Cable Length
+ *	0			< 50 meters
+ *	1			50 - 80 meters
+ *	2			80 - 110 meters
+ *	3			110 - 140 meters
+ *	4			> 140 meters
+ **/
+s32 e1000_get_cable_length_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, index;
+
+	DEBUGFUNC("e1000_get_cable_length_m88");
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which represent the
+ *  combination of coarse and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_data, i, agc_value = 0;
+	u16 cur_agc_index, max_agc_index = 0;
+	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+	                                                 {IGP02E1000_PHY_AGC_A,
+	                                                  IGP02E1000_PHY_AGC_B,
+	                                                  IGP02E1000_PHY_AGC_C,
+	                                                  IGP02E1000_PHY_AGC_D};
+
+	DEBUGFUNC("e1000_get_cable_length_igp_2");
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Getting bits 15:9, which represent the combination of
+		 * coarse and fine gain values.  The result is a number
+		 * that can be put into the lookup table to obtain the
+		 * approximate cable length.
+		 */
+		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+		                IGP02E1000_AGC_LENGTH_MASK;
+
+		/* Array index bound check. */
+		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+		    (cur_agc_index == 0)) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		/* Remove min & max AGC values from calculation. */
+		if (e1000_igp_2_cable_length_table[min_agc_index] >
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			min_agc_index = cur_agc_index;
+		if (e1000_igp_2_cable_length_table[max_agc_index] <
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			max_agc_index = cur_agc_index;
+
+		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+	}
+
+	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+	              e1000_igp_2_cable_length_table[max_agc_index]);
+	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+	/* Calculate cable length with the error range of +/- 10 meters. */
+	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
+	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 e1000_get_phy_info_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u16 phy_data;
+	bool link;
+
+	DEBUGFUNC("e1000_get_phy_info_m88");
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		DEBUGOUT("Phy info is only valid for copper media\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+	                           ? true
+	                           : false;
+
+	ret_val = e1000_check_polarity_m88(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
+
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+		ret_val = hw->phy.ops.get_cable_length(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+	} else {
+		/* Set values to "undefined" */
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 e1000_get_phy_info_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	DEBUGFUNC("e1000_get_phy_info_igp");
+
+	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		DEBUGOUT("Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = e1000_check_polarity_igp(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		ret_val = hw->phy.ops.get_cable_length(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+		                ? e1000_1000t_rx_status_ok
+		                : e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+		                 ? e1000_1000t_rx_status_ok
+		                 : e1000_1000t_rx_status_not_ok;
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_sw_reset_generic - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
+{
+	s32 ret_val = E1000_SUCCESS;
+	u16 phy_ctrl;
+
+	DEBUGFUNC("e1000_phy_sw_reset_generic");
+
+	if (!(hw->phy.ops.read_reg))
+		goto out;
+
+	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= MII_CR_RESET;
+	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	usec_delay(1);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_generic - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and release the semaphore (if necessary).
+ **/
+s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = E1000_SUCCESS;
+	u32 ctrl;
+
+	DEBUGFUNC("e1000_phy_hw_reset_generic");
+
+	ret_val = phy->ops.check_reset_block(hw);
+	if (ret_val) {
+		ret_val = E1000_SUCCESS;
+		goto out;
+	}
+
+	ret_val = phy->ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	ctrl = E1000_READ_REG(hw, E1000_CTRL);
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(phy->reset_delay_us);
+
+	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+	E1000_WRITE_FLUSH(hw);
+
+	usec_delay(150);
+
+	phy->ops.release(hw);
+
+	ret_val = phy->ops.get_cfg_done(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cfg_done_generic - Generic configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Generic function to wait 10 milli-seconds for configuration to complete
+ *  and return success.
+ **/
+s32 e1000_get_cfg_done_generic(struct e1000_hw *hw)
+{
+	DEBUGFUNC("e1000_get_cfg_done_generic");
+
+	msec_delay_irq(10);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 e1000_phy_init_script_igp3(struct e1000_hw *hw)
+{
+	DEBUGOUT("Running IGP 3 PHY init script\n");
+
+	/* PHY init IGP 3 */
+	/* Enable rise/fall, 10-mode work in class-A */
+	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
+	/* Remove all caps from Replica path filter */
+	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
+	/* Bias trimming for ADC, AFE and Driver (Default) */
+	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
+	/* Increase Hybrid poly bias */
+	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
+	/* Add 4% to Tx amplitude in Gig mode */
+	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
+	/* Disable trimming (TTT) */
+	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
+	/* Poly DC correction to 94.6% + 2% for all channels */
+	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
+	/* ABS DC correction to 95.9% */
+	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
+	/* BG temp curve trim */
+	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
+	/* Increasing ADC OPAMP stage 1 currents to max */
+	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
+	/* Force 1000 ( required for enabling PHY regs configuration) */
+	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
+	/* Set upd_freq to 6 */
+	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
+	/* Disable NPDFE */
+	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
+	/* Disable adaptive fixed FFE (Default) */
+	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
+	/* Enable FFE hysteresis */
+	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
+	/* Fixed FFE for short cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
+	/* Fixed FFE for medium cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
+	/* Fixed FFE for long cable lengths */
+	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
+	/* Enable Adaptive Clip Threshold */
+	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
+	/* AHT reset limit to 1 */
+	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
+	/* Set AHT master delay to 127 msec */
+	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
+	/* Set scan bits for AHT */
+	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
+	/* Set AHT Preset bits */
+	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
+	/* Change integ_factor of channel A to 3 */
+	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
+	/* Change prop_factor of channels BCD to 8 */
+	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
+	/* Change cg_icount + enable integbp for channels BCD */
+	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
+	/*
+	 * Change cg_icount + enable integbp + change prop_factor_master
+	 * to 8 for channel A
+	 */
+	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
+	/* Disable AHT in Slave mode on channel A */
+	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
+	/*
+	 * Enable LPLU and disable AN to 1000 in non-D0a states,
+	 * Enable SPD+B2B
+	 */
+	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
+	/* Enable restart AN on an1000_dis change */
+	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
+	/* Enable wh_fifo read clock in 10/100 modes */
+	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
+	/* Restart AN, Speed selection is 1000 */
+	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
+
+	return E1000_SUCCESS;
+}
+
+/**
+ *  e1000_get_phy_type_from_id - Get PHY type from id
+ *  @phy_id: phy_id read from the phy
+ *
+ *  Returns the phy type from the id.
+ **/
+e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
+{
+	e1000_phy_type phy_type = e1000_phy_unknown;
+
+	switch (phy_id)	{
+	case M88E1000_I_PHY_ID:
+	case M88E1000_E_PHY_ID:
+	case M88E1111_I_PHY_ID:
+	case M88E1011_I_PHY_ID:
+		phy_type = e1000_phy_m88;
+		break;
+	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+		phy_type = e1000_phy_igp_2;
+		break;
+	case GG82563_E_PHY_ID:
+		phy_type = e1000_phy_gg82563;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy_type = e1000_phy_igp_3;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy_type = e1000_phy_ife;
+		break;
+	case BME1000_E_PHY_ID:
+	case BME1000_E_PHY_ID_R2:
+		phy_type = e1000_phy_bm;
+		break;
+	default:
+		phy_type = e1000_phy_unknown;
+		break;
+	}
+	return phy_type;
+}
+
+/**
+ *  e1000_determine_phy_address - Determines PHY address.
+ *  @hw: pointer to the HW structure
+ *
+ *  This uses a trial and error method to loop through possible PHY
+ *  addresses. It tests each by reading the PHY ID registers and
+ *  checking for a match.
+ **/
+s32 e1000_determine_phy_address(struct e1000_hw* hw)
+{
+	s32 ret_val = -E1000_ERR_PHY_TYPE;
+	u32 phy_addr= 0;
+	u32 i;
+	e1000_phy_type phy_type = e1000_phy_unknown;
+
+	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+		hw->phy.addr = phy_addr;
+		i = 0;
+
+		do {
+			e1000_get_phy_id(hw);
+			phy_type = e1000_get_phy_type_from_id(hw->phy.id);
+
+			/* 
+		 	 * If phy_type is valid, break - we found our
+		 	 * PHY address
+		 	 */
+			if (phy_type  != e1000_phy_unknown) {
+				ret_val = E1000_SUCCESS;
+				goto out;
+			}
+			msec_delay(1);
+			i++;
+		} while (i < 10);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_addr_for_bm_page - Retrieve PHY page address
+ *  @page: page to access
+ *
+ *  Returns the phy address for the page requested.
+ **/
+static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg)
+{
+	u32 phy_addr = 2;
+
+	if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
+		phy_addr = 1;
+
+	return phy_addr;
+}
+
+/**
+ *  e1000_write_phy_reg_bm - Write BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u32 page_select = 0;
+	u32 page = offset >> IGP_PAGE_SHIFT;
+	u32 page_shift = 0;
+
+	DEBUGFUNC("e1000_write_phy_reg_bm");
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw,
+							offset, &data, false);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/*
+		 * Page select is register 31 for phy address 1 and 22 for
+		 * phy address 2 and 3. Page select is shifted only for
+		 * phy address 1.
+		 */
+		if (hw->phy.addr == 1) {
+			page_shift = IGP_PAGE_SHIFT;
+			page_select = IGP01E1000_PHY_PAGE_SELECT;
+		} else {
+			page_shift = 0;
+			page_select = BM_PHY_PAGE_SELECT;
+		}
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000_write_phy_reg_mdic(hw, page_select,
+		                                   (page << page_shift));
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_write_phy_reg_mdic(hw,
+	                                   MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_bm - Read BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u32 page_select = 0;
+	u32 page = offset >> IGP_PAGE_SHIFT;
+	u32 page_shift = 0;
+
+	DEBUGFUNC("e1000_read_phy_reg_bm");
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw,
+							offset, data, true);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/*
+		 * Page select is register 31 for phy address 1 and 22 for
+		 * phy address 2 and 3. Page select is shifted only for
+		 * phy address 1.
+		 */
+		if (hw->phy.addr == 1) {
+			page_shift = IGP_PAGE_SHIFT;
+			page_select = IGP01E1000_PHY_PAGE_SELECT;
+		} else {
+			page_shift = 0;
+			page_select = BM_PHY_PAGE_SELECT;
+		}
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000_write_phy_reg_mdic(hw, page_select,
+		                                   (page << page_shift));
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+ 	ret_val = e1000_read_phy_reg_mdic(hw,
+ 	                                  MAX_PHY_REG_ADDRESS & offset,
+ 	                                  data);
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_bm2 - Read BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
+		                                         true);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+		                                   page);
+
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+ 	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                  data);
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_bm2 - Write BM PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
+
+	DEBUGFUNC("e1000_write_phy_reg_bm2");
+
+	/* Page 800 works differently than the rest so it has its own func */
+	if (page == BM_WUC_PAGE) {
+		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
+		                                         false);
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val)
+		goto out;
+
+	hw->phy.addr = 1;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		/* Page is shifted left, PHY expects (page x 32) */
+		ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
+		                                   page);
+
+		if (ret_val) {
+			hw->phy.ops.release(hw);
+			goto out;
+		}
+	}
+
+	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
+	                                   data);
+
+	hw->phy.ops.release(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read or written
+ *  @data: pointer to the data to read or write
+ *  @read: determines if operation is read or write
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting. Note that procedure to read the wakeup
+ *  registers are different. It works as such:
+ *  1) Set page 769, register 17, bit 2 = 1
+ *  2) Set page to 800 for host (801 if we were manageability)
+ *  3) Write the address using the address opcode (0x11)
+ *  4) Read or write the data using the data opcode (0x12)
+ *  5) Restore 769_17.2 to its original value
+ **/
+s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw,
+                                      u32 offset, u16 *data, bool read)
+{
+	s32 ret_val;
+	u16 reg = ((u16)offset);
+	u16 phy_reg = 0;
+	u8  phy_acquired = 1;
+
+	DEBUGFUNC("e1000_read_phy_wakeup_reg_bm");
+
+	ret_val = hw->phy.ops.acquire(hw);
+	if (ret_val) {
+		DEBUGOUT("Could not acquire PHY\n");
+		phy_acquired = 0;
+		goto out;
+	}
+
+	/* All operations in this function are phy address 1 */
+	hw->phy.addr = 1;
+
+	/* Set page 769 */
+	e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+	ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
+	if (ret_val) {
+		DEBUGOUT("Could not read PHY page 769\n");
+		goto out;
+	}
+
+	/* First clear bit 4 to avoid a power state change */
+	phy_reg &= ~(BM_WUC_HOST_WU_BIT);
+	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+	if (ret_val) {
+		DEBUGOUT("Could not clear PHY page 769 bit 4\n");
+		goto out;
+	}
+
+	/* Write bit 2 = 1, and clear bit 4 to 769_17 */
+	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
+	                                   phy_reg | BM_WUC_ENABLE_BIT);
+	if (ret_val) {
+		DEBUGOUT("Could not write PHY page 769 bit 2\n");
+		goto out;
+	}
+
+	/* Select page 800 */
+	ret_val = e1000_write_phy_reg_mdic(hw,
+	                                   IGP01E1000_PHY_PAGE_SELECT,
+	                                   (BM_WUC_PAGE << IGP_PAGE_SHIFT));
+
+	/* Write the page 800 offset value using opcode 0x11 */
+	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
+	if (ret_val) {
+		DEBUGOUT("Could not write address opcode to page 800\n");
+		goto out;
+	}
+
+	if (read) {
+	        /* Read the page 800 value using opcode 0x12 */
+		ret_val = e1000_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+							data);
+	} else {
+	        /* Read the page 800 value using opcode 0x12 */
+		ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
+							*data);
+	}
+
+	if (ret_val) {
+		DEBUGOUT("Could not read data value from page 800\n");
+		goto out;
+	}
+
+	/*
+	 * Restore 769_17.2 to its original value
+	 * Set page 769
+	 */
+	e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+
+	/* Clear 769_17.2 */
+	ret_val = e1000_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+	if (ret_val) {
+		DEBUGOUT("Could not clear PHY page 769 bit 2\n");
+		goto out;
+	}
+
+out:
+	if (phy_acquired == 1)
+		hw->phy.ops.release(hw);
+	return ret_val;
+}
+
+/**
+ * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_up_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+	mii_reg &= ~MII_CR_POWER_DOWN;
+	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_down_phy_copper(struct e1000_hw *hw)
+{
+	u16 mii_reg = 0;
+
+	/* The PHY will retain its settings across a power down/up cycle */
+	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+	mii_reg |= MII_CR_POWER_DOWN;
+	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+	msec_delay(1);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_phy.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_phy.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_phy.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_phy.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,190 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_PHY_H_
+#define _E1000_PHY_H_
+
+typedef enum {
+	e1000_ms_hw_default = 0,
+	e1000_ms_force_master,
+	e1000_ms_force_slave,
+	e1000_ms_auto
+} e1000_ms_type;
+
+typedef enum {
+	e1000_smart_speed_default = 0,
+	e1000_smart_speed_on,
+	e1000_smart_speed_off
+} e1000_smart_speed;
+
+void e1000_init_phy_ops_generic(struct e1000_hw *hw);
+s32  e1000_check_downshift_generic(struct e1000_hw *hw);
+s32  e1000_check_polarity_m88(struct e1000_hw *hw);
+s32  e1000_check_polarity_igp(struct e1000_hw *hw);
+s32  e1000_check_reset_block_generic(struct e1000_hw *hw);
+s32  e1000_copper_link_autoneg(struct e1000_hw *hw);
+s32  e1000_copper_link_setup_igp(struct e1000_hw *hw);
+s32  e1000_copper_link_setup_m88(struct e1000_hw *hw);
+s32  e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32  e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32  e1000_get_cable_length_m88(struct e1000_hw *hw);
+s32  e1000_get_cable_length_igp_2(struct e1000_hw *hw);
+s32  e1000_get_cfg_done_generic(struct e1000_hw *hw);
+s32  e1000_get_phy_id(struct e1000_hw *hw);
+s32  e1000_get_phy_info_igp(struct e1000_hw *hw);
+s32  e1000_get_phy_info_m88(struct e1000_hw *hw);
+s32  e1000_phy_sw_reset_generic(struct e1000_hw *hw);
+void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+s32  e1000_phy_hw_reset_generic(struct e1000_hw *hw);
+s32  e1000_phy_reset_dsp_generic(struct e1000_hw *hw);
+s32  e1000_phy_setup_autoneg(struct e1000_hw *hw);
+s32  e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active);
+s32  e1000_setup_copper_link_generic(struct e1000_hw *hw);
+s32  e1000_wait_autoneg_generic(struct e1000_hw *hw);
+s32  e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+s32  e1000_phy_reset_dsp(struct e1000_hw *hw);
+s32  e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+                                u32 usec_interval, bool *success);
+s32  e1000_phy_init_script_igp3(struct e1000_hw *hw);
+e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id);
+s32 e1000_determine_phy_address(struct e1000_hw* hw);
+s32 e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
+s32 e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data,
+                                   bool read);
+s32 e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
+void e1000_power_up_phy_copper(struct e1000_hw *hw);
+void e1000_power_down_phy_copper(struct e1000_hw *hw);
+s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+
+#define E1000_MAX_PHY_ADDR                4
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
+#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
+#define IGP_PAGE_SHIFT                    5
+#define PHY_REG_MASK                      0x1F
+
+#define BM_WUC_PAGE                       800
+#define BM_WUC_ADDRESS_OPCODE             0x11
+#define BM_WUC_DATA_OPCODE                0x12
+#define BM_WUC_ENABLE_PAGE                769
+#define BM_WUC_ENABLE_REG                 17
+#define BM_WUC_ENABLE_BIT                 (1 << 2)
+#define BM_WUC_HOST_WU_BIT                (1 << 4)
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1                       16
+#define BM_CS_CTRL1_ENERGY_DETECT         0x0300 /* Enable Energy Detect */
+
+/* BM PHY Copper Specific States */
+#define BM_CS_STATUS                      17
+#define BM_CS_STATUS_ENERGY_DETECT        0x0010 /* Energy Detect Status */
+
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP01E1000_GMII_FLEX_SPD          0x0010
+#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
+
+#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0008
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+#define IGP03E1000_PHY_MISC_CTRL          0x1B
+#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
+
+#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
+
+#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
+#define E1000_KMRNCTRLSTA_REN             0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED    0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
+#define IFE_PSC_FORCE_POLARITY             0x0020
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE            0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_regs.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_regs.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/e1000_regs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/e1000_regs.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,310 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_REGS_H_
+#define _E1000_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_IVAR     0x000E4  /* Interrupt Vector Allocation Register - RW */
+#define E1000_RCTL     0x00100  /* Rx Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
+#define E1000_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
+#define E1000_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#define E1000_TCTL     0x00400  /* Tx Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
+#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
+#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
+#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_TCPTIMER 0x0104C  /* TCP Timer - RW */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication Rx Control - RW */
+#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
+#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
+#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
+#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
+#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
+#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
+#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)   ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)   ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)   ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)  ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)     ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : (0x0C010 + ((_n) * 0x40)))
+#define E1000_RDT(_n)     ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)  ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : (0x0C028 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)   ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)   ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)   ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)     ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : (0x0E010 + ((_n) * 0x40)))
+#define E1000_TDT(_n)     ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)  ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : (0x0E028 + ((_n) * 0x40)))
+#define E1000_TARC(_n)    (0x03840 + (_n << 8))
+#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
+#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
+#define E1000_TDWBAL(_n)  ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n)  ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : (0x0E03C + ((_n) * 0x40)))
+#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
+#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x054E0 + ((_i - 16) * 8)))
+#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x054E4 + ((_i - 16) * 8)))
+#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
+#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
+#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
+#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
+#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
+#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
+#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
+#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
+#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
+#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
+#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
+#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
+#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
+#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
+#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
+#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VMD_CTL  0x0581C  /* VMDq Control - RW */
+#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
+#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA      0x0003C /* PHY address - RW */
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR         0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
+#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Interface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register (_i) - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr low reg 0 - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr upper reg 0 - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry message reg 0 - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry vector ctrl reg 0 - RW */
+#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW Array */
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+#define E1000_RXMTRL     0x0B634 /* Time sync Rx EtherType and Message Type - RW */
+#define E1000_RXUDP      0x0B638 /* Time Sync Rx UDP Port - RW */
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/es2lan.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/es2lan.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/es2lan.c	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/es2lan.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1232 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/*
- * 80003ES2LAN Gigabit Ethernet Controller (Copper)
- * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
- */
-
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "e1000.h"
-
-#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL	 0x00
-#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL	 0x02
-#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL	 0x10
-
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS	 0x0008
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS	 0x0800
-#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING	 0x0010
-
-#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
-#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT	 0x0000
-
-#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
-#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN	 0x00010000
-
-#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN	 0x8
-#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN	 0x9
-
-/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
-#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE	 0x0002 /* 1=Reversal Disab. */
-#define GG82563_PSCR_CROSSOVER_MODE_MASK	 0x0060
-#define GG82563_PSCR_CROSSOVER_MODE_MDI		 0x0000 /* 00=Manual MDI */
-#define GG82563_PSCR_CROSSOVER_MODE_MDIX	 0x0020 /* 01=Manual MDIX */
-#define GG82563_PSCR_CROSSOVER_MODE_AUTO	 0x0060 /* 11=Auto crossover */
-
-/* PHY Specific Control Register 2 (Page 0, Register 26) */
-#define GG82563_PSCR2_REVERSE_AUTO_NEG		 0x2000
-						/* 1=Reverse Auto-Negotiation */
-
-/* MAC Specific Control Register (Page 2, Register 21) */
-/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
-#define GG82563_MSCR_TX_CLK_MASK		 0x0007
-#define GG82563_MSCR_TX_CLK_10MBPS_2_5		 0x0004
-#define GG82563_MSCR_TX_CLK_100MBPS_25		 0x0005
-#define GG82563_MSCR_TX_CLK_1000MBPS_25		 0x0007
-
-#define GG82563_MSCR_ASSERT_CRS_ON_TX		 0x0010 /* 1=Assert */
-
-/* DSP Distance Register (Page 5, Register 26) */
-#define GG82563_DSPD_CABLE_LENGTH		 0x0007 /* 0 = <50M
-							   1 = 50-80M
-							   2 = 80-110M
-							   3 = 110-140M
-							   4 = >140M */
-
-/* Kumeran Mode Control Register (Page 193, Register 16) */
-#define GG82563_KMCR_PASS_FALSE_CARRIER		 0x0800
-
-/* Power Management Control Register (Page 193, Register 20) */
-#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE	 0x0001
-					   /* 1=Enable SERDES Electrical Idle */
-
-/* In-Band Control Register (Page 194, Register 18) */
-#define GG82563_ICR_DIS_PADDING			 0x0010 /* Disable Padding */
-
-/* A table for the GG82563 cable length where the range is defined
- * with a lower bound at "index" and the upper bound at
- * "index + 5".
- */
-static const u16 e1000_gg82563_cable_length_table[] =
-	 { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
-
-static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
-static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
-static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
-static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
-static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
-static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
-static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
-
-/**
- *  e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-
-	if (hw->media_type != e1000_media_type_copper) {
-		phy->type	= e1000_phy_none;
-		return 0;
-	}
-
-	phy->addr		= 1;
-	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us      = 100;
-	phy->type		= e1000_phy_gg82563;
-
-	/* This can only be done after all function pointers are setup. */
-	ret_val = e1000e_get_phy_id(hw);
-
-	/* Verify phy id */
-	if (phy->id != GG82563_E_PHY_ID)
-		return -E1000_ERR_PHY;
-
-	return ret_val;
-}
-
-/**
- *  e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u16 size;
-
-	nvm->opcode_bits	= 8;
-	nvm->delay_usec	 = 1;
-	switch (nvm->override) {
-	case e1000_nvm_override_spi_large:
-		nvm->page_size    = 32;
-		nvm->address_bits = 16;
-		break;
-	case e1000_nvm_override_spi_small:
-		nvm->page_size    = 8;
-		nvm->address_bits = 8;
-		break;
-	default:
-		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
-		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
-		break;
-	}
-
-	nvm->type	       = e1000_nvm_eeprom_spi;
-
-	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
-			  E1000_EECD_SIZE_EX_SHIFT);
-
-	/* Added to a constant, "size" becomes the left-shift value
-	 * for setting word_size.
-	 */
-	size += NVM_WORD_SIZE_BASE_SHIFT;
-	nvm->word_size	= 1 << size;
-
-	return 0;
-}
-
-/**
- *  e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_mac_operations *func = &mac->ops;
-
-	/* Set media type */
-	switch (adapter->pdev->device) {
-	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
-		hw->media_type = e1000_media_type_internal_serdes;
-		break;
-	default:
-		hw->media_type = e1000_media_type_copper;
-		break;
-	}
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid =
-		(er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
-
-	/* check for link */
-	switch (hw->media_type) {
-	case e1000_media_type_copper:
-		func->setup_physical_interface = e1000_setup_copper_link_80003es2lan;
-		func->check_for_link = e1000e_check_for_copper_link;
-		break;
-	case e1000_media_type_fiber:
-		func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
-		func->check_for_link = e1000e_check_for_fiber_link;
-		break;
-	case e1000_media_type_internal_serdes:
-		func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
-		func->check_for_link = e1000e_check_for_serdes_link;
-		break;
-	default:
-		return -E1000_ERR_CONFIG;
-		break;
-	}
-
-	return 0;
-}
-
-static s32 e1000_get_invariants_80003es2lan(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	s32 rc;
-
-	rc = e1000_init_mac_params_80003es2lan(adapter);
-	if (rc)
-		return rc;
-
-	rc = e1000_init_nvm_params_80003es2lan(hw);
-	if (rc)
-		return rc;
-
-	rc = e1000_init_phy_params_80003es2lan(hw);
-	if (rc)
-		return rc;
-
-	return 0;
-}
-
-/**
- *  e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
- *  @hw: pointer to the HW structure
- *
- *  A wrapper to acquire access rights to the correct PHY.  This is a
- *  function pointer entry point called by the api module.
- **/
-static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
-{
-	u16 mask;
-
-	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
-
-	return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
-}
-
-/**
- *  e1000_release_phy_80003es2lan - Release rights to access PHY
- *  @hw: pointer to the HW structure
- *
- *  A wrapper to release access rights to the correct PHY.  This is a
- *  function pointer entry point called by the api module.
- **/
-static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
-{
-	u16 mask;
-
-	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
-	e1000_release_swfw_sync_80003es2lan(hw, mask);
-}
-
-/**
- *  e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
- *  @hw: pointer to the HW structure
- *
- *  Acquire the semaphore to access the EEPROM.  This is a function
- *  pointer entry point called by the api module.
- **/
-static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000e_acquire_nvm(hw);
-
-	if (ret_val)
-		e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-
-	return ret_val;
-}
-
-/**
- *  e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
- *  @hw: pointer to the HW structure
- *
- *  Release the semaphore used to access the EEPROM.  This is a
- *  function pointer entry point called by the api module.
- **/
-static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
-{
-	e1000e_release_nvm(hw);
-	e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-}
-
-/**
- *  e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
- *  @hw: pointer to the HW structure
- *  @mask: specifies which semaphore to acquire
- *
- *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
- *  will also specify which port we're acquiring the lock for.
- **/
-static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
-{
-	u32 swfw_sync;
-	u32 swmask = mask;
-	u32 fwmask = mask << 16;
-	s32 i = 0;
-	s32 timeout = 200;
-
-	while (i < timeout) {
-		if (e1000e_get_hw_semaphore(hw))
-			return -E1000_ERR_SWFW_SYNC;
-
-		swfw_sync = er32(SW_FW_SYNC);
-		if (!(swfw_sync & (fwmask | swmask)))
-			break;
-
-		/* Firmware currently using resource (fwmask)
-		 * or other software thread using resource (swmask) */
-		e1000e_put_hw_semaphore(hw);
-		mdelay(5);
-		i++;
-	}
-
-	if (i == timeout) {
-		hw_dbg(hw,
-		       "Driver can't access resource, SW_FW_SYNC timeout.\n");
-		return -E1000_ERR_SWFW_SYNC;
-	}
-
-	swfw_sync |= swmask;
-	ew32(SW_FW_SYNC, swfw_sync);
-
-	e1000e_put_hw_semaphore(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
- *  @hw: pointer to the HW structure
- *  @mask: specifies which semaphore to acquire
- *
- *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
- *  will also specify which port we're releasing the lock for.
- **/
-static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
-{
-	u32 swfw_sync;
-
-	while (e1000e_get_hw_semaphore(hw) != 0);
-	/* Empty */
-
-	swfw_sync = er32(SW_FW_SYNC);
-	swfw_sync &= ~mask;
-	ew32(SW_FW_SYNC, swfw_sync);
-
-	e1000e_put_hw_semaphore(hw);
-}
-
-/**
- *  e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: offset of the register to read
- *  @data: pointer to the data returned from the operation
- *
- *  Read the GG82563 PHY register.  This is a function pointer entry
- *  point called by the api module.
- **/
-static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
-						  u32 offset, u16 *data)
-{
-	s32 ret_val;
-	u32 page_select;
-	u16 temp;
-
-	/* Select Configuration Page */
-	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
-		page_select = GG82563_PHY_PAGE_SELECT;
-	else
-		/* Use Alternative Page Select register to access
-		 * registers 30 and 31
-		 */
-		page_select = GG82563_PHY_PAGE_SELECT_ALT;
-
-	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
-	ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
-	if (ret_val)
-		return ret_val;
-
-	/* The "ready" bit in the MDIC register may be incorrectly set
-	 * before the device has completed the "Page Select" MDI
-	 * transaction.  So we wait 200us after each MDI command...
-	 */
-	udelay(200);
-
-	/* ...and verify the command was successful. */
-	ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
-
-	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
-		ret_val = -E1000_ERR_PHY;
-		return ret_val;
-	}
-
-	udelay(200);
-
-	ret_val = e1000e_read_phy_reg_m88(hw,
-					 MAX_PHY_REG_ADDRESS & offset,
-					 data);
-
-	udelay(200);
-
-	return ret_val;
-}
-
-/**
- *  e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: offset of the register to read
- *  @data: value to write to the register
- *
- *  Write to the GG82563 PHY register.  This is a function pointer entry
- *  point called by the api module.
- **/
-static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
-						   u32 offset, u16 data)
-{
-	s32 ret_val;
-	u32 page_select;
-	u16 temp;
-
-	/* Select Configuration Page */
-	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
-		page_select = GG82563_PHY_PAGE_SELECT;
-	else
-		/* Use Alternative Page Select register to access
-		 * registers 30 and 31
-		 */
-		page_select = GG82563_PHY_PAGE_SELECT_ALT;
-
-	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
-	ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
-	if (ret_val)
-		return ret_val;
-
-
-	/* The "ready" bit in the MDIC register may be incorrectly set
-	 * before the device has completed the "Page Select" MDI
-	 * transaction.  So we wait 200us after each MDI command...
-	 */
-	udelay(200);
-
-	/* ...and verify the command was successful. */
-	ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
-
-	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp)
-		return -E1000_ERR_PHY;
-
-	udelay(200);
-
-	ret_val = e1000e_write_phy_reg_m88(hw,
-					  MAX_PHY_REG_ADDRESS & offset,
-					  data);
-
-	udelay(200);
-
-	return ret_val;
-}
-
-/**
- *  e1000_write_nvm_80003es2lan - Write to ESB2 NVM
- *  @hw: pointer to the HW structure
- *  @offset: offset of the register to read
- *  @words: number of words to write
- *  @data: buffer of data to write to the NVM
- *
- *  Write "words" of data to the ESB2 NVM.  This is a function
- *  pointer entry point called by the api module.
- **/
-static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
-				       u16 words, u16 *data)
-{
-	return e1000e_write_nvm_spi(hw, offset, words, data);
-}
-
-/**
- *  e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
- *  @hw: pointer to the HW structure
- *
- *  Wait a specific amount of time for manageability processes to complete.
- *  This is a function pointer entry point called by the phy module.
- **/
-static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
-{
-	s32 timeout = PHY_CFG_TIMEOUT;
-	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
-
-	if (hw->bus.func == 1)
-		mask = E1000_NVM_CFG_DONE_PORT_1;
-
-	while (timeout) {
-		if (er32(EEMNGCTL) & mask)
-			break;
-		msleep(1);
-		timeout--;
-	}
-	if (!timeout) {
-		hw_dbg(hw, "MNG configuration cycle has not completed.\n");
-		return -E1000_ERR_RESET;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
- *  @hw: pointer to the HW structure
- *
- *  Force the speed and duplex settings onto the PHY.  This is a
- *  function pointer entry point called by the phy module.
- **/
-static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	/* Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
-	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data);
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	/* Reset the phy to commit changes. */
-	phy_data |= MII_CR_RESET;
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	udelay(1);
-
-	if (hw->phy.wait_for_link) {
-		hw_dbg(hw, "Waiting for forced speed/duplex link "
-			 "on GG82563 phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-						     100000, &link);
-		if (ret_val)
-			return ret_val;
-
-		if (!link) {
-			/* We didn't get link.
-			 * Reset the DSP and cross our fingers.
-			 */
-			ret_val = e1000e_phy_reset_dsp(hw);
-			if (ret_val)
-				return ret_val;
-		}
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-						     100000, &link);
-		if (ret_val)
-			return ret_val;
-	}
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	/* Resetting the phy means we need to verify the TX_CLK corresponds
-	 * to the link speed.  10Mbps -> 2.5MHz, else 25MHz.
-	 */
-	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
-	if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
-		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
-	else
-		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
-
-	/* In addition, we must re-enable CRS on Tx for both half and full
-	 * duplex.
-	 */
-	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
-	ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
-
-	return ret_val;
-}
-
-/**
- *  e1000_get_cable_length_80003es2lan - Set approximate cable length
- *  @hw: pointer to the HW structure
- *
- *  Find the approximate cable length as measured by the GG82563 PHY.
- *  This is a function pointer entry point called by the phy module.
- **/
-static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	u16 index;
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	index = phy_data & GG82563_DSPD_CABLE_LENGTH;
-	phy->min_cable_length = e1000_gg82563_cable_length_table[index];
-	phy->max_cable_length = e1000_gg82563_cable_length_table[index+5];
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-	return 0;
-}
-
-/**
- *  e1000_get_link_up_info_80003es2lan - Report speed and duplex
- *  @hw: pointer to the HW structure
- *  @speed: pointer to speed buffer
- *  @duplex: pointer to duplex buffer
- *
- *  Retrieve the current speed and duplex configuration.
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
-					      u16 *duplex)
-{
-	s32 ret_val;
-
-	if (hw->media_type == e1000_media_type_copper) {
-		ret_val = e1000e_get_speed_and_duplex_copper(hw,
-								    speed,
-								    duplex);
-		if (ret_val)
-			return ret_val;
-		if (*speed == SPEED_1000)
-			ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
-		else
-			ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw,
-							      *duplex);
-	} else {
-		ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
-								  speed,
-								  duplex);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_reset_hw_80003es2lan - Reset the ESB2 controller
- *  @hw: pointer to the HW structure
- *
- *  Perform a global reset to the ESB2 controller.
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	u32 icr;
-	s32 ret_val;
-
-	/* Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = e1000e_disable_pcie_master(hw);
-	if (ret_val)
-		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
-
-	hw_dbg(hw, "Masking off all interrupts\n");
-	ew32(IMC, 0xffffffff);
-
-	ew32(RCTL, 0);
-	ew32(TCTL, E1000_TCTL_PSP);
-	e1e_flush();
-
-	msleep(10);
-
-	ctrl = er32(CTRL);
-
-	hw_dbg(hw, "Issuing a global reset to MAC\n");
-	ew32(CTRL, ctrl | E1000_CTRL_RST);
-
-	ret_val = e1000e_get_auto_rd_done(hw);
-	if (ret_val)
-		/* We don't want to continue accessing MAC registers. */
-		return ret_val;
-
-	/* Clear any pending interrupt events. */
-	ew32(IMC, 0xffffffff);
-	icr = er32(ICR);
-
-	return 0;
-}
-
-/**
- *  e1000_init_hw_80003es2lan - Initialize the ESB2 controller
- *  @hw: pointer to the HW structure
- *
- *  Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
- *  This is a function pointer entry point called by the api module.
- **/
-static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 reg_data;
-	s32 ret_val;
-	u16 i;
-
-	e1000_initialize_hw_bits_80003es2lan(hw);
-
-	/* Initialize identification LED */
-	ret_val = e1000e_id_led_init(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error initializing identification LED\n");
-		return ret_val;
-	}
-
-	/* Disabling VLAN filtering */
-	hw_dbg(hw, "Initializing the IEEE VLAN\n");
-	e1000e_clear_vfta(hw);
-
-	/* Setup the receive address. */
-	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	hw_dbg(hw, "Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/* Setup link and flow control */
-	ret_val = e1000e_setup_link(hw);
-
-	/* Set the transmit descriptor write-back policy */
-	reg_data = er32(TXDCTL);
-	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-		   E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
-	ew32(TXDCTL, reg_data);
-
-	/* ...for both queues. */
-	reg_data = er32(TXDCTL1);
-	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-		   E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
-	ew32(TXDCTL1, reg_data);
-
-	/* Enable retransmit on late collisions */
-	reg_data = er32(TCTL);
-	reg_data |= E1000_TCTL_RTLC;
-	ew32(TCTL, reg_data);
-
-	/* Configure Gigabit Carry Extend Padding */
-	reg_data = er32(TCTL_EXT);
-	reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
-	reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
-	ew32(TCTL_EXT, reg_data);
-
-	/* Configure Transmit Inter-Packet Gap */
-	reg_data = er32(TIPG);
-	reg_data &= ~E1000_TIPG_IPGT_MASK;
-	reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
-	ew32(TIPG, reg_data);
-
-	reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
-	reg_data &= ~0x00100000;
-	E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
-
-	/* Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_80003es2lan(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
- *  @hw: pointer to the HW structure
- *
- *  Initializes required hardware-dependent bits needed for normal operation.
- **/
-static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
-{
-	u32 reg;
-
-	/* Transmit Descriptor Control 0 */
-	reg = er32(TXDCTL);
-	reg |= (1 << 22);
-	ew32(TXDCTL, reg);
-
-	/* Transmit Descriptor Control 1 */
-	reg = er32(TXDCTL1);
-	reg |= (1 << 22);
-	ew32(TXDCTL1, reg);
-
-	/* Transmit Arbitration Control 0 */
-	reg = er32(TARC0);
-	reg &= ~(0xF << 27); /* 30:27 */
-	if (hw->media_type != e1000_media_type_copper)
-		reg &= ~(1 << 20);
-	ew32(TARC0, reg);
-
-	/* Transmit Arbitration Control 1 */
-	reg = er32(TARC1);
-	if (er32(TCTL) & E1000_TCTL_MULR)
-		reg &= ~(1 << 28);
-	else
-		reg |= (1 << 28);
-	ew32(TARC1, reg);
-}
-
-/**
- *  e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
- *  @hw: pointer to the HW structure
- *
- *  Setup some GG82563 PHY registers for obtaining link
- **/
-static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u32 ctrl_ext;
-	u16 data;
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
-				     &data);
-	if (ret_val)
-		return ret_val;
-
-	data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
-	/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
-	data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
-
-	ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
-				      data);
-	if (ret_val)
-		return ret_val;
-
-	/* Options:
-	 *   MDI/MDI-X = 0 (default)
-	 *   0 - Auto for all speeds
-	 *   1 - MDI mode
-	 *   2 - MDI-X mode
-	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-	 */
-	ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data);
-	if (ret_val)
-		return ret_val;
-
-	data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
-
-	switch (phy->mdix) {
-	case 1:
-		data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
-		break;
-	case 2:
-		data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
-		break;
-	case 0:
-	default:
-		data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
-		break;
-	}
-
-	/* Options:
-	 *   disable_polarity_correction = 0 (default)
-	 *       Automatic Correction for Reversed Cable Polarity
-	 *   0 - Disabled
-	 *   1 - Enabled
-	 */
-	data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
-	if (phy->disable_polarity_correction)
-		data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
-
-	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data);
-	if (ret_val)
-		return ret_val;
-
-	/* SW Reset the PHY so all changes take effect */
-	ret_val = e1000e_commit_phy(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error Resetting the PHY\n");
-		return ret_val;
-	}
-
-	/* Bypass RX and TX FIFO's */
-	ret_val = e1000e_write_kmrn_reg(hw,
-				E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
-				E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
-					E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
-	if (ret_val)
-		return ret_val;
-
-	data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
-	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data);
-	if (ret_val)
-		return ret_val;
-
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
-	ew32(CTRL_EXT, ctrl_ext);
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
-	if (ret_val)
-		return ret_val;
-
-	/* Do not init these registers when the HW is in IAMT mode, since the
-	 * firmware will have already initialized them.  We only initialize
-	 * them if the HW is not in IAMT mode.
-	 */
-	if (!e1000e_check_mng_mode(hw)) {
-		/* Enable Electrical Idle on the PHY */
-		data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
-		ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, data);
-		if (ret_val)
-			return ret_val;
-
-		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
-		if (ret_val)
-			return ret_val;
-
-		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-		ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Workaround: Disable padding in Kumeran interface in the MAC
-	 * and in the PHY to avoid CRC errors.
-	 */
-	ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data);
-	if (ret_val)
-		return ret_val;
-
-	data |= GG82563_ICR_DIS_PADDING;
-	ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data);
-	if (ret_val)
-		return ret_val;
-
-	return 0;
-}
-
-/**
- *  e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
- *  @hw: pointer to the HW structure
- *
- *  Essentially a wrapper for setting up all things "copper" related.
- *  This is a function pointer entry point called by the mac module.
- **/
-static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-	u16 reg_data;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ew32(CTRL, ctrl);
-
-	/* Set the mac to wait the maximum time between each
-	 * iteration and increase the max iterations when
-	 * polling the phy; this fixes erroneous timeouts at 10Mbps. */
-	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
-	if (ret_val)
-		return ret_val;
-	ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
-	if (ret_val)
-		return ret_val;
-	reg_data |= 0x3F;
-	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
-	if (ret_val)
-		return ret_val;
-	ret_val = e1000e_read_kmrn_reg(hw,
-				      E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
-				      &reg_data);
-	if (ret_val)
-		return ret_val;
-	reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
-	ret_val = e1000e_write_kmrn_reg(hw,
-				       E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
-				       reg_data);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000e_setup_copper_link(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
- *  @hw: pointer to the HW structure
- *  @duplex: current duplex setting
- *
- *  Configure the KMRN interface by applying last minute quirks for
- *  10/100 operation.
- **/
-static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
-{
-	s32 ret_val;
-	u32 tipg;
-	u16 reg_data;
-
-	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
-	ret_val = e1000e_write_kmrn_reg(hw,
-				       E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
-				       reg_data);
-	if (ret_val)
-		return ret_val;
-
-	/* Configure Transmit Inter-Packet Gap */
-	tipg = er32(TIPG);
-	tipg &= ~E1000_TIPG_IPGT_MASK;
-	tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
-	ew32(TIPG, tipg);
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
-	if (ret_val)
-		return ret_val;
-
-	if (duplex == HALF_DUPLEX)
-		reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
-	else
-		reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-
-	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
-
-	return 0;
-}
-
-/**
- *  e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
- *  @hw: pointer to the HW structure
- *
- *  Configure the KMRN interface by applying last minute quirks for
- *  gigabit operation.
- **/
-static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 reg_data;
-	u32 tipg;
-
-	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
-	ret_val = e1000e_write_kmrn_reg(hw,
-				       E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
-				       reg_data);
-	if (ret_val)
-		return ret_val;
-
-	/* Configure Transmit Inter-Packet Gap */
-	tipg = er32(TIPG);
-	tipg &= ~E1000_TIPG_IPGT_MASK;
-	tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
-	ew32(TIPG, tipg);
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
-	if (ret_val)
-		return ret_val;
-
-	reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
-
-	return ret_val;
-}
-
-/**
- *  e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
-{
-	u32 temp;
-
-	e1000e_clear_hw_cntrs_base(hw);
-
-	temp = er32(PRC64);
-	temp = er32(PRC127);
-	temp = er32(PRC255);
-	temp = er32(PRC511);
-	temp = er32(PRC1023);
-	temp = er32(PRC1522);
-	temp = er32(PTC64);
-	temp = er32(PTC127);
-	temp = er32(PTC255);
-	temp = er32(PTC511);
-	temp = er32(PTC1023);
-	temp = er32(PTC1522);
-
-	temp = er32(ALGNERRC);
-	temp = er32(RXERRC);
-	temp = er32(TNCRS);
-	temp = er32(CEXTERR);
-	temp = er32(TSCTC);
-	temp = er32(TSCTFC);
-
-	temp = er32(MGTPRC);
-	temp = er32(MGTPDC);
-	temp = er32(MGTPTC);
-
-	temp = er32(IAC);
-	temp = er32(ICRXOC);
-
-	temp = er32(ICRXPTC);
-	temp = er32(ICRXATC);
-	temp = er32(ICTXPTC);
-	temp = er32(ICTXATC);
-	temp = er32(ICTXQEC);
-	temp = er32(ICTXQMTC);
-	temp = er32(ICRXDMTC);
-}
-
-static struct e1000_mac_operations es2_mac_ops = {
-	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
-	/* check_for_link dependent on media type */
-	.cleanup_led		= e1000e_cleanup_led_generic,
-	.clear_hw_cntrs		= e1000_clear_hw_cntrs_80003es2lan,
-	.get_bus_info		= e1000e_get_bus_info_pcie,
-	.get_link_up_info	= e1000_get_link_up_info_80003es2lan,
-	.led_on			= e1000e_led_on_generic,
-	.led_off		= e1000e_led_off_generic,
-	.mc_addr_list_update	= e1000e_mc_addr_list_update_generic,
-	.reset_hw		= e1000_reset_hw_80003es2lan,
-	.init_hw		= e1000_init_hw_80003es2lan,
-	.setup_link		= e1000e_setup_link,
-	/* setup_physical_interface dependent on media type */
-};
-
-static struct e1000_phy_operations es2_phy_ops = {
-	.acquire_phy		= e1000_acquire_phy_80003es2lan,
-	.check_reset_block	= e1000e_check_reset_block_generic,
-	.commit_phy	 	= e1000e_phy_sw_reset,
-	.force_speed_duplex 	= e1000_phy_force_speed_duplex_80003es2lan,
-	.get_cfg_done       	= e1000_get_cfg_done_80003es2lan,
-	.get_cable_length   	= e1000_get_cable_length_80003es2lan,
-	.get_phy_info       	= e1000e_get_phy_info_m88,
-	.read_phy_reg       	= e1000_read_phy_reg_gg82563_80003es2lan,
-	.release_phy		= e1000_release_phy_80003es2lan,
-	.reset_phy	  	= e1000e_phy_hw_reset_generic,
-	.set_d0_lplu_state  	= NULL,
-	.set_d3_lplu_state  	= e1000e_set_d3_lplu_state,
-	.write_phy_reg      	= e1000_write_phy_reg_gg82563_80003es2lan,
-};
-
-static struct e1000_nvm_operations es2_nvm_ops = {
-	.acquire_nvm		= e1000_acquire_nvm_80003es2lan,
-	.read_nvm		= e1000e_read_nvm_eerd,
-	.release_nvm		= e1000_release_nvm_80003es2lan,
-	.update_nvm		= e1000e_update_nvm_checksum_generic,
-	.valid_led_default	= e1000e_valid_led_default,
-	.validate_nvm		= e1000e_validate_nvm_checksum_generic,
-	.write_nvm		= e1000_write_nvm_80003es2lan,
-};
-
-struct e1000_info e1000_es2_info = {
-	.mac			= e1000_80003es2lan,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_STATS_PTC_PRC
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_STATS_ICR_ICT
-				  | FLAG_RX_NEEDS_RESTART /* errata */
-				  | FLAG_TARC_SET_BIT_ZERO /* errata */
-				  | FLAG_APME_CHECK_PORT_B
-				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
-				  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
-	.pba			= 38,
-	.get_invariants		= e1000_get_invariants_80003es2lan,
-	.mac_ops		= &es2_mac_ops,
-	.phy_ops		= &es2_phy_ops,
-	.nvm_ops		= &es2_nvm_ops,
-};
-
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/ethtool.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/ethtool.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/ethtool.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/ethtool.c	2008-06-23 18:27:33.000000000 +0200
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -29,11 +29,19 @@
 /* ethtool support for e1000 */
 
 #include <linux/netdevice.h>
+#ifdef SIOCETHTOOL
 #include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 
 #include "e1000.h"
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#endif
+
+#ifdef ETHTOOL_OPS_COMPAT
+#include "kcompat_ethtool.c"
+#endif
 
 struct e1000_stats {
 	char stat_string[ETH_GSTRING_LEN];
@@ -46,8 +54,8 @@
 static const struct e1000_stats e1000_gstrings_stats[] = {
 	{ "rx_packets", E1000_STAT(stats.gprc) },
 	{ "tx_packets", E1000_STAT(stats.gptc) },
-	{ "rx_bytes", E1000_STAT(stats.gorcl) },
-	{ "tx_bytes", E1000_STAT(stats.gotcl) },
+	{ "rx_bytes", E1000_STAT(stats.gorc) },
+	{ "tx_bytes", E1000_STAT(stats.gotc) },
 	{ "rx_broadcast", E1000_STAT(stats.bprc) },
 	{ "tx_broadcast", E1000_STAT(stats.bptc) },
 	{ "rx_multicast", E1000_STAT(stats.mprc) },
@@ -83,7 +91,7 @@
 	{ "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
 	{ "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
 	{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
-	{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
+	{ "rx_long_byte_count", E1000_STAT(stats.gorc) },
 	{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
 	{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
 	{ "rx_header_split", E1000_STAT(rx_hdr_split) },
@@ -103,7 +111,7 @@
 	"Interrupt test (offline)", "Loopback test  (offline)",
 	"Link test   (on/offline)"
 };
-#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
+#define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test)
 
 static int e1000_get_settings(struct net_device *netdev,
 			      struct ethtool_cmd *ecmd)
@@ -112,7 +120,7 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 status;
 
-	if (hw->media_type == e1000_media_type_copper) {
+	if (hw->phy.media_type == e1000_media_type_copper) {
 
 		ecmd->supported = (SUPPORTED_10baseT_Half |
 				   SUPPORTED_10baseT_Full |
@@ -166,7 +174,7 @@
 		ecmd->duplex = -1;
 	}
 
-	ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) ||
+	ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
 			 hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
 	return 0;
 }
@@ -188,10 +196,9 @@
 	mac->autoneg = 0;
 
 	/* Fiber NICs only allow 1000 gbps Full duplex */
-	if ((adapter->hw.media_type == e1000_media_type_fiber) &&
+	if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
 		spddplx != (SPEED_1000 + DUPLEX_FULL)) {
-		ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
-			 "configuration\n");
+		e_err("Unsupported Speed/Duplex configuration\n");
 		return -EINVAL;
 	}
 
@@ -214,8 +221,7 @@
 		break;
 	case SPEED_1000 + DUPLEX_HALF: /* not supported */
 	default:
-		ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
-			 "configuration\n");
+		e_err("Unsupported Speed/Duplex configuration\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -227,11 +233,14 @@
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
-	/* When SoL/IDER sessions are active, autoneg/speed/duplex
-	 * cannot be changed */
-	if (e1000_check_reset_block(hw)) {
-		ndev_err(netdev, "Cannot change link "
-			 "characteristics when SoL/IDER is active.\n");
+	/*
+	 * When SoL/IDER sessions are active, autoneg/speed/duplex
+	 * cannot be changed
+	 */
+	if (hw->phy.ops.check_reset_block &&
+	    hw->phy.ops.check_reset_block(&adapter->hw)) {
+		e_err("Cannot change link characteristics when SoL/IDER"
+		      " is active.\n");
 		return -EINVAL;
 	}
 
@@ -240,7 +249,7 @@
 
 	if (ecmd->autoneg == AUTONEG_ENABLE) {
 		hw->mac.autoneg = 1;
-		if (hw->media_type == e1000_media_type_fiber)
+		if (hw->phy.media_type == e1000_media_type_fiber)
 			hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
 						     ADVERTISED_FIBRE |
 						     ADVERTISED_Autoneg;
@@ -249,6 +258,8 @@
 						     ADVERTISED_TP |
 						     ADVERTISED_Autoneg;
 		ecmd->advertising = hw->phy.autoneg_advertised;
+		if (adapter->fc_autoneg)
+			hw->fc.original_type = e1000_fc_default;
 	} else {
 		if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
 			clear_bit(__E1000_RESETTING, &adapter->state);
@@ -259,10 +270,10 @@
 	/* reset the link */
 
 	if (netif_running(adapter->netdev)) {
-		e1000e_down(adapter);
-		e1000e_up(adapter);
+		e1000_down(adapter);
+		e1000_up(adapter);
 	} else {
-		e1000e_reset(adapter);
+		e1000_reset(adapter);
 	}
 
 	clear_bit(__E1000_RESETTING, &adapter->state);
@@ -278,11 +289,11 @@
 	pause->autoneg =
 		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
 
-	if (hw->mac.fc == e1000_fc_rx_pause) {
+	if (hw->fc.type == e1000_fc_rx_pause) {
 		pause->rx_pause = 1;
-	} else if (hw->mac.fc == e1000_fc_tx_pause) {
+	} else if (hw->fc.type == e1000_fc_tx_pause) {
 		pause->tx_pause = 1;
-	} else if (hw->mac.fc == e1000_fc_full) {
+	} else if (hw->fc.type == e1000_fc_full) {
 		pause->rx_pause = 1;
 		pause->tx_pause = 1;
 	}
@@ -301,27 +312,28 @@
 		msleep(1);
 
 	if (pause->rx_pause && pause->tx_pause)
-		hw->mac.fc = e1000_fc_full;
+		hw->fc.type = e1000_fc_full;
 	else if (pause->rx_pause && !pause->tx_pause)
-		hw->mac.fc = e1000_fc_rx_pause;
+		hw->fc.type = e1000_fc_rx_pause;
 	else if (!pause->rx_pause && pause->tx_pause)
-		hw->mac.fc = e1000_fc_tx_pause;
+		hw->fc.type = e1000_fc_tx_pause;
 	else if (!pause->rx_pause && !pause->tx_pause)
-		hw->mac.fc = e1000_fc_none;
+		hw->fc.type = e1000_fc_none;
 
-	hw->mac.original_fc = hw->mac.fc;
+	hw->fc.original_type = hw->fc.type;
 
 	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
-		hw->mac.fc = e1000_fc_default;
+		hw->fc.type = e1000_fc_default;
 		if (netif_running(adapter->netdev)) {
-			e1000e_down(adapter);
-			e1000e_up(adapter);
+			e1000_down(adapter);
+			e1000_up(adapter);
 		} else {
-			e1000e_reset(adapter);
+			e1000_reset(adapter);
 		}
 	} else {
-		retval = ((hw->media_type == e1000_media_type_fiber) ?
-			  hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw));
+		retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
+				hw->mac.ops.setup_link(hw) :
+				e1000_force_mac_fc_generic(hw));
 	}
 
 	clear_bit(__E1000_RESETTING, &adapter->state);
@@ -344,9 +356,9 @@
 		adapter->flags &= ~FLAG_RX_CSUM_ENABLED;
 
 	if (netif_running(netdev))
-		e1000e_reinit_locked(adapter);
+		e1000_reinit_locked(adapter);
 	else
-		e1000e_reset(adapter);
+		e1000_reset(adapter);
 	return 0;
 }
 
@@ -365,23 +377,47 @@
 	return 0;
 }
 
+#ifdef NETIF_F_TSO
 static int e1000_set_tso(struct net_device *netdev, u32 data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int i;
+	struct net_device *v_netdev;
 
 	if (data) {
 		netdev->features |= NETIF_F_TSO;
+#ifdef NETIF_F_TSO6
 		netdev->features |= NETIF_F_TSO6;
+#endif
 	} else {
 		netdev->features &= ~NETIF_F_TSO;
+#ifdef NETIF_F_TSO6
 		netdev->features &= ~NETIF_F_TSO6;
-	}
-
-	ndev_info(netdev, "TSO is %s\n",
-		  data ? "Enabled" : "Disabled");
+#endif
+#ifdef NETIF_F_HW_VLAN_TX
+		/* disable TSO on all VLANs if they're present */
+		if (!adapter->vlgrp)
+			goto tso_out;
+		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+			v_netdev = vlan_group_get_device(adapter->vlgrp, i);
+			if (!v_netdev)
+				continue;
+
+			v_netdev->features &= ~NETIF_F_TSO;
+#ifdef NETIF_F_TSO6
+			v_netdev->features &= ~NETIF_F_TSO6;
+#endif
+			vlan_group_set_device(adapter->vlgrp, i, v_netdev);
+		}
+#endif
+	}
+ 
+tso_out:
+	e_info("TSO is %s\n", data ? "Enabled" : "Disabled");
 	adapter->flags |= FLAG_TSO_FORCE;
 	return 0;
 }
+#endif
 
 static u32 e1000_get_msglevel(struct net_device *netdev)
 {
@@ -420,25 +456,25 @@
 	regs_buff[1]  = er32(STATUS);
 
 	regs_buff[2]  = er32(RCTL);
-	regs_buff[3]  = er32(RDLEN);
-	regs_buff[4]  = er32(RDH);
-	regs_buff[5]  = er32(RDT);
+	regs_buff[3]  = er32(RDLEN(0));
+	regs_buff[4]  = er32(RDH(0));
+	regs_buff[5]  = er32(RDT(0));
 	regs_buff[6]  = er32(RDTR);
 
 	regs_buff[7]  = er32(TCTL);
-	regs_buff[8]  = er32(TDLEN);
-	regs_buff[9]  = er32(TDH);
-	regs_buff[10] = er32(TDT);
+	regs_buff[8]  = er32(TDLEN(0));
+	regs_buff[9]  = er32(TDH(0));
+	regs_buff[10] = er32(TDT(0));
 	regs_buff[11] = er32(TIDV);
 
 	regs_buff[12] = adapter->hw.phy.type;  /* PHY type (IGP=1, M88=0) */
 	if (hw->phy.type == e1000_phy_m88) {
-		e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+		hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
 		regs_buff[13] = (u32)phy_data; /* cable length */
 		regs_buff[14] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
 		regs_buff[15] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
 		regs_buff[16] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
-		e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+		hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
 		regs_buff[17] = (u32)phy_data; /* extended 10bt distance */
 		regs_buff[18] = regs_buff[13]; /* cable polarity */
 		regs_buff[19] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
@@ -448,7 +484,7 @@
 		regs_buff[23] = regs_buff[13]; /* mdix mode */
 	}
 	regs_buff[21] = adapter->phy_stats.idle_errors;  /* phy idle errors */
-	e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+	hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
 	regs_buff[24] = (u32)phy_data;  /* phy local receiver status */
 	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
 }
@@ -484,13 +520,13 @@
 		return -ENOMEM;
 
 	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
-		ret_val = e1000_read_nvm(hw, first_word,
-					 last_word - first_word + 1,
-					 eeprom_buff);
+		ret_val = hw->nvm.ops.read(hw, first_word,
+		                           last_word - first_word + 1,
+		                           eeprom_buff);
 	} else {
 		for (i = 0; i < last_word - first_word + 1; i++) {
-			ret_val = e1000_read_nvm(hw, first_word + i, 1,
-						      &eeprom_buff[i]);
+			ret_val = hw->nvm.ops.read(hw, first_word + i, 1,
+			                           &eeprom_buff[i]);
 			if (ret_val)
 				break;
 		}
@@ -538,14 +574,14 @@
 	if (eeprom->offset & 1) {
 		/* need read/modify/write of first changed EEPROM word */
 		/* only the second byte of the word is being modified */
-		ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]);
+		ret_val = hw->nvm.ops.read(hw, first_word, 1, &eeprom_buff[0]);
 		ptr++;
 	}
 	if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0))
 		/* need read/modify/write of last changed EEPROM word */
 		/* only the first byte of the word is being modified */
-		ret_val = e1000_read_nvm(hw, last_word, 1,
-				  &eeprom_buff[last_word - first_word]);
+		ret_val = hw->nvm.ops.read(hw, last_word, 1,
+		                          &eeprom_buff[last_word - first_word]);
 
 	/* Device's eeprom is always little-endian, word addressable */
 	for (i = 0; i < last_word - first_word + 1; i++)
@@ -556,14 +592,17 @@
 	for (i = 0; i < last_word - first_word + 1; i++)
 		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
 
-	ret_val = e1000_write_nvm(hw, first_word,
-				  last_word - first_word + 1, eeprom_buff);
+	ret_val = hw->nvm.ops.write(hw, first_word, last_word - first_word + 1,
+	                            eeprom_buff);
 
-	/* Update the checksum over the first part of the EEPROM if needed
-	 * and flush shadow RAM for 82573 controllers */
+	/*
+	 * Update the checksum over the first part of the EEPROM if needed
+	 * and flush shadow RAM for 82573 controllers
+	 */
 	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
+			       (hw->mac.type == e1000_82574) ||
 			       (hw->mac.type == e1000_82573)))
-		e1000e_update_nvm_checksum(hw);
+		hw->nvm.ops.update(hw);
 
 	kfree(eeprom_buff);
 	return ret_val;
@@ -573,15 +612,18 @@
 			      struct ethtool_drvinfo *drvinfo)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 	char firmware_version[32];
 	u16 eeprom_data;
 
 	strncpy(drvinfo->driver,  e1000e_driver_name, 32);
 	strncpy(drvinfo->version, e1000e_driver_version, 32);
 
-	/* EEPROM image version # is reported as firmware version # for
-	 * PCI-E controllers */
-	e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data);
+	/*
+	 * EEPROM image version # is reported as firmware version # for
+	 * PCI-E controllers
+	 */
+	hw->nvm.ops.read(&adapter->hw, 5, 1, &eeprom_data);
 	sprintf(firmware_version, "%d.%d-%d",
 		(eeprom_data & 0xF000) >> 12,
 		(eeprom_data & 0x0FF0) >> 4,
@@ -625,7 +667,7 @@
 		msleep(1);
 
 	if (netif_running(adapter->netdev))
-		e1000e_down(adapter);
+		e1000_down(adapter);
 
 	tx_old = adapter->tx_ring;
 	rx_old = adapter->rx_ring;
@@ -634,10 +676,17 @@
 	tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
 	if (!tx_ring)
 		goto err_alloc_tx;
+	/*
+	 * use a memcpy to save any previously configured
+	 * items like napi structs from having to be
+	 * reinitialized
+	 */
+	memcpy(tx_ring, tx_old, sizeof(struct e1000_ring));
 
 	rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
 	if (!rx_ring)
 		goto err_alloc_rx;
+	memcpy(rx_ring, rx_old, sizeof(struct e1000_ring));
 
 	adapter->tx_ring = tx_ring;
 	adapter->rx_ring = rx_ring;
@@ -652,24 +701,26 @@
 
 	if (netif_running(adapter->netdev)) {
 		/* Try to get new resources before deleting old */
-		err = e1000e_setup_rx_resources(adapter);
+		err = e1000_setup_rx_resources(adapter);
 		if (err)
 			goto err_setup_rx;
-		err = e1000e_setup_tx_resources(adapter);
+		err = e1000_setup_tx_resources(adapter);
 		if (err)
 			goto err_setup_tx;
 
-		/* save the new, restore the old in order to free it,
-		 * then restore the new back again */
+		/*
+		 * restore the old in order to free it,
+		 * then add in the new
+		 */
 		adapter->rx_ring = rx_old;
 		adapter->tx_ring = tx_old;
-		e1000e_free_rx_resources(adapter);
-		e1000e_free_tx_resources(adapter);
+		e1000_free_rx_resources(adapter);
+		e1000_free_tx_resources(adapter);
 		kfree(tx_old);
 		kfree(rx_old);
 		adapter->rx_ring = rx_ring;
 		adapter->tx_ring = tx_ring;
-		err = e1000e_up(adapter);
+		err = e1000_up(adapter);
 		if (err)
 			goto err_setup;
 	}
@@ -677,7 +728,7 @@
 	clear_bit(__E1000_RESETTING, &adapter->state);
 	return 0;
 err_setup_tx:
-	e1000e_free_rx_resources(adapter);
+	e1000_free_rx_resources(adapter);
 err_setup_rx:
 	adapter->rx_ring = rx_old;
 	adapter->tx_ring = tx_old;
@@ -685,59 +736,74 @@
 err_alloc_rx:
 	kfree(tx_ring);
 err_alloc_tx:
-	e1000e_up(adapter);
+	e1000_up(adapter);
 err_setup:
 	clear_bit(__E1000_RESETTING, &adapter->state);
 	return err;
 }
 
-#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W)
-#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable)		      \
-{									      \
-	u32 _pat;							      \
-	u32 _value;							      \
-	u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};	      \
-	for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) {		      \
-		E1000_WRITE_REG_ARRAY(hw, reg, offset,	      \
-				      (_test[_pat] & writeable));	      \
-		_value = E1000_READ_REG_ARRAY(hw, reg, offset);     \
-		if (_value != (_test[_pat] & writeable & mask)) {	      \
-			ndev_err(netdev, "pattern test reg %04X "             \
-				 "failed: got 0x%08X expected 0x%08X\n",      \
-				 reg + offset,  \
-				 value, (_test[_pat] & writeable & mask));    \
-			*data = reg;					      \
-			return 1;					      \
-		}							      \
-	}								      \
-}
-
-#define REG_SET_AND_CHECK(R, M, W)					      \
-{									      \
-	u32 _value;							      \
-	__ew32(hw, R, W & M);						\
-	_value = __er32(hw, R);						\
-	if ((W & M) != (_value & M)) {					      \
-		ndev_err(netdev, "set/check reg %04X test failed: "           \
-			 "got 0x%08X expected 0x%08X\n", R, (_value & M),     \
-			 (W & M));					      \
-		*data = R;						      \
-		return 1;						      \
-	}								      \
+static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data,
+			     int reg, int offset, u32 mask, u32 write)
+{
+	u32 pat, val;
+	static const u32 test[] =
+		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+	for (pat = 0; pat < ARRAY_SIZE(test); pat++) {
+		E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset,
+		                      (test[pat] & write));
+		val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset);
+		if (val != (test[pat] & write & mask)) {
+			e_err("pattern test reg %04X failed: got "
+			      "0x%08X expected 0x%08X\n",
+			      reg + offset,
+			      val, (test[pat] & write & mask));
+			*data = reg;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data,
+			      int reg, u32 mask, u32 write)
+{
+	u32 val;
+	__ew32(&adapter->hw, reg, write & mask);
+	val = __er32(&adapter->hw, reg);
+	if ((write & mask) != (val & mask)) {
+		e_err("set/check reg %04X test failed: got 0x%08X"
+		      "expected 0x%08X\n", reg, (val & mask), (write & mask));
+		*data = reg;
+		return 1;
+	}
+	return 0;
 }
+#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write)                       \
+	do {                                                                   \
+		if (reg_pattern_test(adapter, data, reg, offset, mask, write)) \
+			return 1;                                              \
+	} while (0)
+#define REG_PATTERN_TEST(reg, mask, write)                                     \
+	REG_PATTERN_TEST_ARRAY(reg, 0, mask, write)
+
+#define REG_SET_AND_CHECK(reg, mask, write)                                    \
+	do {                                                                   \
+		if (reg_set_and_check(adapter, data, reg, mask, write))        \
+			return 1;                                              \
+	} while (0)
 
 static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
 {
 	struct e1000_hw *hw = &adapter->hw;
 	struct e1000_mac_info *mac = &adapter->hw.mac;
-	struct net_device *netdev = adapter->netdev;
 	u32 value;
 	u32 before;
 	u32 after;
 	u32 i;
 	u32 toggle;
 
-	/* The status register is Read Only, so a write should fail.
+	/*
+	 * The status register is Read Only, so a write should fail.
 	 * Some bits that get toggled are ignored.
 	 */
 	switch (mac->type) {
@@ -748,8 +814,10 @@
 		toggle = 0x7FFFF3FF;
 		break;
 	case e1000_82573:
+	case e1000_82574:
 	case e1000_ich8lan:
 	case e1000_ich9lan:
+	case e1000_ich10lan:
 		toggle = 0x7FFFF033;
 		break;
 	default:
@@ -762,7 +830,7 @@
 	ew32(STATUS, toggle);
 	after = er32(STATUS) & toggle;
 	if (value != after) {
-		ndev_err(netdev, "failed STATUS register test got: "
+		e_err("failed STATUS register test got: "
 			 "0x%08X expected: 0x%08X\n", after, value);
 		*data = 1;
 		return 1;
@@ -770,8 +838,7 @@
 	/* restore previous status */
 	ew32(STATUS, before);
 
-	if ((mac->type != e1000_ich8lan) &&
-	    (mac->type != e1000_ich9lan)) {
+	if (!(adapter->flags & FLAG_IS_ICH)) {
 		REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
 		REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF);
 		REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF);
@@ -779,33 +846,33 @@
 	}
 
 	REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF);
-	REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
-	REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF);
-	REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF);
-	REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF);
+	REG_PATTERN_TEST(E1000_RDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_RDLEN(0), 0x000FFF80, 0x000FFFFF);
+	REG_PATTERN_TEST(E1000_RDH(0), 0x0000FFFF, 0x0000FFFF);
+	REG_PATTERN_TEST(E1000_RDT(0), 0x0000FFFF, 0x0000FFFF);
 	REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8);
 	REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF);
 	REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
-	REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
-	REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF);
+	REG_PATTERN_TEST(E1000_TDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_TDLEN(0), 0x000FFF80, 0x000FFFFF);
 
 	REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000);
 
-	before = (((mac->type == e1000_ich8lan) ||
-		   (mac->type == e1000_ich9lan)) ? 0x06C3B33E : 0x06DFB3FE);
+	before = ((adapter->flags & FLAG_IS_ICH) ? 0x06C3B33E : 0x06DFB3FE);
 	REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB);
 	REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000);
 
 	REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF);
-	REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
-	if ((mac->type != e1000_ich8lan) &&
-	    (mac->type != e1000_ich9lan))
+	REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF);
+	if (!(adapter->flags & FLAG_IS_ICH))
 		REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
-	REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF);
 	REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
 	for (i = 0; i < mac->rar_entry_count; i++)
 		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
-				       0x8003FFFF, 0xFFFFFFFF);
+				       ((mac->type == e1000_ich10lan) ?
+		                           0x8007FFFF : 0x8003FFFF),
+		                       0xFFFFFFFF);
 
 	for (i = 0; i < mac->mta_reg_count; i++)
 		REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
@@ -816,6 +883,7 @@
 
 static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
 {
+	struct e1000_hw *hw = &adapter->hw;
 	u16 temp;
 	u16 checksum = 0;
 	u16 i;
@@ -823,7 +891,7 @@
 	*data = 0;
 	/* Read and add up the contents of the EEPROM */
 	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
-		if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) {
+		if ((hw->nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) {
 			*data = 1;
 			break;
 		}
@@ -856,10 +924,22 @@
 	u32 shared_int = 1;
 	u32 irq = adapter->pdev->irq;
 	int i;
+#ifdef CONFIG_E1000E_MSIX
+	int ret_val = 0;
+	int int_mode = E1000E_INT_MODE_LEGACY;
+#endif
 
 	*data = 0;
 
-	/* NOTE: we don't test MSI interrupts here, yet */
+	/* NOTE: we don't test MSI/MSI-X interrupts here, yet */
+#ifdef CONFIG_E1000E_MSIX
+	if (adapter->int_mode == E1000E_INT_MODE_MSIX) {
+		int_mode = adapter->int_mode;
+		e1000_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
+		e1000_set_interrupt_capability(adapter);
+	}
+#endif
 	/* Hook up test interrupt handler just for this test */
 	if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
 			 netdev)) {
@@ -867,10 +947,14 @@
 	} else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
 		 netdev->name, netdev)) {
 		*data = 1;
+#ifdef CONFIG_E1000E_MSIX
+		ret_val = -1;
+		goto out;
+#else
 		return -1;
+#endif
 	}
-	ndev_info(netdev, "testing %s interrupt\n",
-		  (shared_int ? "shared" : "unshared"));
+	e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
 
 	/* Disable all the interrupts */
 	ew32(IMC, 0xFFFFFFFF);
@@ -878,16 +962,26 @@
 
 	/* Test each interrupt */
 	for (i = 0; i < 10; i++) {
-
-		if (((adapter->hw.mac.type == e1000_ich8lan) ||
-		     (adapter->hw.mac.type == e1000_ich9lan)) && i == 8)
-			continue;
-
 		/* Interrupt to test */
 		mask = 1 << i;
 
+		if (adapter->flags & FLAG_IS_ICH) {
+			switch (mask) {
+			case E1000_ICR_RXSEQ:
+				continue;
+			case 0x00000100:
+				if (adapter->hw.mac.type == e1000_ich8lan ||
+				    adapter->hw.mac.type == e1000_ich9lan)
+					continue;
+				break;
+			default:
+				break;
+			}
+		}
+
 		if (!shared_int) {
-			/* Disable the interrupt to be reported in
+			/*
+			 * Disable the interrupt to be reported in
 			 * the cause register and then force the same
 			 * interrupt and see if one gets posted.  If
 			 * an interrupt was posted to the bus, the
@@ -904,7 +998,8 @@
 			}
 		}
 
-		/* Enable the interrupt to be reported in
+		/*
+		 * Enable the interrupt to be reported in
 		 * the cause register and then force the same
 		 * interrupt and see if one gets posted.  If
 		 * an interrupt was not posted to the bus, the
@@ -921,7 +1016,8 @@
 		}
 
 		if (!shared_int) {
-			/* Disable the other interrupts to be reported in
+			/*
+			 * Disable the other interrupts to be reported in
 			 * the cause register and then force the other
 			 * interrupts and see if any get posted.  If
 			 * an interrupt was posted to the bus, the
@@ -946,7 +1042,18 @@
 	/* Unhook test interrupt handler */
 	free_irq(irq, netdev);
 
+#ifdef CONFIG_E1000E_MSIX
+out:
+	if (int_mode == E1000E_INT_MODE_MSIX) {
+		e1000_reset_interrupt_capability(adapter);
+		adapter->int_mode = int_mode;
+		e1000_set_interrupt_capability(adapter);
+	}
+
+	return ret_val;
+#else
 	return *data;
+#endif
 }
 
 static void e1000_free_desc_rings(struct e1000_adapter *adapter)
@@ -1003,7 +1110,6 @@
 	struct pci_dev *pdev = adapter->pdev;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 rctl;
-	int size;
 	int i;
 	int ret_val;
 
@@ -1012,13 +1118,12 @@
 	if (!tx_ring->count)
 		tx_ring->count = E1000_DEFAULT_TXD;
 
-	size = tx_ring->count * sizeof(struct e1000_buffer);
-	tx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
-	if (!tx_ring->buffer_info) {
+	if (!(tx_ring->buffer_info = kcalloc(tx_ring->count,
+	                                     sizeof(struct e1000_buffer),
+	                                     GFP_KERNEL))) {
 		ret_val = 1;
 		goto err_nomem;
 	}
-	memset(tx_ring->buffer_info, 0, size);
 
 	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
 	tx_ring->size = ALIGN(tx_ring->size, 4096);
@@ -1028,21 +1133,17 @@
 		ret_val = 2;
 		goto err_nomem;
 	}
-	memset(tx_ring->desc, 0, tx_ring->size);
 	tx_ring->next_to_use = 0;
 	tx_ring->next_to_clean = 0;
 
-	ew32(TDBAL,
-			((u64) tx_ring->dma & 0x00000000FFFFFFFF));
-	ew32(TDBAH, ((u64) tx_ring->dma >> 32));
-	ew32(TDLEN,
-			tx_ring->count * sizeof(struct e1000_tx_desc));
-	ew32(TDH, 0);
-	ew32(TDT, 0);
-	ew32(TCTL,
-			E1000_TCTL_PSP | E1000_TCTL_EN |
-			E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
-			E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+	ew32(TDBAL(0), ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+	ew32(TDBAH(0), ((u64) tx_ring->dma >> 32));
+	ew32(TDLEN(0), tx_ring->count * sizeof(struct e1000_tx_desc));
+	ew32(TDH(0), 0);
+	ew32(TDT(0), 0);
+	ew32(TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_TCTL_MULR |
+	     E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+	     E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
 
 	for (i = 0; i < tx_ring->count; i++) {
 		struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
@@ -1064,12 +1165,11 @@
 			ret_val = 4;
 			goto err_nomem;
 		}
-		tx_desc->buffer_addr = cpu_to_le64(
-					 tx_ring->buffer_info[i].dma);
+		tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
 		tx_desc->lower.data = cpu_to_le32(skb->len);
 		tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
 						   E1000_TXD_CMD_IFCS |
-						   E1000_TXD_CMD_RPS);
+						   E1000_TXD_CMD_RS);
 		tx_desc->upper.data = 0;
 	}
 
@@ -1078,13 +1178,12 @@
 	if (!rx_ring->count)
 		rx_ring->count = E1000_DEFAULT_RXD;
 
-	size = rx_ring->count * sizeof(struct e1000_buffer);
-	rx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
-	if (!rx_ring->buffer_info) {
+	if (!(rx_ring->buffer_info = kcalloc(rx_ring->count,
+	                                     sizeof(struct e1000_buffer),
+	                                     GFP_KERNEL))) {
 		ret_val = 5;
 		goto err_nomem;
 	}
-	memset(rx_ring->buffer_info, 0, size);
 
 	rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
 	rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
@@ -1093,18 +1192,19 @@
 		ret_val = 6;
 		goto err_nomem;
 	}
-	memset(rx_ring->desc, 0, rx_ring->size);
 	rx_ring->next_to_use = 0;
 	rx_ring->next_to_clean = 0;
 
 	rctl = er32(RCTL);
 	ew32(RCTL, rctl & ~E1000_RCTL_EN);
-	ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
-	ew32(RDBAH, ((u64) rx_ring->dma >> 32));
-	ew32(RDLEN, rx_ring->size);
-	ew32(RDH, 0);
-	ew32(RDT, 0);
+	ew32(RDBAL(0), ((u64) rx_ring->dma & 0xFFFFFFFF));
+	ew32(RDBAH(0), ((u64) rx_ring->dma >> 32));
+	ew32(RDLEN(0), rx_ring->size);
+	ew32(RDH(0), 0);
+	ew32(RDT(0), 0);
 	rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+		E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE |
+		E1000_RCTL_SBP | E1000_RCTL_SECRC |
 		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
 		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
 	ew32(RCTL, rctl);
@@ -1142,10 +1242,10 @@
 static void e1000_phy_disable_receiver(struct e1000_adapter *adapter)
 {
 	/* Write out to PHY registers 29 and 30 to disable the Receiver. */
-	e1e_wphy(&adapter->hw, 29, 0x001F);
-	e1e_wphy(&adapter->hw, 30, 0x8FFC);
-	e1e_wphy(&adapter->hw, 29, 0x001A);
-	e1e_wphy(&adapter->hw, 30, 0x8FF0);
+	adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001F);
+	adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FFC);
+	adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001A);
+	adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FF0);
 }
 
 static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
@@ -1153,24 +1253,26 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ctrl_reg = 0;
 	u32 stat_reg = 0;
+	u16 phy_reg = 0;
 
-	adapter->hw.mac.autoneg = 0;
+	hw->mac.autoneg = 0;
 
-	if (adapter->hw.phy.type == e1000_phy_m88) {
+	if (hw->phy.type == e1000_phy_m88) {
 		/* Auto-MDI/MDIX Off */
-		e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+		hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
 		/* reset to update Auto-MDI/MDIX */
-		e1e_wphy(hw, PHY_CONTROL, 0x9140);
+		hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x9140);
 		/* autoneg off */
-		e1e_wphy(hw, PHY_CONTROL, 0x8140);
-	} else if (adapter->hw.phy.type == e1000_phy_gg82563)
-		e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
+		hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x8140);
+	} else if (hw->phy.type == e1000_phy_gg82563)
+		hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
 
 	ctrl_reg = er32(CTRL);
 
-	if (adapter->hw.phy.type == e1000_phy_ife) {
+	switch (hw->phy.type) {
+	case e1000_phy_ife:
 		/* force 100, set loopback */
-		e1e_wphy(hw, PHY_CONTROL, 0x6100);
+		hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x6100);
 
 		/* Now set up the MAC to the same speed/duplex as the PHY. */
 		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
@@ -1178,9 +1280,33 @@
 			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
 			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */
 			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
-	} else {
+		break;
+	case e1000_phy_bm:
+		/* Set Default MAC Interface speed to 1GB */
+		hw->phy.ops.read_reg(hw, PHY_REG(2, 21), &phy_reg);
+		phy_reg &= ~0x0007;
+		phy_reg |= 0x006;
+		hw->phy.ops.write_reg(hw, PHY_REG(2, 21), phy_reg);
+		/* Assert SW reset for above settings to take effect */
+		hw->phy.ops.commit(hw);
+		mdelay(1);
+		/* Force Full Duplex */
+		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg);
+		hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x000C);
+		/* Set Link Up (in force link) */
+		hw->phy.ops.read_reg(hw, PHY_REG(776, 16), &phy_reg);
+		hw->phy.ops.write_reg(hw, PHY_REG(776, 16), phy_reg | 0x0040);
+		/* Force Link */
+		hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg);
+		hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x0040);
+		/* Set Early Link Enable */
+		hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg);
+		hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | 0x0400);
+		/* fall through */
+	default:
 		/* force 1000, set loopback */
-		e1e_wphy(hw, PHY_CONTROL, 0x4140);
+		hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x4140);
+		mdelay(250);
 
 		/* Now set up the MAC to the same speed/duplex as the PHY. */
 		ctrl_reg = er32(CTRL);
@@ -1189,14 +1315,19 @@
 			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
 			     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
 			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+
+		if (adapter->flags & FLAG_IS_ICH)
+			ctrl_reg |= E1000_CTRL_SLU;	/* Set Link Up */
 	}
 
-	if (adapter->hw.media_type == e1000_media_type_copper &&
-	   adapter->hw.phy.type == e1000_phy_m88) {
+	if (hw->phy.media_type == e1000_media_type_copper &&
+	    hw->phy.type == e1000_phy_m88) {
 		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
 	} else {
-		/* Set the ILOS bit on the fiber Nic if half duplex link is
-		 * detected. */
+		/*
+		 * Set the ILOS bit on the fiber Nic if half duplex link is
+		 * detected.
+		 */
 		stat_reg = er32(STATUS);
 		if ((stat_reg & E1000_STATUS_FD) == 0)
 			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
@@ -1204,10 +1335,11 @@
 
 	ew32(CTRL, ctrl_reg);
 
-	/* Disable the receiver on the PHY so when a cable is plugged in, the
+	/*
+	 * Disable the receiver on the PHY so when a cable is plugged in, the
 	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.
 	 */
-	if (adapter->hw.phy.type == e1000_phy_m88)
+	if (hw->phy.type == e1000_phy_m88)
 		e1000_phy_disable_receiver(adapter);
 
 	udelay(500);
@@ -1223,8 +1355,10 @@
 
 	/* special requirements for 82571/82572 fiber adapters */
 
-	/* jump through hoops to make sure link is up because serdes
-	 * link is hardwired up */
+	/*
+	 * jump through hoops to make sure link is up because serdes
+	 * link is hardwired up
+	 */
 	ctrl |= E1000_CTRL_SLU;
 	ew32(CTRL, ctrl);
 
@@ -1242,8 +1376,10 @@
 		ew32(CTRL, ctrl);
 	}
 
-	/* special write to serdes control register to enable SerDes analog
-	 * loopback */
+	/*
+	 * special write to serdes control register to enable SerDes analog
+	 * loopback
+	 */
 #define E1000_SERDES_LB_ON 0x410
 	ew32(SCTL, E1000_SERDES_LB_ON);
 	msleep(10);
@@ -1258,8 +1394,10 @@
 	u32 ctrlext = er32(CTRL_EXT);
 	u32 ctrl = er32(CTRL);
 
-	/* save CTRL_EXT to restore later, reuse an empty variable (unused
-	   on mac_type 80003es2lan) */
+	/*
+	 * save CTRL_EXT to restore later, reuse an empty variable (unused
+	 * on mac_type 80003es2lan)
+	 */
 	adapter->tx_fifo_head = ctrlext;
 
 	/* clear the serdes mode bits, putting the device into mac loopback */
@@ -1281,7 +1419,7 @@
 #define KMRNCTRLSTA_OPMODE (0x1F << 16)
 #define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582
 	ew32(KMRNCTRLSTA,
-		(KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));
+	     (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));
 
 	return 0;
 }
@@ -1291,8 +1429,8 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 rctl;
 
-	if (hw->media_type == e1000_media_type_fiber ||
-	    hw->media_type == e1000_media_type_internal_serdes) {
+	if (hw->phy.media_type == e1000_media_type_fiber ||
+	    hw->phy.media_type == e1000_media_type_internal_serdes) {
 		switch (hw->mac.type) {
 		case e1000_80003es2lan:
 			return e1000_set_es2lan_mac_loopback(adapter);
@@ -1307,7 +1445,7 @@
 			ew32(RCTL, rctl);
 			return 0;
 		}
-	} else if (hw->media_type == e1000_media_type_copper) {
+	} else if (hw->phy.media_type == e1000_media_type_copper) {
 		return e1000_integrated_phy_loopback(adapter);
 	}
 
@@ -1326,18 +1464,17 @@
 
 	switch (hw->mac.type) {
 	case e1000_80003es2lan:
-		if (hw->media_type == e1000_media_type_fiber ||
-		    hw->media_type == e1000_media_type_internal_serdes) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes) {
 			/* restore CTRL_EXT, stealing space from tx_fifo_head */
-			ew32(CTRL_EXT,
-					adapter->tx_fifo_head);
+			ew32(CTRL_EXT, adapter->tx_fifo_head);
 			adapter->tx_fifo_head = 0;
 		}
 		/* fall through */
 	case e1000_82571:
 	case e1000_82572:
-		if (hw->media_type == e1000_media_type_fiber ||
-		    hw->media_type == e1000_media_type_internal_serdes) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes) {
 #define E1000_SERDES_LB_OFF 0x400
 			ew32(SCTL, E1000_SERDES_LB_OFF);
 			msleep(10);
@@ -1347,12 +1484,15 @@
 	default:
 		hw->mac.autoneg = 1;
 		if (hw->phy.type == e1000_phy_gg82563)
-			e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180);
-		e1e_rphy(hw, PHY_CONTROL, &phy_reg);
+			hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
+			                          0x180);
+		if(hw->phy.ops.read_reg)
+			hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_reg);
 		if (phy_reg & MII_CR_LOOPBACK) {
 			phy_reg &= ~MII_CR_LOOPBACK;
-			e1e_wphy(hw, PHY_CONTROL, phy_reg);
-			e1000e_commit_phy(hw);
+			hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_reg);
+			if (hw->phy.ops.commit)
+				hw->phy.ops.commit(hw);
 		}
 		break;
 	}
@@ -1391,9 +1531,10 @@
 	int ret_val = 0;
 	unsigned long time;
 
-	ew32(RDT, rx_ring->count - 1);
+	ew32(RDT(0), rx_ring->count - 1);
 
-	/* Calculate the loop count based on the largest descriptor ring
+	/*
+	 * Calculate the loop count based on the largest descriptor ring
 	 * The idea is to wrap the largest ring a number of times using 64
 	 * send/receive pairs during each loop
 	 */
@@ -1407,8 +1548,8 @@
 	l = 0;
 	for (j = 0; j <= lc; j++) { /* loop count loop */
 		for (i = 0; i < 64; i++) { /* send the packets */
-			e1000_create_lbtest_frame(
-				tx_ring->buffer_info[i].skb, 1024);
+			e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb,
+			                          1024);
 			pci_dma_sync_single_for_device(pdev,
 					tx_ring->buffer_info[k].dma,
 					tx_ring->buffer_info[k].length,
@@ -1417,7 +1558,7 @@
 			if (k == tx_ring->count)
 				k = 0;
 		}
-		ew32(TDT, k);
+		ew32(TDT(0), k);
 		msleep(200);
 		time = jiffies; /* set the start time for the receive */
 		good_cnt = 0;
@@ -1433,7 +1574,8 @@
 			l++;
 			if (l == rx_ring->count)
 				l = 0;
-			/* time + 20 msecs (200 msecs on 2.4) is more than
+			/*
+			 * time + 20 msecs (200 msecs on 2.4) is more than
 			 * enough time to complete the receives, if it's
 			 * exceeded, break and error off
 			 */
@@ -1442,7 +1584,7 @@
 			ret_val = 13; /* ret_val is the same as mis-compare */
 			break;
 		}
-		if (jiffies >= (time + 2)) {
+		if (jiffies >= (time + 20)) {
 			ret_val = 14; /* error code for time out error */
 			break;
 		}
@@ -1452,11 +1594,14 @@
 
 static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data)
 {
-	/* PHY loopback cannot be performed if SoL/IDER
-	 * sessions are active */
-	if (e1000_check_reset_block(&adapter->hw)) {
-		ndev_err(adapter->netdev, "Cannot do PHY loopback test "
-			 "when SoL/IDER is active.\n");
+	struct e1000_hw *hw = &adapter->hw;
+	/*
+	 * PHY loopback cannot be performed if SoL/IDER
+	 * sessions are active
+	 */
+	if (hw->phy.ops.check_reset_block &&
+	    hw->phy.ops.check_reset_block(&adapter->hw)) {
+		e_err("Cannot do PHY loopback test when SoL/IDER is active.\n");
 		*data = 0;
 		goto out;
 	}
@@ -1483,12 +1628,14 @@
 	struct e1000_hw *hw = &adapter->hw;
 
 	*data = 0;
-	if (hw->media_type == e1000_media_type_internal_serdes) {
+	if (hw->phy.media_type == e1000_media_type_internal_serdes) {
 		int i = 0;
 		hw->mac.serdes_has_link = 0;
 
-		/* On some blade server designs, link establishment
-		 * could take as long as 2-3 minutes */
+		/*
+		 * On some blade server designs, link establishment
+		 * could take as long as 2-3 minutes
+		 */
 		do {
 			hw->mac.ops.check_for_link(hw);
 			if (hw->mac.serdes_has_link)
@@ -1509,16 +1656,14 @@
 	return *data;
 }
 
-static int e1000e_get_sset_count(struct net_device *netdev, int sset)
+static int e1000_get_self_test_count(struct net_device *netdev)
 {
-	switch (sset) {
-	case ETH_SS_TEST:
-		return E1000_TEST_LEN;
-	case ETH_SS_STATS:
-		return E1000_STATS_LEN;
-	default:
-		return -EOPNOTSUPP;
-	}
+	return E1000_TEST_LEN;
+}
+
+static int e1000_get_stats_count(struct net_device *netdev)
+{
+	return E1000_STATS_LEN;
 }
 
 static void e1000_diag_test(struct net_device *netdev,
@@ -1539,10 +1684,12 @@
 		forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
 		autoneg = adapter->hw.mac.autoneg;
 
-		ndev_info(netdev, "offline testing starting\n");
+		e_info("offline testing starting\n");
 
-		/* Link test performed before hardware reset so autoneg doesn't
-		 * interfere with test result */
+		/*
+		 * Link test performed before hardware reset so autoneg doesn't
+		 * interfere with test result
+		 */
 		if (e1000_link_test(adapter, &data[4]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
@@ -1550,22 +1697,22 @@
 			/* indicate we're in test mode */
 			dev_close(netdev);
 		else
-			e1000e_reset(adapter);
+			e1000_reset(adapter);
 
 		if (e1000_reg_test(adapter, &data[0]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
-		e1000e_reset(adapter);
+		e1000_reset(adapter);
 		if (e1000_eeprom_test(adapter, &data[1]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
-		e1000e_reset(adapter);
+		e1000_reset(adapter);
 		if (e1000_intr_test(adapter, &data[2]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
-		e1000e_reset(adapter);
+		e1000_reset(adapter);
 		/* make sure the phy is powered up */
-		e1000e_power_up_phy(adapter);
+		e1000_power_up_phy(&adapter->hw);
 		if (e1000_loopback_test(adapter, &data[3]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
@@ -1575,15 +1722,15 @@
 		adapter->hw.mac.autoneg = autoneg;
 
 		/* force this routine to wait until autoneg complete/timeout */
-		adapter->hw.phy.wait_for_link = 1;
-		e1000e_reset(adapter);
-		adapter->hw.phy.wait_for_link = 0;
+		adapter->hw.phy.autoneg_wait_to_complete = 1;
+		e1000_reset(adapter);
+		adapter->hw.phy.autoneg_wait_to_complete = 0;
 
 		clear_bit(__E1000_TESTING, &adapter->state);
 		if (if_running)
 			dev_open(netdev);
 	} else {
-		ndev_info(netdev, "online testing starting\n");
+		e_info("online testing starting\n");
 		/* Online tests */
 		if (e1000_link_test(adapter, &data[4]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1611,15 +1758,16 @@
 		return;
 
 	wol->supported = WAKE_UCAST | WAKE_MCAST |
-			 WAKE_BCAST | WAKE_MAGIC;
+	                 WAKE_BCAST | WAKE_MAGIC |
+	                 WAKE_PHY | WAKE_ARP;
 
 	/* apply any specific unsupported masks here */
 	if (adapter->flags & FLAG_NO_WAKE_UCAST) {
 		wol->supported &= ~WAKE_UCAST;
 
 		if (adapter->wol & E1000_WUFC_EX)
-			ndev_err(netdev, "Interface does not support "
-				 "directed (unicast) frame wake-up packets\n");
+			e_err("Interface does not support directed (unicast)"
+			      " frame wake-up packets\n");
 	}
 
 	if (adapter->wol & E1000_WUFC_EX)
@@ -1630,6 +1778,10 @@
 		wol->wolopts |= WAKE_BCAST;
 	if (adapter->wol & E1000_WUFC_MAG)
 		wol->wolopts |= WAKE_MAGIC;
+	if (adapter->wol & E1000_WUFC_LNKC)
+		wol->wolopts |= WAKE_PHY;
+	if (adapter->wol & E1000_WUFC_ARP)
+		wol->wolopts |= WAKE_ARP;
 }
 
 static int e1000_set_wol(struct net_device *netdev,
@@ -1637,7 +1789,7 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
-	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+	if (wol->wolopts & WAKE_MAGICSECURE)
 		return -EOPNOTSUPP;
 
 	if (!(adapter->flags & FLAG_HAS_WOL))
@@ -1654,6 +1806,10 @@
 		adapter->wol |= E1000_WUFC_BC;
 	if (wol->wolopts & WAKE_MAGIC)
 		adapter->wol |= E1000_WUFC_MAG;
+	if (wol->wolopts & WAKE_PHY)
+		adapter->wol |= E1000_WUFC_LNKC;
+	if (wol->wolopts & WAKE_ARP)
+		adapter->wol |= E1000_WUFC_ARP;
 
 	return 0;
 }
@@ -1679,11 +1835,13 @@
 static int e1000_phys_id(struct net_device *netdev, u32 data)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 
 	if (!data)
 		data = INT_MAX;
 
-	if (adapter->hw.phy.type == e1000_phy_ife) {
+	if ((hw->phy.type == e1000_phy_ife) ||
+	    (hw->mac.type == e1000_82574)) {
 		if (!adapter->blink_timer.function) {
 			init_timer(&adapter->blink_timer);
 			adapter->blink_timer.function =
@@ -1693,16 +1851,63 @@
 		mod_timer(&adapter->blink_timer, jiffies);
 		msleep_interruptible(data * 1000);
 		del_timer_sync(&adapter->blink_timer);
-		e1e_wphy(&adapter->hw,
-				    IFE_PHY_SPECIAL_CONTROL_LED, 0);
+	if (hw->phy.type == e1000_phy_ife)
+			hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+			                      0);
 	} else {
-		e1000e_blink_led(&adapter->hw);
+		hw->mac.ops.blink_led(hw);
 		msleep_interruptible(data * 1000);
 	}
 
-	adapter->hw.mac.ops.led_off(&adapter->hw);
+	hw->mac.ops.led_off(hw);
 	clear_bit(E1000_LED_ON, &adapter->led_status);
-	adapter->hw.mac.ops.cleanup_led(&adapter->hw);
+	hw->mac.ops.cleanup_led(hw);
+
+	return 0;
+}
+
+static int e1000_get_coalesce(struct net_device *netdev,
+			      struct ethtool_coalesce *ec)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->itr_setting <= 3)
+		ec->rx_coalesce_usecs = adapter->itr_setting;
+	else
+		ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+	ec->stats_block_coalesce_usecs = adapter->stats_freq_us;
+
+	return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+			      struct ethtool_coalesce *ec)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+	    ((ec->rx_coalesce_usecs > 3) &&
+	     (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+	    (ec->rx_coalesce_usecs == 2) ||
+	    (ec->stats_block_coalesce_usecs > (10 * 1000000)))
+		return -EINVAL;
+
+	adapter->stats_freq_us = ec->stats_block_coalesce_usecs;
+
+	if (ec->rx_coalesce_usecs <= 3) {
+		adapter->itr = 20000;
+		adapter->itr_setting = ec->rx_coalesce_usecs;
+	} else {
+		adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+		adapter->itr_setting = adapter->itr & ~3;
+	}
+
+	if (adapter->itr_setting != 0)
+		ew32(ITR, 1000000000 / (adapter->itr * 256));
+	else
+		ew32(ITR, 0);
 
 	return 0;
 }
@@ -1711,7 +1916,7 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	if (netif_running(netdev))
-		e1000e_reinit_locked(adapter);
+		e1000_reinit_locked(adapter);
 	return 0;
 }
 
@@ -1722,7 +1927,7 @@
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int i;
 
-	e1000e_update_stats(adapter);
+	e1000_update_stats(adapter);
 	for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
 		char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
 		data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
@@ -1738,8 +1943,7 @@
 
 	switch (stringset) {
 	case ETH_SS_TEST:
-		memcpy(data, *e1000_gstrings_test,
-			sizeof(e1000_gstrings_test));
+		memcpy(data, *e1000_gstrings_test, sizeof(e1000_gstrings_test));
 		break;
 	case ETH_SS_STATS:
 		for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
@@ -1776,16 +1980,23 @@
 	.set_tx_csum		= e1000_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
+#ifdef NETIF_F_TSO
 	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= e1000_set_tso,
+#endif
 	.self_test		= e1000_diag_test,
 	.get_strings		= e1000_get_strings,
 	.phys_id		= e1000_phys_id,
 	.get_ethtool_stats	= e1000_get_ethtool_stats,
-	.get_sset_count		= e1000e_get_sset_count,
+	.self_test_count	= e1000_get_self_test_count,
+	.get_stats_count	= e1000_get_stats_count,
+	.get_coalesce		= e1000_get_coalesce,
+	.set_coalesce		= e1000_set_coalesce,
 };
 
-void e1000e_set_ethtool_ops(struct net_device *netdev)
+void e1000_set_ethtool_ops(struct net_device *netdev)
 {
-	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
+	/* have to "undeclare" const on this struct to remove warnings */
+	SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&e1000_ethtool_ops);
 }
+#endif /* SIOCETHTOOL */
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/hw.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/hw.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/hw.h	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/hw.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,864 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#ifndef _E1000_HW_H_
-#define _E1000_HW_H_
-
-#include <linux/types.h>
-
-struct e1000_hw;
-struct e1000_adapter;
-
-#include "defines.h"
-
-#define er32(reg)	__er32(hw, E1000_##reg)
-#define ew32(reg,val)	__ew32(hw, E1000_##reg, (val))
-#define e1e_flush()	er32(STATUS)
-
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
-	(writel((value), ((a)->hw_addr + reg + ((offset) << 2))))
-
-#define E1000_READ_REG_ARRAY(a, reg, offset) \
-	(readl((a)->hw_addr + reg + ((offset) << 2)))
-
-enum e1e_registers {
-	E1000_CTRL     = 0x00000, /* Device Control - RW */
-	E1000_STATUS   = 0x00008, /* Device Status - RO */
-	E1000_EECD     = 0x00010, /* EEPROM/Flash Control - RW */
-	E1000_EERD     = 0x00014, /* EEPROM Read - RW */
-	E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */
-	E1000_FLA      = 0x0001C, /* Flash Access - RW */
-	E1000_MDIC     = 0x00020, /* MDI Control - RW */
-	E1000_SCTL     = 0x00024, /* SerDes Control - RW */
-	E1000_FCAL     = 0x00028, /* Flow Control Address Low - RW */
-	E1000_FCAH     = 0x0002C, /* Flow Control Address High -RW */
-	E1000_FEXTNVM  = 0x00028, /* Future Extended NVM - RW */
-	E1000_FCT      = 0x00030, /* Flow Control Type - RW */
-	E1000_VET      = 0x00038, /* VLAN Ether Type - RW */
-	E1000_ICR      = 0x000C0, /* Interrupt Cause Read - R/clr */
-	E1000_ITR      = 0x000C4, /* Interrupt Throttling Rate - RW */
-	E1000_ICS      = 0x000C8, /* Interrupt Cause Set - WO */
-	E1000_IMS      = 0x000D0, /* Interrupt Mask Set - RW */
-	E1000_IMC      = 0x000D8, /* Interrupt Mask Clear - WO */
-	E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
-	E1000_RCTL     = 0x00100, /* RX Control - RW */
-	E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
-	E1000_TXCW     = 0x00178, /* TX Configuration Word - RW */
-	E1000_RXCW     = 0x00180, /* RX Configuration Word - RO */
-	E1000_TCTL     = 0x00400, /* TX Control - RW */
-	E1000_TCTL_EXT = 0x00404, /* Extended TX Control - RW */
-	E1000_TIPG     = 0x00410, /* TX Inter-packet gap -RW */
-	E1000_AIT      = 0x00458, /* Adaptive Interframe Spacing Throttle - RW */
-	E1000_LEDCTL   = 0x00E00, /* LED Control - RW */
-	E1000_EXTCNF_CTRL  = 0x00F00, /* Extended Configuration Control */
-	E1000_EXTCNF_SIZE  = 0x00F08, /* Extended Configuration Size */
-	E1000_PHY_CTRL     = 0x00F10, /* PHY Control Register in CSR */
-	E1000_PBA      = 0x01000, /* Packet Buffer Allocation - RW */
-	E1000_PBS      = 0x01008, /* Packet Buffer Size */
-	E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
-	E1000_EEWR     = 0x0102C, /* EEPROM Write Register - RW */
-	E1000_FLOP     = 0x0103C, /* FLASH Opcode Register */
-	E1000_ERT      = 0x02008, /* Early Rx Threshold - RW */
-	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
-	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
-	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
-	E1000_RDBAL    = 0x02800, /* RX Descriptor Base Address Low - RW */
-	E1000_RDBAH    = 0x02804, /* RX Descriptor Base Address High - RW */
-	E1000_RDLEN    = 0x02808, /* RX Descriptor Length - RW */
-	E1000_RDH      = 0x02810, /* RX Descriptor Head - RW */
-	E1000_RDT      = 0x02818, /* RX Descriptor Tail - RW */
-	E1000_RDTR     = 0x02820, /* RX Delay Timer - RW */
-	E1000_RADV     = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
-
-/* Convenience macros
- *
- * Note: "_n" is the queue number of the register to be written to.
- *
- * Example usage:
- * E1000_RDBAL_REG(current_rx_queue)
- *
- */
-#define E1000_RDBAL_REG(_n)   (E1000_RDBAL + (_n << 8))
-	E1000_KABGTXD  = 0x03004, /* AFE Band Gap Transmit Ref Data */
-	E1000_TDBAL    = 0x03800, /* TX Descriptor Base Address Low - RW */
-	E1000_TDBAH    = 0x03804, /* TX Descriptor Base Address High - RW */
-	E1000_TDLEN    = 0x03808, /* TX Descriptor Length - RW */
-	E1000_TDH      = 0x03810, /* TX Descriptor Head - RW */
-	E1000_TDT      = 0x03818, /* TX Descriptor Tail - RW */
-	E1000_TIDV     = 0x03820, /* TX Interrupt Delay Value - RW */
-	E1000_TXDCTL   = 0x03828, /* TX Descriptor Control - RW */
-	E1000_TADV     = 0x0382C, /* TX Interrupt Absolute Delay Val - RW */
-	E1000_TARC0    = 0x03840, /* TX Arbitration Count (0) */
-	E1000_TXDCTL1  = 0x03928, /* TX Descriptor Control (1) - RW */
-	E1000_TARC1    = 0x03940, /* TX Arbitration Count (1) */
-	E1000_CRCERRS  = 0x04000, /* CRC Error Count - R/clr */
-	E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */
-	E1000_SYMERRS  = 0x04008, /* Symbol Error Count - R/clr */
-	E1000_RXERRC   = 0x0400C, /* Receive Error Count - R/clr */
-	E1000_MPC      = 0x04010, /* Missed Packet Count - R/clr */
-	E1000_SCC      = 0x04014, /* Single Collision Count - R/clr */
-	E1000_ECOL     = 0x04018, /* Excessive Collision Count - R/clr */
-	E1000_MCC      = 0x0401C, /* Multiple Collision Count - R/clr */
-	E1000_LATECOL  = 0x04020, /* Late Collision Count - R/clr */
-	E1000_COLC     = 0x04028, /* Collision Count - R/clr */
-	E1000_DC       = 0x04030, /* Defer Count - R/clr */
-	E1000_TNCRS    = 0x04034, /* TX-No CRS - R/clr */
-	E1000_SEC      = 0x04038, /* Sequence Error Count - R/clr */
-	E1000_CEXTERR  = 0x0403C, /* Carrier Extension Error Count - R/clr */
-	E1000_RLEC     = 0x04040, /* Receive Length Error Count - R/clr */
-	E1000_XONRXC   = 0x04048, /* XON RX Count - R/clr */
-	E1000_XONTXC   = 0x0404C, /* XON TX Count - R/clr */
-	E1000_XOFFRXC  = 0x04050, /* XOFF RX Count - R/clr */
-	E1000_XOFFTXC  = 0x04054, /* XOFF TX Count - R/clr */
-	E1000_FCRUC    = 0x04058, /* Flow Control RX Unsupported Count- R/clr */
-	E1000_PRC64    = 0x0405C, /* Packets RX (64 bytes) - R/clr */
-	E1000_PRC127   = 0x04060, /* Packets RX (65-127 bytes) - R/clr */
-	E1000_PRC255   = 0x04064, /* Packets RX (128-255 bytes) - R/clr */
-	E1000_PRC511   = 0x04068, /* Packets RX (255-511 bytes) - R/clr */
-	E1000_PRC1023  = 0x0406C, /* Packets RX (512-1023 bytes) - R/clr */
-	E1000_PRC1522  = 0x04070, /* Packets RX (1024-1522 bytes) - R/clr */
-	E1000_GPRC     = 0x04074, /* Good Packets RX Count - R/clr */
-	E1000_BPRC     = 0x04078, /* Broadcast Packets RX Count - R/clr */
-	E1000_MPRC     = 0x0407C, /* Multicast Packets RX Count - R/clr */
-	E1000_GPTC     = 0x04080, /* Good Packets TX Count - R/clr */
-	E1000_GORCL    = 0x04088, /* Good Octets RX Count Low - R/clr */
-	E1000_GORCH    = 0x0408C, /* Good Octets RX Count High - R/clr */
-	E1000_GOTCL    = 0x04090, /* Good Octets TX Count Low - R/clr */
-	E1000_GOTCH    = 0x04094, /* Good Octets TX Count High - R/clr */
-	E1000_RNBC     = 0x040A0, /* RX No Buffers Count - R/clr */
-	E1000_RUC      = 0x040A4, /* RX Undersize Count - R/clr */
-	E1000_RFC      = 0x040A8, /* RX Fragment Count - R/clr */
-	E1000_ROC      = 0x040AC, /* RX Oversize Count - R/clr */
-	E1000_RJC      = 0x040B0, /* RX Jabber Count - R/clr */
-	E1000_MGTPRC   = 0x040B4, /* Management Packets RX Count - R/clr */
-	E1000_MGTPDC   = 0x040B8, /* Management Packets Dropped Count - R/clr */
-	E1000_MGTPTC   = 0x040BC, /* Management Packets TX Count - R/clr */
-	E1000_TORL     = 0x040C0, /* Total Octets RX Low - R/clr */
-	E1000_TORH     = 0x040C4, /* Total Octets RX High - R/clr */
-	E1000_TOTL     = 0x040C8, /* Total Octets TX Low - R/clr */
-	E1000_TOTH     = 0x040CC, /* Total Octets TX High - R/clr */
-	E1000_TPR      = 0x040D0, /* Total Packets RX - R/clr */
-	E1000_TPT      = 0x040D4, /* Total Packets TX - R/clr */
-	E1000_PTC64    = 0x040D8, /* Packets TX (64 bytes) - R/clr */
-	E1000_PTC127   = 0x040DC, /* Packets TX (65-127 bytes) - R/clr */
-	E1000_PTC255   = 0x040E0, /* Packets TX (128-255 bytes) - R/clr */
-	E1000_PTC511   = 0x040E4, /* Packets TX (256-511 bytes) - R/clr */
-	E1000_PTC1023  = 0x040E8, /* Packets TX (512-1023 bytes) - R/clr */
-	E1000_PTC1522  = 0x040EC, /* Packets TX (1024-1522 Bytes) - R/clr */
-	E1000_MPTC     = 0x040F0, /* Multicast Packets TX Count - R/clr */
-	E1000_BPTC     = 0x040F4, /* Broadcast Packets TX Count - R/clr */
-	E1000_TSCTC    = 0x040F8, /* TCP Segmentation Context TX - R/clr */
-	E1000_TSCTFC   = 0x040FC, /* TCP Segmentation Context TX Fail - R/clr */
-	E1000_IAC      = 0x04100, /* Interrupt Assertion Count */
-	E1000_ICRXPTC  = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */
-	E1000_ICRXATC  = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */
-	E1000_ICTXPTC  = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */
-	E1000_ICTXATC  = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */
-	E1000_ICTXQEC  = 0x04118, /* Irq Cause Tx Queue Empty Count */
-	E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
-	E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
-	E1000_ICRXOC   = 0x04124, /* Irq Cause Receiver Overrun Count */
-	E1000_RXCSUM   = 0x05000, /* RX Checksum Control - RW */
-	E1000_RFCTL    = 0x05008, /* Receive Filter Control*/
-	E1000_MTA      = 0x05200, /* Multicast Table Array - RW Array */
-	E1000_RA       = 0x05400, /* Receive Address - RW Array */
-	E1000_VFTA     = 0x05600, /* VLAN Filter Table Array - RW Array */
-	E1000_WUC      = 0x05800, /* Wakeup Control - RW */
-	E1000_WUFC     = 0x05808, /* Wakeup Filter Control - RW */
-	E1000_WUS      = 0x05810, /* Wakeup Status - RO */
-	E1000_MANC     = 0x05820, /* Management Control - RW */
-	E1000_FFLT     = 0x05F00, /* Flexible Filter Length Table - RW Array */
-	E1000_HOST_IF  = 0x08800, /* Host Interface */
-
-	E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
-	E1000_MANC2H    = 0x05860, /* Management Control To Host - RW */
-	E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
-	E1000_GCR	= 0x05B00, /* PCI-Ex Control */
-	E1000_FACTPS    = 0x05B30, /* Function Active and Power State to MNG */
-	E1000_SWSM      = 0x05B50, /* SW Semaphore */
-	E1000_FWSM      = 0x05B54, /* FW Semaphore */
-	E1000_HICR      = 0x08F00, /* Host Inteface Control */
-};
-
-/* RSS registers */
-
-/* IGP01E1000 Specific Registers */
-#define IGP01E1000_PHY_PORT_CONFIG	0x10 /* Port Config */
-#define IGP01E1000_PHY_PORT_STATUS	0x11 /* Status */
-#define IGP01E1000_PHY_PORT_CTRL	0x12 /* Control */
-#define IGP01E1000_PHY_LINK_HEALTH	0x13 /* PHY Link Health */
-#define IGP02E1000_PHY_POWER_MGMT	0x19 /* Power Management */
-#define IGP01E1000_PHY_PAGE_SELECT	0x1F /* Page Select */
-
-#define IGP01E1000_PHY_PCS_INIT_REG	0x00B4
-#define IGP01E1000_PHY_POLARITY_MASK	0x0078
-
-#define IGP01E1000_PSCR_AUTO_MDIX	0x1000
-#define IGP01E1000_PSCR_FORCE_MDI_MDIX	0x2000 /* 0=MDI, 1=MDIX */
-
-#define IGP01E1000_PSCFR_SMART_SPEED	0x0080
-
-#define IGP02E1000_PM_SPD		0x0001 /* Smart Power Down */
-#define IGP02E1000_PM_D0_LPLU		0x0002 /* For D0a states */
-#define IGP02E1000_PM_D3_LPLU		0x0004 /* For all other states */
-
-#define IGP01E1000_PLHR_SS_DOWNGRADE	0x8000
-
-#define IGP01E1000_PSSR_POLARITY_REVERSED	0x0002
-#define IGP01E1000_PSSR_MDIX			0x0008
-#define IGP01E1000_PSSR_SPEED_MASK		0xC000
-#define IGP01E1000_PSSR_SPEED_1000MBPS		0xC000
-
-#define IGP02E1000_PHY_CHANNEL_NUM		4
-#define IGP02E1000_PHY_AGC_A			0x11B1
-#define IGP02E1000_PHY_AGC_B			0x12B1
-#define IGP02E1000_PHY_AGC_C			0x14B1
-#define IGP02E1000_PHY_AGC_D			0x18B1
-
-#define IGP02E1000_AGC_LENGTH_SHIFT	9 /* Course - 15:13, Fine - 12:9 */
-#define IGP02E1000_AGC_LENGTH_MASK	0x7F
-#define IGP02E1000_AGC_RANGE		15
-
-/* manage.c */
-#define E1000_VFTA_ENTRY_SHIFT		5
-#define E1000_VFTA_ENTRY_MASK		0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK	0x1F
-
-#define E1000_HICR_EN			0x01  /* Enable bit - RO */
-#define E1000_HICR_C			0x02  /* Driver sets this bit when done
-					       * to put command in RAM */
-#define E1000_HICR_FW_RESET_ENABLE	0x40
-#define E1000_HICR_FW_RESET		0x80
-
-#define E1000_FWSM_MODE_MASK		0xE
-#define E1000_FWSM_MODE_SHIFT		1
-
-#define E1000_MNG_IAMT_MODE		0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH	0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET	0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT	10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD	64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING	0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN	0x2
-
-/* nvm.c */
-#define E1000_STM_OPCODE  0xDB00
-
-#define E1000_KMRNCTRLSTA_OFFSET	0x001F0000
-#define E1000_KMRNCTRLSTA_OFFSET_SHIFT	16
-#define E1000_KMRNCTRLSTA_REN		0x00200000
-#define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3    /* Kumeran Diagnostic */
-#define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000 /* Nearend Loopback mode */
-
-#define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
-#define IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED	0x1B /* PHY Special and LED Control */
-#define IFE_PHY_MDIX_CONTROL		0x1C /* MDI/MDI-X Control */
-
-/* IFE PHY Extended Status Control */
-#define IFE_PESC_POLARITY_REVERSED	0x0100
-
-/* IFE PHY Special Control */
-#define IFE_PSC_AUTO_POLARITY_DISABLE		0x0010
-#define IFE_PSC_FORCE_POLARITY			0x0020
-
-/* IFE PHY Special Control and LED Control */
-#define IFE_PSCL_PROBE_MODE		0x0020
-#define IFE_PSCL_PROBE_LEDS_OFF		0x0006 /* Force LEDs 0 and 2 off */
-#define IFE_PSCL_PROBE_LEDS_ON		0x0007 /* Force LEDs 0 and 2 on */
-
-/* IFE PHY MDIX Control */
-#define IFE_PMC_MDIX_STATUS	0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_FORCE_MDIX	0x0040 /* 1=force MDI-X, 0=force MDI */
-#define IFE_PMC_AUTO_MDIX	0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
-
-#define E1000_CABLE_LENGTH_UNDEFINED	0xFF
-
-#define E1000_DEV_ID_82571EB_COPPER		0x105E
-#define E1000_DEV_ID_82571EB_FIBER		0x105F
-#define E1000_DEV_ID_82571EB_SERDES		0x1060
-#define E1000_DEV_ID_82571EB_QUAD_COPPER	0x10A4
-#define E1000_DEV_ID_82571EB_QUAD_FIBER		0x10A5
-#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP	0x10BC
-#define E1000_DEV_ID_82572EI_COPPER		0x107D
-#define E1000_DEV_ID_82572EI_FIBER		0x107E
-#define E1000_DEV_ID_82572EI_SERDES		0x107F
-#define E1000_DEV_ID_82572EI			0x10B9
-#define E1000_DEV_ID_82573E			0x108B
-#define E1000_DEV_ID_82573E_IAMT		0x108C
-#define E1000_DEV_ID_82573L			0x109A
-
-#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT	0x1096
-#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT	0x1098
-#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT	0x10BA
-#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT	0x10BB
-
-#define E1000_DEV_ID_ICH8_IGP_M_AMT		0x1049
-#define E1000_DEV_ID_ICH8_IGP_AMT		0x104A
-#define E1000_DEV_ID_ICH8_IGP_C			0x104B
-#define E1000_DEV_ID_ICH8_IFE			0x104C
-#define E1000_DEV_ID_ICH8_IFE_GT		0x10C4
-#define E1000_DEV_ID_ICH8_IFE_G			0x10C5
-#define E1000_DEV_ID_ICH8_IGP_M			0x104D
-#define E1000_DEV_ID_ICH9_IGP_AMT		0x10BD
-#define E1000_DEV_ID_ICH9_IGP_C			0x294C
-#define E1000_DEV_ID_ICH9_IFE			0x10C0
-#define E1000_DEV_ID_ICH9_IFE_GT		0x10C3
-#define E1000_DEV_ID_ICH9_IFE_G			0x10C2
-
-#define E1000_FUNC_1 1
-
-enum e1000_mac_type {
-	e1000_82571,
-	e1000_82572,
-	e1000_82573,
-	e1000_80003es2lan,
-	e1000_ich8lan,
-	e1000_ich9lan,
-};
-
-enum e1000_media_type {
-	e1000_media_type_unknown = 0,
-	e1000_media_type_copper = 1,
-	e1000_media_type_fiber = 2,
-	e1000_media_type_internal_serdes = 3,
-	e1000_num_media_types
-};
-
-enum e1000_nvm_type {
-	e1000_nvm_unknown = 0,
-	e1000_nvm_none,
-	e1000_nvm_eeprom_spi,
-	e1000_nvm_flash_hw,
-	e1000_nvm_flash_sw
-};
-
-enum e1000_nvm_override {
-	e1000_nvm_override_none = 0,
-	e1000_nvm_override_spi_small,
-	e1000_nvm_override_spi_large
-};
-
-enum e1000_phy_type {
-	e1000_phy_unknown = 0,
-	e1000_phy_none,
-	e1000_phy_m88,
-	e1000_phy_igp,
-	e1000_phy_igp_2,
-	e1000_phy_gg82563,
-	e1000_phy_igp_3,
-	e1000_phy_ife,
-};
-
-enum e1000_bus_width {
-	e1000_bus_width_unknown = 0,
-	e1000_bus_width_pcie_x1,
-	e1000_bus_width_pcie_x2,
-	e1000_bus_width_pcie_x4 = 4,
-	e1000_bus_width_32,
-	e1000_bus_width_64,
-	e1000_bus_width_reserved
-};
-
-enum e1000_1000t_rx_status {
-	e1000_1000t_rx_status_not_ok = 0,
-	e1000_1000t_rx_status_ok,
-	e1000_1000t_rx_status_undefined = 0xFF
-};
-
-enum e1000_rev_polarity{
-	e1000_rev_polarity_normal = 0,
-	e1000_rev_polarity_reversed,
-	e1000_rev_polarity_undefined = 0xFF
-};
-
-enum e1000_fc_mode {
-	e1000_fc_none = 0,
-	e1000_fc_rx_pause,
-	e1000_fc_tx_pause,
-	e1000_fc_full,
-	e1000_fc_default = 0xFF
-};
-
-enum e1000_ms_type {
-	e1000_ms_hw_default = 0,
-	e1000_ms_force_master,
-	e1000_ms_force_slave,
-	e1000_ms_auto
-};
-
-enum e1000_smart_speed {
-	e1000_smart_speed_default = 0,
-	e1000_smart_speed_on,
-	e1000_smart_speed_off
-};
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
-	u64 buffer_addr; /* Address of the descriptor's data buffer */
-	u16 length;      /* Length of data DMAed into data buffer */
-	u16 csum;	/* Packet checksum */
-	u8  status;      /* Descriptor status */
-	u8  errors;      /* Descriptor Errors */
-	u16 special;
-};
-
-/* Receive Descriptor - Extended */
-union e1000_rx_desc_extended {
-	struct {
-		u64 buffer_addr;
-		u64 reserved;
-	} read;
-	struct {
-		struct {
-			u32 mrq;	      /* Multiple Rx Queues */
-			union {
-				u32 rss;	    /* RSS Hash */
-				struct {
-					u16 ip_id;  /* IP id */
-					u16 csum;   /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			u32 status_error;     /* ext status/error */
-			u16 length;
-			u16 vlan;	     /* VLAN tag */
-		} upper;
-	} wb;  /* writeback */
-};
-
-#define MAX_PS_BUFFERS 4
-/* Receive Descriptor - Packet Split */
-union e1000_rx_desc_packet_split {
-	struct {
-		/* one buffer for protocol header(s), three data buffers */
-		u64 buffer_addr[MAX_PS_BUFFERS];
-	} read;
-	struct {
-		struct {
-			u32 mrq;	      /* Multiple Rx Queues */
-			union {
-				u32 rss;	      /* RSS Hash */
-				struct {
-					u16 ip_id;    /* IP id */
-					u16 csum;     /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			u32 status_error;     /* ext status/error */
-			u16 length0;	  /* length of buffer 0 */
-			u16 vlan;	     /* VLAN tag */
-		} middle;
-		struct {
-			u16 header_status;
-			u16 length[3];	/* length of buffers 1-3 */
-		} upper;
-		u64 reserved;
-	} wb; /* writeback */
-};
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
-	u64 buffer_addr;      /* Address of the descriptor's data buffer */
-	union {
-		u32 data;
-		struct {
-			u16 length;    /* Data buffer length */
-			u8 cso;	/* Checksum offset */
-			u8 cmd;	/* Descriptor control */
-		} flags;
-	} lower;
-	union {
-		u32 data;
-		struct {
-			u8 status;     /* Descriptor status */
-			u8 css;	/* Checksum start */
-			u16 special;
-		} fields;
-	} upper;
-};
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-	union {
-		u32 ip_config;
-		struct {
-			u8 ipcss;      /* IP checksum start */
-			u8 ipcso;      /* IP checksum offset */
-			u16 ipcse;     /* IP checksum end */
-		} ip_fields;
-	} lower_setup;
-	union {
-		u32 tcp_config;
-		struct {
-			u8 tucss;      /* TCP checksum start */
-			u8 tucso;      /* TCP checksum offset */
-			u16 tucse;     /* TCP checksum end */
-		} tcp_fields;
-	} upper_setup;
-	u32 cmd_and_length;
-	union {
-		u32 data;
-		struct {
-			u8 status;     /* Descriptor status */
-			u8 hdr_len;    /* Header length */
-			u16 mss;       /* Maximum segment size */
-		} fields;
-	} tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-	u64 buffer_addr;   /* Address of the descriptor's buffer address */
-	union {
-		u32 data;
-		struct {
-			u16 length;    /* Data buffer length */
-			u8 typ_len_ext;
-			u8 cmd;
-		} flags;
-	} lower;
-	union {
-		u32 data;
-		struct {
-			u8 status;     /* Descriptor status */
-			u8 popts;      /* Packet Options */
-			u16 special;   /* */
-		} fields;
-	} upper;
-};
-
-/* Statistics counters collected by the MAC */
-struct e1000_hw_stats {
-	u64 crcerrs;
-	u64 algnerrc;
-	u64 symerrs;
-	u64 rxerrc;
-	u64 mpc;
-	u64 scc;
-	u64 ecol;
-	u64 mcc;
-	u64 latecol;
-	u64 colc;
-	u64 dc;
-	u64 tncrs;
-	u64 sec;
-	u64 cexterr;
-	u64 rlec;
-	u64 xonrxc;
-	u64 xontxc;
-	u64 xoffrxc;
-	u64 xofftxc;
-	u64 fcruc;
-	u64 prc64;
-	u64 prc127;
-	u64 prc255;
-	u64 prc511;
-	u64 prc1023;
-	u64 prc1522;
-	u64 gprc;
-	u64 bprc;
-	u64 mprc;
-	u64 gptc;
-	u64 gorcl;
-	u64 gorch;
-	u64 gotcl;
-	u64 gotch;
-	u64 rnbc;
-	u64 ruc;
-	u64 rfc;
-	u64 roc;
-	u64 rjc;
-	u64 mgprc;
-	u64 mgpdc;
-	u64 mgptc;
-	u64 torl;
-	u64 torh;
-	u64 totl;
-	u64 toth;
-	u64 tpr;
-	u64 tpt;
-	u64 ptc64;
-	u64 ptc127;
-	u64 ptc255;
-	u64 ptc511;
-	u64 ptc1023;
-	u64 ptc1522;
-	u64 mptc;
-	u64 bptc;
-	u64 tsctc;
-	u64 tsctfc;
-	u64 iac;
-	u64 icrxptc;
-	u64 icrxatc;
-	u64 ictxptc;
-	u64 ictxatc;
-	u64 ictxqec;
-	u64 ictxqmtc;
-	u64 icrxdmtc;
-	u64 icrxoc;
-};
-
-struct e1000_phy_stats {
-	u32 idle_errors;
-	u32 receive_errors;
-};
-
-struct e1000_host_mng_dhcp_cookie {
-	u32 signature;
-	u8  status;
-	u8  reserved0;
-	u16 vlan_id;
-	u32 reserved1;
-	u16 reserved2;
-	u8  reserved3;
-	u8  checksum;
-};
-
-/* Host Interface "Rev 1" */
-struct e1000_host_command_header {
-	u8 command_id;
-	u8 command_length;
-	u8 command_options;
-	u8 checksum;
-};
-
-#define E1000_HI_MAX_DATA_LENGTH     252
-struct e1000_host_command_info {
-	struct e1000_host_command_header command_header;
-	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
-};
-
-/* Host Interface "Rev 2" */
-struct e1000_host_mng_command_header {
-	u8  command_id;
-	u8  checksum;
-	u16 reserved1;
-	u16 reserved2;
-	u16 command_length;
-};
-
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
-struct e1000_host_mng_command_info {
-	struct e1000_host_mng_command_header command_header;
-	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
-};
-
-/* Function pointers and static data for the MAC. */
-struct e1000_mac_operations {
-	u32			mng_mode_enab;
-
-	s32  (*check_for_link)(struct e1000_hw *);
-	s32  (*cleanup_led)(struct e1000_hw *);
-	void (*clear_hw_cntrs)(struct e1000_hw *);
-	s32  (*get_bus_info)(struct e1000_hw *);
-	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
-	s32  (*led_on)(struct e1000_hw *);
-	s32  (*led_off)(struct e1000_hw *);
-	void (*mc_addr_list_update)(struct e1000_hw *, u8 *, u32, u32,
-					 u32);
-	s32  (*reset_hw)(struct e1000_hw *);
-	s32  (*init_hw)(struct e1000_hw *);
-	s32  (*setup_link)(struct e1000_hw *);
-	s32  (*setup_physical_interface)(struct e1000_hw *);
-};
-
-/* Function pointers for the PHY. */
-struct e1000_phy_operations {
-	s32  (*acquire_phy)(struct e1000_hw *);
-	s32  (*check_reset_block)(struct e1000_hw *);
-	s32  (*commit_phy)(struct e1000_hw *);
-	s32  (*force_speed_duplex)(struct e1000_hw *);
-	s32  (*get_cfg_done)(struct e1000_hw *hw);
-	s32  (*get_cable_length)(struct e1000_hw *);
-	s32  (*get_phy_info)(struct e1000_hw *);
-	s32  (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
-	void (*release_phy)(struct e1000_hw *);
-	s32  (*reset_phy)(struct e1000_hw *);
-	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
-	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
-	s32  (*write_phy_reg)(struct e1000_hw *, u32, u16);
-};
-
-/* Function pointers for the NVM. */
-struct e1000_nvm_operations {
-	s32  (*acquire_nvm)(struct e1000_hw *);
-	s32  (*read_nvm)(struct e1000_hw *, u16, u16, u16 *);
-	void (*release_nvm)(struct e1000_hw *);
-	s32  (*update_nvm)(struct e1000_hw *);
-	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
-	s32  (*validate_nvm)(struct e1000_hw *);
-	s32  (*write_nvm)(struct e1000_hw *, u16, u16, u16 *);
-};
-
-struct e1000_mac_info {
-	struct e1000_mac_operations ops;
-
-	u8 addr[6];
-	u8 perm_addr[6];
-
-	enum e1000_mac_type type;
-	enum e1000_fc_mode  fc;
-	enum e1000_fc_mode  original_fc;
-
-	u32 collision_delta;
-	u32 ledctl_default;
-	u32 ledctl_mode1;
-	u32 ledctl_mode2;
-	u32 max_frame_size;
-	u32 mc_filter_type;
-	u32 min_frame_size;
-	u32 tx_packet_delta;
-	u32 txcw;
-
-	u16 current_ifs_val;
-	u16 ifs_max_val;
-	u16 ifs_min_val;
-	u16 ifs_ratio;
-	u16 ifs_step_size;
-	u16 mta_reg_count;
-	u16 rar_entry_count;
-	u16 fc_high_water;
-	u16 fc_low_water;
-	u16 fc_pause_time;
-
-	u8  forced_speed_duplex;
-
-	bool arc_subsystem_valid;
-	bool autoneg;
-	bool autoneg_failed;
-	bool get_link_status;
-	bool in_ifs_mode;
-	bool serdes_has_link;
-	bool tx_pkt_filtering;
-};
-
-struct e1000_phy_info {
-	struct e1000_phy_operations ops;
-
-	enum e1000_phy_type type;
-
-	enum e1000_1000t_rx_status local_rx;
-	enum e1000_1000t_rx_status remote_rx;
-	enum e1000_ms_type ms_type;
-	enum e1000_ms_type original_ms_type;
-	enum e1000_rev_polarity cable_polarity;
-	enum e1000_smart_speed smart_speed;
-
-	u32 addr;
-	u32 id;
-	u32 reset_delay_us; /* in usec */
-	u32 revision;
-
-	u16 autoneg_advertised;
-	u16 autoneg_mask;
-	u16 cable_length;
-	u16 max_cable_length;
-	u16 min_cable_length;
-
-	u8 mdix;
-
-	bool disable_polarity_correction;
-	bool is_mdix;
-	bool polarity_correction;
-	bool speed_downgraded;
-	bool wait_for_link;
-};
-
-struct e1000_nvm_info {
-	struct e1000_nvm_operations ops;
-
-	enum e1000_nvm_type type;
-	enum e1000_nvm_override override;
-
-	u32 flash_bank_size;
-	u32 flash_base_addr;
-
-	u16 word_size;
-	u16 delay_usec;
-	u16 address_bits;
-	u16 opcode_bits;
-	u16 page_size;
-};
-
-struct e1000_bus_info {
-	enum e1000_bus_width width;
-
-	u16 func;
-};
-
-struct e1000_dev_spec_82571 {
-	bool laa_is_present;
-};
-
-struct e1000_shadow_ram {
-	u16  value;
-	bool modified;
-};
-
-#define E1000_ICH8_SHADOW_RAM_WORDS		2048
-
-struct e1000_dev_spec_ich8lan {
-	bool kmrn_lock_loss_workaround_enabled;
-	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
-};
-
-struct e1000_hw {
-	struct e1000_adapter *adapter;
-
-	u8 __iomem *hw_addr;
-	u8 __iomem *flash_address;
-
-	struct e1000_mac_info  mac;
-	struct e1000_phy_info  phy;
-	struct e1000_nvm_info  nvm;
-	struct e1000_bus_info  bus;
-	struct e1000_host_mng_dhcp_cookie mng_cookie;
-
-	union {
-		struct e1000_dev_spec_82571	e82571;
-		struct e1000_dev_spec_ich8lan	ich8lan;
-	} dev_spec;
-
-	enum e1000_media_type media_type;
-};
-
-#ifdef DEBUG
-#define hw_dbg(hw, format, arg...) \
-	printk(KERN_DEBUG "%s: " format, e1000e_get_hw_dev_name(hw), ##arg)
-#else
-static inline int __attribute__ ((format (printf, 2, 3)))
-hw_dbg(struct e1000_hw *hw, const char *format, ...)
-{
-	return 0;
-}
-#endif
-
-#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/ich8lan.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/ich8lan.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/ich8lan.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/ich8lan.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,2225 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/*
- * 82562G-2 10/100 Network Connection
- * 82562GT 10/100 Network Connection
- * 82562GT-2 10/100 Network Connection
- * 82562V 10/100 Network Connection
- * 82562V-2 10/100 Network Connection
- * 82566DC-2 Gigabit Network Connection
- * 82566DC Gigabit Network Connection
- * 82566DM-2 Gigabit Network Connection
- * 82566DM Gigabit Network Connection
- * 82566MC Gigabit Network Connection
- * 82566MM Gigabit Network Connection
- */
-
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "e1000.h"
-
-#define ICH_FLASH_GFPREG		0x0000
-#define ICH_FLASH_HSFSTS		0x0004
-#define ICH_FLASH_HSFCTL		0x0006
-#define ICH_FLASH_FADDR			0x0008
-#define ICH_FLASH_FDATA0		0x0010
-
-#define ICH_FLASH_READ_COMMAND_TIMEOUT	500
-#define ICH_FLASH_WRITE_COMMAND_TIMEOUT	500
-#define ICH_FLASH_ERASE_COMMAND_TIMEOUT	3000000
-#define ICH_FLASH_LINEAR_ADDR_MASK	0x00FFFFFF
-#define ICH_FLASH_CYCLE_REPEAT_COUNT	10
-
-#define ICH_CYCLE_READ			0
-#define ICH_CYCLE_WRITE			2
-#define ICH_CYCLE_ERASE			3
-
-#define FLASH_GFPREG_BASE_MASK		0x1FFF
-#define FLASH_SECTOR_ADDR_SHIFT		12
-
-#define ICH_FLASH_SEG_SIZE_256		256
-#define ICH_FLASH_SEG_SIZE_4K		4096
-#define ICH_FLASH_SEG_SIZE_8K		8192
-#define ICH_FLASH_SEG_SIZE_64K		65536
-
-
-#define E1000_ICH_FWSM_RSPCIPHY	0x00000040 /* Reset PHY on PCI Reset */
-
-#define E1000_ICH_MNG_IAMT_MODE		0x2
-
-#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
-				 (ID_LED_DEF1_OFF2 <<  8) | \
-				 (ID_LED_DEF1_ON2  <<  4) | \
-				 (ID_LED_DEF1_DEF2))
-
-#define E1000_ICH_NVM_SIG_WORD		0x13
-#define E1000_ICH_NVM_SIG_MASK		0xC000
-
-#define E1000_ICH8_LAN_INIT_TIMEOUT	1500
-
-#define E1000_FEXTNVM_SW_CONFIG		1
-#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
-
-#define PCIE_ICH8_SNOOP_ALL		PCIE_NO_SNOOP_ALL
-
-#define E1000_ICH_RAR_ENTRIES		7
-
-#define PHY_PAGE_SHIFT 5
-#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
-			   ((reg) & MAX_PHY_REG_ADDRESS))
-#define IGP3_KMRN_DIAG  PHY_REG(770, 19) /* KMRN Diagnostic */
-#define IGP3_VR_CTRL    PHY_REG(776, 18) /* Voltage Regulator Control */
-
-#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS	0x0002
-#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
-#define IGP3_VR_CTRL_MODE_SHUTDOWN	0x0200
-
-/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
-/* Offset 04h HSFSTS */
-union ich8_hws_flash_status {
-	struct ich8_hsfsts {
-		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
-		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
-		u16 dael       :1; /* bit 2 Direct Access error Log */
-		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
-		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
-		u16 reserved1  :2; /* bit 13:6 Reserved */
-		u16 reserved2  :6; /* bit 13:6 Reserved */
-		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
-		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
-	} hsf_status;
-	u16 regval;
-};
-
-/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
-/* Offset 06h FLCTL */
-union ich8_hws_flash_ctrl {
-	struct ich8_hsflctl {
-		u16 flcgo      :1;   /* 0 Flash Cycle Go */
-		u16 flcycle    :2;   /* 2:1 Flash Cycle */
-		u16 reserved   :5;   /* 7:3 Reserved  */
-		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
-		u16 flockdn    :6;   /* 15:10 Reserved */
-	} hsf_ctrl;
-	u16 regval;
-};
-
-/* ICH Flash Region Access Permissions */
-union ich8_hws_flash_regacc {
-	struct ich8_flracc {
-		u32 grra      :8; /* 0:7 GbE region Read Access */
-		u32 grwa      :8; /* 8:15 GbE region Write Access */
-		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
-		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
-	} hsf_flregacc;
-	u16 regval;
-};
-
-static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
-static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
-static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
-static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
-static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
-static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
-						u32 offset, u8 byte);
-static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
-					 u16 *data);
-static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-					 u8 size, u16 *data);
-static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
-static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
-
-static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
-{
-	return readw(hw->flash_address + reg);
-}
-
-static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg)
-{
-	return readl(hw->flash_address + reg);
-}
-
-static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val)
-{
-	writew(val, hw->flash_address + reg);
-}
-
-static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
-{
-	writel(val, hw->flash_address + reg);
-}
-
-#define er16flash(reg)		__er16flash(hw, (reg))
-#define er32flash(reg)		__er32flash(hw, (reg))
-#define ew16flash(reg,val)	__ew16flash(hw, (reg), (val))
-#define ew32flash(reg,val)	__ew32flash(hw, (reg), (val))
-
-/**
- *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific PHY parameters and function pointers.
- **/
-static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 i = 0;
-
-	phy->addr			= 1;
-	phy->reset_delay_us		= 100;
-
-	phy->id = 0;
-	while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
-	       (i++ < 100)) {
-		msleep(1);
-		ret_val = e1000e_get_phy_id(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Verify phy id */
-	switch (phy->id) {
-	case IGP03E1000_E_PHY_ID:
-		phy->type = e1000_phy_igp_3;
-		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-		break;
-	case IFE_E_PHY_ID:
-	case IFE_PLUS_E_PHY_ID:
-	case IFE_C_E_PHY_ID:
-		phy->type = e1000_phy_ife;
-		phy->autoneg_mask = E1000_ALL_NOT_GIG;
-		break;
-	default:
-		return -E1000_ERR_PHY;
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific NVM parameters and function
- *  pointers.
- **/
-static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 gfpreg;
-	u32 sector_base_addr;
-	u32 sector_end_addr;
-	u16 i;
-
-	/* Can't read flash registers if the register set isn't mapped.
-	 */
-	if (!hw->flash_address) {
-		hw_dbg(hw, "ERROR: Flash registers not mapped\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	nvm->type = e1000_nvm_flash_sw;
-
-	gfpreg = er32flash(ICH_FLASH_GFPREG);
-
-	/* sector_X_addr is a "sector"-aligned address (4096 bytes)
-	 * Add 1 to sector_end_addr since this sector is included in
-	 * the overall size. */
-	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
-	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
-
-	/* flash_base_addr is byte-aligned */
-	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
-
-	/* find total size of the NVM, then cut in half since the total
-	 * size represents two separate NVM banks. */
-	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
-				<< FLASH_SECTOR_ADDR_SHIFT;
-	nvm->flash_bank_size /= 2;
-	/* Adjust to word count */
-	nvm->flash_bank_size /= sizeof(u16);
-
-	nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
-
-	/* Clear shadow ram */
-	for (i = 0; i < nvm->word_size; i++) {
-		dev_spec->shadow_ram[i].modified = 0;
-		dev_spec->shadow_ram[i].value    = 0xFFFF;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific MAC parameters and function
- *  pointers.
- **/
-static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct e1000_mac_info *mac = &hw->mac;
-
-	/* Set media type function pointer */
-	hw->media_type = e1000_media_type_copper;
-
-	/* Set mta register count */
-	mac->mta_reg_count = 32;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
-	if (mac->type == e1000_ich8lan)
-		mac->rar_entry_count--;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid = 1;
-
-	/* Enable PCS Lock-loss workaround for ICH8 */
-	if (mac->type == e1000_ich8lan)
-		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1);
-
-	return 0;
-}
-
-static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	s32 rc;
-
-	rc = e1000_init_mac_params_ich8lan(adapter);
-	if (rc)
-		return rc;
-
-	rc = e1000_init_nvm_params_ich8lan(hw);
-	if (rc)
-		return rc;
-
-	rc = e1000_init_phy_params_ich8lan(hw);
-	if (rc)
-		return rc;
-
-	if ((adapter->hw.mac.type == e1000_ich8lan) &&
-	    (adapter->hw.phy.type == e1000_phy_igp_3))
-		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
-
-	return 0;
-}
-
-/**
- *  e1000_acquire_swflag_ich8lan - Acquire software control flag
- *  @hw: pointer to the HW structure
- *
- *  Acquires the software control flag for performing NVM and PHY
- *  operations.  This is a function pointer entry point only called by
- *  read/write routines for the PHY and NVM parts.
- **/
-static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
-{
-	u32 extcnf_ctrl;
-	u32 timeout = PHY_CFG_TIMEOUT;
-
-	while (timeout) {
-		extcnf_ctrl = er32(EXTCNF_CTRL);
-		extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
-		ew32(EXTCNF_CTRL, extcnf_ctrl);
-
-		extcnf_ctrl = er32(EXTCNF_CTRL);
-		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
-			break;
-		mdelay(1);
-		timeout--;
-	}
-
-	if (!timeout) {
-		hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_release_swflag_ich8lan - Release software control flag
- *  @hw: pointer to the HW structure
- *
- *  Releases the software control flag for performing NVM and PHY operations.
- *  This is a function pointer entry point only called by read/write
- *  routines for the PHY and NVM parts.
- **/
-static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
-{
-	u32 extcnf_ctrl;
-
-	extcnf_ctrl = er32(EXTCNF_CTRL);
-	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
-	ew32(EXTCNF_CTRL, extcnf_ctrl);
-}
-
-/**
- *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
- *  @hw: pointer to the HW structure
- *
- *  Checks if firmware is blocking the reset of the PHY.
- *  This is a function pointer entry point only called by
- *  reset routines.
- **/
-static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
-{
-	u32 fwsm;
-
-	fwsm = er32(FWSM);
-
-	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
-}
-
-/**
- *  e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
- *  @hw: pointer to the HW structure
- *
- *  Forces the speed and duplex settings of the PHY.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	if (phy->type != e1000_phy_ife) {
-		ret_val = e1000e_phy_force_speed_duplex_igp(hw);
-		return ret_val;
-	}
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
-	if (ret_val)
-		return ret_val;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &data);
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, data);
-	if (ret_val)
-		return ret_val;
-
-	/* Disable MDI-X support for 10/100 */
-	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		return ret_val;
-
-	data &= ~IFE_PMC_AUTO_MDIX;
-	data &= ~IFE_PMC_FORCE_MDIX;
-
-	ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
-	if (ret_val)
-		return ret_val;
-
-	hw_dbg(hw, "IFE PMC: %X\n", data);
-
-	udelay(1);
-
-	if (phy->wait_for_link) {
-		hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw,
-						     PHY_FORCE_LIMIT,
-						     100000,
-						     &link);
-		if (ret_val)
-			return ret_val;
-
-		if (!link)
-			hw_dbg(hw, "Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw,
-						     PHY_FORCE_LIMIT,
-						     100000,
-						     &link);
-		if (ret_val)
-			return ret_val;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Resets the PHY
- *  This is a function pointer entry point called by drivers
- *  or other shared routines.
- **/
-static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i;
-	u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
-	s32 ret_val;
-	u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
-	u16 word_addr, reg_data, reg_addr, phy_page = 0;
-
-	ret_val = e1000e_phy_hw_reset_generic(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Initialize the PHY from the NVM on ICH platforms.  This
-	 * is needed due to an issue where the NVM configuration is
-	 * not properly autoloaded after power transitions.
-	 * Therefore, after each PHY reset, we will load the
-	 * configuration data out of the NVM manually.
-	 */
-	if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
-		struct e1000_adapter *adapter = hw->adapter;
-
-		/* Check if SW needs configure the PHY */
-		if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
-		    (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M))
-			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
-		else
-			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
-
-		data = er32(FEXTNVM);
-		if (!(data & sw_cfg_mask))
-			return 0;
-
-		/* Wait for basic configuration completes before proceeding*/
-		do {
-			data = er32(STATUS);
-			data &= E1000_STATUS_LAN_INIT_DONE;
-			udelay(100);
-		} while ((!data) && --loop);
-
-		/* If basic configuration is incomplete before the above loop
-		 * count reaches 0, loading the configuration from NVM will
-		 * leave the PHY in a bad state possibly resulting in no link.
-		 */
-		if (loop == 0) {
-			hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
-		}
-
-		/* Clear the Init Done bit for the next init event */
-		data = er32(STATUS);
-		data &= ~E1000_STATUS_LAN_INIT_DONE;
-		ew32(STATUS, data);
-
-		/* Make sure HW does not configure LCD from PHY
-		 * extended configuration before SW configuration */
-		data = er32(EXTCNF_CTRL);
-		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-			return 0;
-
-		cnf_size = er32(EXTCNF_SIZE);
-		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
-		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
-		if (!cnf_size)
-			return 0;
-
-		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
-		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
-
-		/* Configure LCD from extended configuration
-		 * region. */
-
-		/* cnf_base_addr is in DWORD */
-		word_addr = (u16)(cnf_base_addr << 1);
-
-		for (i = 0; i < cnf_size; i++) {
-			ret_val = e1000_read_nvm(hw,
-						(word_addr + i * 2),
-						1,
-						&reg_data);
-			if (ret_val)
-				return ret_val;
-
-			ret_val = e1000_read_nvm(hw,
-						(word_addr + i * 2 + 1),
-						1,
-						&reg_addr);
-			if (ret_val)
-				return ret_val;
-
-			/* Save off the PHY page for future writes. */
-			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
-				phy_page = reg_data;
-				continue;
-			}
-
-			reg_addr |= phy_page;
-
-			ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data);
-			if (ret_val)
-				return ret_val;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
- *  @hw: pointer to the HW structure
- *
- *  Populates "phy" structure with various feature states.
- *  This function is only called by other family-specific
- *  routines.
- **/
-static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		return ret_val;
-
-	if (!link) {
-		hw_dbg(hw, "Phy info is only valid if link is up\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
-	if (ret_val)
-		return ret_val;
-	phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
-
-	if (phy->polarity_correction) {
-		ret_val = e1000_check_polarity_ife_ich8lan(hw);
-		if (ret_val)
-			return ret_val;
-	} else {
-		/* Polarity is forced */
-		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
-				      ? e1000_rev_polarity_reversed
-				      : e1000_rev_polarity_normal;
-	}
-
-	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		return ret_val;
-
-	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS);
-
-	/* The following parameters are undefined for 10/100 operation. */
-	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-	phy->local_rx = e1000_1000t_rx_status_undefined;
-	phy->remote_rx = e1000_1000t_rx_status_undefined;
-
-	return 0;
-}
-
-/**
- *  e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
- *  @hw: pointer to the HW structure
- *
- *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
- *  This is a function pointer entry point called by drivers
- *  or other shared routines.
- **/
-static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
-{
-	switch (hw->phy.type) {
-	case e1000_phy_ife:
-		return e1000_get_phy_info_ife_ich8lan(hw);
-		break;
-	case e1000_phy_igp_3:
-		return e1000e_get_phy_info_igp(hw);
-		break;
-	default:
-		break;
-	}
-
-	return -E1000_ERR_PHY_TYPE;
-}
-
-/**
- *  e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
- *  @hw: pointer to the HW structure
- *
- *  Polarity is determined on the polarity reveral feature being enabled.
- *  This function is only called by other family-specific
- *  routines.
- **/
-static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	/* Polarity is determined based on the reversal feature
-	 * being enabled.
-	 */
-	if (phy->polarity_correction) {
-		offset	= IFE_PHY_EXTENDED_STATUS_CONTROL;
-		mask	= IFE_PESC_POLARITY_REVERSED;
-	} else {
-		offset	= IFE_PHY_SPECIAL_CONTROL;
-		mask	= IFE_PSC_FORCE_POLARITY;
-	}
-
-	ret_val = e1e_rphy(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->cable_polarity = (phy_data & mask)
-				      ? e1000_rev_polarity_reversed
-				      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
- *  @hw: pointer to the HW structure
- *  @active: TRUE to enable LPLU, FALSE to disable
- *
- *  Sets the LPLU D0 state according to the active flag.  When
- *  activating LPLU this function also disables smart speed
- *  and vice versa.  LPLU will not be activated unless the
- *  device autonegotiation advertisement meets standards of
- *  either 10 or 10/100 or 10/100/1000 at all duplexes.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 phy_ctrl;
-	s32 ret_val = 0;
-	u16 data;
-
-	if (phy->type != e1000_phy_igp_3)
-		return ret_val;
-
-	phy_ctrl = er32(PHY_CTRL);
-
-	if (active) {
-		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		/* Call gig speed drop workaround on LPLU before accessing
-		 * any PHY registers */
-		if ((hw->mac.type == e1000_ich8lan) &&
-		    (hw->phy.type == e1000_phy_igp_3))
-			e1000e_gig_downshift_workaround_ich8lan(hw);
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
-		if (ret_val)
-			return ret_val;
-	} else {
-		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained. */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						    &data);
-			if (ret_val)
-				return ret_val;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						    &data);
-			if (ret_val)
-				return ret_val;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
- *  @hw: pointer to the HW structure
- *  @active: TRUE to enable LPLU, FALSE to disable
- *
- *  Sets the LPLU D3 state according to the active flag.  When
- *  activating LPLU this function also disables smart speed
- *  and vice versa.  LPLU will not be activated unless the
- *  device autonegotiation advertisement meets standards of
- *  either 10 or 10/100 or 10/100/1000 at all duplexes.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 phy_ctrl;
-	s32 ret_val;
-	u16 data;
-
-	phy_ctrl = er32(PHY_CTRL);
-
-	if (!active) {
-		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained. */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw,
-						    IGP01E1000_PHY_PORT_CONFIG,
-						    &data);
-			if (ret_val)
-				return ret_val;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-						     IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw,
-						    IGP01E1000_PHY_PORT_CONFIG,
-						    &data);
-			if (ret_val)
-				return ret_val;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-						     IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		/* Call gig speed drop workaround on LPLU before accessing
-		 * any PHY registers */
-		if ((hw->mac.type == e1000_ich8lan) &&
-		    (hw->phy.type == e1000_phy_igp_3))
-			e1000e_gig_downshift_workaround_ich8lan(hw);
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw,
-					    IGP01E1000_PHY_PORT_CONFIG,
-					    &data);
-		if (ret_val)
-			return ret_val;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw,
-					     IGP01E1000_PHY_PORT_CONFIG,
-					     data);
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the word(s) to read.
- *  @words: Size of data to read in words
- *  @data: Pointer to the word(s) to read at offset.
- *
- *  Reads a word(s) from the NVM using the flash access registers.
- **/
-static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
-				  u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 act_offset;
-	s32 ret_val;
-	u16 i, word;
-
-	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
-	    (words == 0)) {
-		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-		return -E1000_ERR_NVM;
-	}
-
-	ret_val = e1000_acquire_swflag_ich8lan(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Start with the bank offset, then add the relative offset. */
-	act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
-		     ? nvm->flash_bank_size
-		     : 0;
-	act_offset += offset;
-
-	for (i = 0; i < words; i++) {
-		if ((dev_spec->shadow_ram) &&
-		    (dev_spec->shadow_ram[offset+i].modified)) {
-			data[i] = dev_spec->shadow_ram[offset+i].value;
-		} else {
-			ret_val = e1000_read_flash_word_ich8lan(hw,
-								act_offset + i,
-								&word);
-			if (ret_val)
-				break;
-			data[i] = word;
-		}
-	}
-
-	e1000_release_swflag_ich8lan(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_flash_cycle_init_ich8lan - Initialize flash
- *  @hw: pointer to the HW structure
- *
- *  This function does initial flash setup so that a new read/write/erase cycle
- *  can be started.
- **/
-static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
-{
-	union ich8_hws_flash_status hsfsts;
-	s32 ret_val = -E1000_ERR_NVM;
-	s32 i = 0;
-
-	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-
-	/* Check if the flash descriptor is valid */
-	if (hsfsts.hsf_status.fldesvalid == 0) {
-		hw_dbg(hw, "Flash descriptor invalid.  "
-			 "SW Sequencing must be used.");
-		return -E1000_ERR_NVM;
-	}
-
-	/* Clear FCERR and DAEL in hw status by writing 1 */
-	hsfsts.hsf_status.flcerr = 1;
-	hsfsts.hsf_status.dael = 1;
-
-	ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
-
-	/* Either we should have a hardware SPI cycle in progress
-	 * bit to check against, in order to start a new cycle or
-	 * FDONE bit should be changed in the hardware so that it
-	 * is 1 after harware reset, which can then be used as an
-	 * indication whether a cycle is in progress or has been
-	 * completed.
-	 */
-
-	if (hsfsts.hsf_status.flcinprog == 0) {
-		/* There is no cycle running at present,
-		 * so we can start a cycle */
-		/* Begin by setting Flash Cycle Done. */
-		hsfsts.hsf_status.flcdone = 1;
-		ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
-		ret_val = 0;
-	} else {
-		/* otherwise poll for sometime so the current
-		 * cycle has a chance to end before giving up. */
-		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
-			hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS);
-			if (hsfsts.hsf_status.flcinprog == 0) {
-				ret_val = 0;
-				break;
-			}
-			udelay(1);
-		}
-		if (ret_val == 0) {
-			/* Successful in waiting for previous cycle to timeout,
-			 * now set the Flash Cycle Done. */
-			hsfsts.hsf_status.flcdone = 1;
-			ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
-		} else {
-			hw_dbg(hw, "Flash controller busy, cannot get access");
-		}
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
- *  @hw: pointer to the HW structure
- *  @timeout: maximum time to wait for completion
- *
- *  This function starts a flash cycle and waits for its completion.
- **/
-static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
-{
-	union ich8_hws_flash_ctrl hsflctl;
-	union ich8_hws_flash_status hsfsts;
-	s32 ret_val = -E1000_ERR_NVM;
-	u32 i = 0;
-
-	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
-	hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-	hsflctl.hsf_ctrl.flcgo = 1;
-	ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-	/* wait till FDONE bit is set to 1 */
-	do {
-		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-		if (hsfsts.hsf_status.flcdone == 1)
-			break;
-		udelay(1);
-	} while (i++ < timeout);
-
-	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
-		return 0;
-
-	return ret_val;
-}
-
-/**
- *  e1000_read_flash_word_ich8lan - Read word from flash
- *  @hw: pointer to the HW structure
- *  @offset: offset to data location
- *  @data: pointer to the location for storing the data
- *
- *  Reads the flash word at offset into data.  Offset is converted
- *  to bytes before read.
- **/
-static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
-					 u16 *data)
-{
-	/* Must convert offset into bytes. */
-	offset <<= 1;
-
-	return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
-}
-
-/**
- *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the byte or word to read.
- *  @size: Size of data to read, 1=byte 2=word
- *  @data: Pointer to the word to store the value read.
- *
- *  Reads a byte or word from the NVM using the flash access registers.
- **/
-static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-					 u8 size, u16 *data)
-{
-	union ich8_hws_flash_status hsfsts;
-	union ich8_hws_flash_ctrl hsflctl;
-	u32 flash_linear_addr;
-	u32 flash_data = 0;
-	s32 ret_val = -E1000_ERR_NVM;
-	u8 count = 0;
-
-	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
-		return -E1000_ERR_NVM;
-
-	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
-			    hw->nvm.flash_base_addr;
-
-	do {
-		udelay(1);
-		/* Steps */
-		ret_val = e1000_flash_cycle_init_ich8lan(hw);
-		if (ret_val != 0)
-			break;
-
-		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
-		hsflctl.hsf_ctrl.fldbcount = size - 1;
-		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
-		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
-
-		ret_val = e1000_flash_cycle_ich8lan(hw,
-						ICH_FLASH_READ_COMMAND_TIMEOUT);
-
-		/* Check if FCERR is set to 1, if set to 1, clear it
-		 * and try the whole sequence a few more times, else
-		 * read in (shift in) the Flash Data0, the order is
-		 * least significant byte first msb to lsb */
-		if (ret_val == 0) {
-			flash_data = er32flash(ICH_FLASH_FDATA0);
-			if (size == 1) {
-				*data = (u8)(flash_data & 0x000000FF);
-			} else if (size == 2) {
-				*data = (u16)(flash_data & 0x0000FFFF);
-			}
-			break;
-		} else {
-			/* If we've gotten here, then things are probably
-			 * completely hosed, but if the error condition is
-			 * detected, it won't hurt to give it another try...
-			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
-			 */
-			hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-			if (hsfsts.hsf_status.flcerr == 1) {
-				/* Repeat for some time before giving up. */
-				continue;
-			} else if (hsfsts.hsf_status.flcdone == 0) {
-				hw_dbg(hw, "Timeout error - flash cycle "
-					 "did not complete.");
-				break;
-			}
-		}
-	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
-
-	return ret_val;
-}
-
-/**
- *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the word(s) to write.
- *  @words: Size of data to write in words
- *  @data: Pointer to the word(s) to write at offset.
- *
- *  Writes a byte or word to the NVM using the flash access registers.
- **/
-static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
-				   u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	s32 ret_val;
-	u16 i;
-
-	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
-	    (words == 0)) {
-		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-		return -E1000_ERR_NVM;
-	}
-
-	ret_val = e1000_acquire_swflag_ich8lan(hw);
-	if (ret_val)
-		return ret_val;
-
-	for (i = 0; i < words; i++) {
-		dev_spec->shadow_ram[offset+i].modified = 1;
-		dev_spec->shadow_ram[offset+i].value = data[i];
-	}
-
-	e1000_release_swflag_ich8lan(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
- *  @hw: pointer to the HW structure
- *
- *  The NVM checksum is updated by calling the generic update_nvm_checksum,
- *  which writes the checksum to the shadow ram.  The changes in the shadow
- *  ram are then committed to the EEPROM by processing each bank at a time
- *  checking for the modified bit and writing only the pending changes.
- *  After a succesful commit, the shadow ram is cleared and is ready for
- *  future writes.
- **/
-static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 i, act_offset, new_bank_offset, old_bank_offset;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1000e_update_nvm_checksum_generic(hw);
-	if (ret_val)
-		return ret_val;;
-
-	if (nvm->type != e1000_nvm_flash_sw)
-		return ret_val;;
-
-	ret_val = e1000_acquire_swflag_ich8lan(hw);
-	if (ret_val)
-		return ret_val;;
-
-	/* We're writing to the opposite bank so if we're on bank 1,
-	 * write to bank 0 etc.  We also need to erase the segment that
-	 * is going to be written */
-	if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
-		new_bank_offset = nvm->flash_bank_size;
-		old_bank_offset = 0;
-		e1000_erase_flash_bank_ich8lan(hw, 1);
-	} else {
-		old_bank_offset = nvm->flash_bank_size;
-		new_bank_offset = 0;
-		e1000_erase_flash_bank_ich8lan(hw, 0);
-	}
-
-	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
-		/* Determine whether to write the value stored
-		 * in the other NVM bank or a modified value stored
-		 * in the shadow RAM */
-		if (dev_spec->shadow_ram[i].modified) {
-			data = dev_spec->shadow_ram[i].value;
-		} else {
-			e1000_read_flash_word_ich8lan(hw,
-						      i + old_bank_offset,
-						      &data);
-		}
-
-		/* If the word is 0x13, then make sure the signature bits
-		 * (15:14) are 11b until the commit has completed.
-		 * This will allow us to write 10b which indicates the
-		 * signature is valid.  We want to do this after the write
-		 * has completed so that we don't mark the segment valid
-		 * while the write is still in progress */
-		if (i == E1000_ICH_NVM_SIG_WORD)
-			data |= E1000_ICH_NVM_SIG_MASK;
-
-		/* Convert offset to bytes. */
-		act_offset = (i + new_bank_offset) << 1;
-
-		udelay(100);
-		/* Write the bytes to the new bank. */
-		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
-							       act_offset,
-							       (u8)data);
-		if (ret_val)
-			break;
-
-		udelay(100);
-		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
-							  act_offset + 1,
-							  (u8)(data >> 8));
-		if (ret_val)
-			break;
-	}
-
-	/* Don't bother writing the segment valid bits if sector
-	 * programming failed. */
-	if (ret_val) {
-		hw_dbg(hw, "Flash commit failed.\n");
-		e1000_release_swflag_ich8lan(hw);
-		return ret_val;
-	}
-
-	/* Finally validate the new segment by setting bit 15:14
-	 * to 10b in word 0x13 , this can be done without an
-	 * erase as well since these bits are 11 to start with
-	 * and we need to change bit 14 to 0b */
-	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
-	e1000_read_flash_word_ich8lan(hw, act_offset, &data);
-	data &= 0xBFFF;
-	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
-						       act_offset * 2 + 1,
-						       (u8)(data >> 8));
-	if (ret_val) {
-		e1000_release_swflag_ich8lan(hw);
-		return ret_val;
-	}
-
-	/* And invalidate the previously valid segment by setting
-	 * its signature word (0x13) high_byte to 0b. This can be
-	 * done without an erase because flash erase sets all bits
-	 * to 1's. We can write 1's to 0's without an erase */
-	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
-	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
-	if (ret_val) {
-		e1000_release_swflag_ich8lan(hw);
-		return ret_val;
-	}
-
-	/* Great!  Everything worked, we can now clear the cached entries. */
-	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
-		dev_spec->shadow_ram[i].modified = 0;
-		dev_spec->shadow_ram[i].value = 0xFFFF;
-	}
-
-	e1000_release_swflag_ich8lan(hw);
-
-	/* Reload the EEPROM, or else modifications will not appear
-	 * until after the next adapter reset.
-	 */
-	e1000e_reload_nvm(hw);
-	msleep(10);
-
-	return ret_val;
-}
-
-/**
- *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
- *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
- *  calculated, in which case we need to calculate the checksum and set bit 6.
- **/
-static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 data;
-
-	/* Read 0x19 and check bit 6.  If this bit is 0, the checksum
-	 * needs to be fixed.  This bit is an indication that the NVM
-	 * was prepared by OEM software and did not calculate the
-	 * checksum...a likely scenario.
-	 */
-	ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
-	if (ret_val)
-		return ret_val;
-
-	if ((data & 0x40) == 0) {
-		data |= 0x40;
-		ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
-		if (ret_val)
-			return ret_val;
-		ret_val = e1000e_update_nvm_checksum(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	return e1000e_validate_nvm_checksum_generic(hw);
-}
-
-/**
- *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the byte/word to read.
- *  @size: Size of data to read, 1=byte 2=word
- *  @data: The byte(s) to write to the NVM.
- *
- *  Writes one/two bytes to the NVM using the flash access registers.
- **/
-static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-					  u8 size, u16 data)
-{
-	union ich8_hws_flash_status hsfsts;
-	union ich8_hws_flash_ctrl hsflctl;
-	u32 flash_linear_addr;
-	u32 flash_data = 0;
-	s32 ret_val;
-	u8 count = 0;
-
-	if (size < 1 || size > 2 || data > size * 0xff ||
-	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
-		return -E1000_ERR_NVM;
-
-	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
-			    hw->nvm.flash_base_addr;
-
-	do {
-		udelay(1);
-		/* Steps */
-		ret_val = e1000_flash_cycle_init_ich8lan(hw);
-		if (ret_val)
-			break;
-
-		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
-		hsflctl.hsf_ctrl.fldbcount = size -1;
-		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
-		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
-
-		if (size == 1)
-			flash_data = (u32)data & 0x00FF;
-		else
-			flash_data = (u32)data;
-
-		ew32flash(ICH_FLASH_FDATA0, flash_data);
-
-		/* check if FCERR is set to 1 , if set to 1, clear it
-		 * and try the whole sequence a few more times else done */
-		ret_val = e1000_flash_cycle_ich8lan(hw,
-					       ICH_FLASH_WRITE_COMMAND_TIMEOUT);
-		if (!ret_val)
-			break;
-
-		/* If we're here, then things are most likely
-		 * completely hosed, but if the error condition
-		 * is detected, it won't hurt to give it another
-		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
-		 */
-		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-		if (hsfsts.hsf_status.flcerr == 1)
-			/* Repeat for some time before giving up. */
-			continue;
-		if (hsfsts.hsf_status.flcdone == 0) {
-			hw_dbg(hw, "Timeout error - flash cycle "
-				 "did not complete.");
-			break;
-		}
-	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
-
-	return ret_val;
-}
-
-/**
- *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
- *  @hw: pointer to the HW structure
- *  @offset: The index of the byte to read.
- *  @data: The byte to write to the NVM.
- *
- *  Writes a single byte to the NVM using the flash access registers.
- **/
-static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
-					  u8 data)
-{
-	u16 word = (u16)data;
-
-	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
-}
-
-/**
- *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset of the byte to write.
- *  @byte: The byte to write to the NVM.
- *
- *  Writes a single byte to the NVM using the flash access registers.
- *  Goes through a retry algorithm before giving up.
- **/
-static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
-						u32 offset, u8 byte)
-{
-	s32 ret_val;
-	u16 program_retries;
-
-	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
-	if (!ret_val)
-		return ret_val;
-
-	for (program_retries = 0; program_retries < 100; program_retries++) {
-		hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset);
-		udelay(100);
-		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
-		if (!ret_val)
-			break;
-	}
-	if (program_retries == 100)
-		return -E1000_ERR_NVM;
-
-	return 0;
-}
-
-/**
- *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
- *  @hw: pointer to the HW structure
- *  @bank: 0 for first bank, 1 for second bank, etc.
- *
- *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
- *  bank N is 4096 * N + flash_reg_addr.
- **/
-static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	union ich8_hws_flash_status hsfsts;
-	union ich8_hws_flash_ctrl hsflctl;
-	u32 flash_linear_addr;
-	/* bank size is in 16bit words - adjust to bytes */
-	u32 flash_bank_size = nvm->flash_bank_size * 2;
-	s32 ret_val;
-	s32 count = 0;
-	s32 iteration;
-	s32 sector_size;
-	s32 j;
-
-	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-
-	/* Determine HW Sector size: Read BERASE bits of hw flash status
-	 * register */
-	/* 00: The Hw sector is 256 bytes, hence we need to erase 16
-	 *     consecutive sectors.  The start index for the nth Hw sector
-	 *     can be calculated as = bank * 4096 + n * 256
-	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
-	 *     The start index for the nth Hw sector can be calculated
-	 *     as = bank * 4096
-	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
-	 *     (ich9 only, otherwise error condition)
-	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
-	 */
-	switch (hsfsts.hsf_status.berasesz) {
-	case 0:
-		/* Hw sector size 256 */
-		sector_size = ICH_FLASH_SEG_SIZE_256;
-		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
-		break;
-	case 1:
-		sector_size = ICH_FLASH_SEG_SIZE_4K;
-		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
-		break;
-	case 2:
-		if (hw->mac.type == e1000_ich9lan) {
-			sector_size = ICH_FLASH_SEG_SIZE_8K;
-			iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
-		} else {
-			return -E1000_ERR_NVM;
-		}
-		break;
-	case 3:
-		sector_size = ICH_FLASH_SEG_SIZE_64K;
-		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
-		break;
-	default:
-		return -E1000_ERR_NVM;
-	}
-
-	/* Start with the base address, then add the sector offset. */
-	flash_linear_addr = hw->nvm.flash_base_addr;
-	flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
-
-	for (j = 0; j < iteration ; j++) {
-		do {
-			/* Steps */
-			ret_val = e1000_flash_cycle_init_ich8lan(hw);
-			if (ret_val)
-				return ret_val;
-
-			/* Write a value 11 (block Erase) in Flash
-			 * Cycle field in hw flash control */
-			hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
-			ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-			/* Write the last 24 bits of an index within the
-			 * block into Flash Linear address field in Flash
-			 * Address.
-			 */
-			flash_linear_addr += (j * sector_size);
-			ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
-
-			ret_val = e1000_flash_cycle_ich8lan(hw,
-					       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
-			if (ret_val == 0)
-				break;
-
-			/* Check if FCERR is set to 1.  If 1,
-			 * clear it and try the whole sequence
-			 * a few more times else Done */
-			hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-			if (hsfsts.hsf_status.flcerr == 1)
-				/* repeat for some time before
-				 * giving up */
-				continue;
-			else if (hsfsts.hsf_status.flcdone == 0)
-				return ret_val;
-		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_valid_led_default_ich8lan - Set the default LED settings
- *  @hw: pointer to the HW structure
- *  @data: Pointer to the LED settings
- *
- *  Reads the LED default settings from the NVM to data.  If the NVM LED
- *  settings is all 0's or F's, set the LED default to a valid LED default
- *  setting.
- **/
-static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 ||
-	    *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT_ICH8LAN;
-
-	return 0;
-}
-
-/**
- *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
- *  @hw: pointer to the HW structure
- *
- *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
- *  register, so the the bus width is hard coded.
- **/
-static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	s32 ret_val;
-
-	ret_val = e1000e_get_bus_info_pcie(hw);
-
-	/* ICH devices are "PCI Express"-ish.  They have
-	 * a configuration space, but do not contain
-	 * PCI Express Capability registers, so bus width
-	 * must be hardcoded.
-	 */
-	if (bus->width == e1000_bus_width_unknown)
-		bus->width = e1000_bus_width_pcie_x1;
-
-	return ret_val;
-}
-
-/**
- *  e1000_reset_hw_ich8lan - Reset the hardware
- *  @hw: pointer to the HW structure
- *
- *  Does a full reset of the hardware which includes a reset of the PHY and
- *  MAC.
- **/
-static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
-{
-	u32 ctrl, icr, kab;
-	s32 ret_val;
-
-	/* Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = e1000e_disable_pcie_master(hw);
-	if (ret_val) {
-		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
-	}
-
-	hw_dbg(hw, "Masking off all interrupts\n");
-	ew32(IMC, 0xffffffff);
-
-	/* Disable the Transmit and Receive units.  Then delay to allow
-	 * any pending transactions to complete before we hit the MAC
-	 * with the global reset.
-	 */
-	ew32(RCTL, 0);
-	ew32(TCTL, E1000_TCTL_PSP);
-	e1e_flush();
-
-	msleep(10);
-
-	/* Workaround for ICH8 bit corruption issue in FIFO memory */
-	if (hw->mac.type == e1000_ich8lan) {
-		/* Set Tx and Rx buffer allocation to 8k apiece. */
-		ew32(PBA, E1000_PBA_8K);
-		/* Set Packet Buffer Size to 16k. */
-		ew32(PBS, E1000_PBS_16K);
-	}
-
-	ctrl = er32(CTRL);
-
-	if (!e1000_check_reset_block(hw)) {
-		/* PHY HW reset requires MAC CORE reset at the same
-		 * time to make sure the interface between MAC and the
-		 * external PHY is reset.
-		 */
-		ctrl |= E1000_CTRL_PHY_RST;
-	}
-	ret_val = e1000_acquire_swflag_ich8lan(hw);
-	hw_dbg(hw, "Issuing a global reset to ich8lan");
-	ew32(CTRL, (ctrl | E1000_CTRL_RST));
-	msleep(20);
-
-	ret_val = e1000e_get_auto_rd_done(hw);
-	if (ret_val) {
-		/*
-		 * When auto config read does not complete, do not
-		 * return with an error. This can happen in situations
-		 * where there is no eeprom and prevents getting link.
-		 */
-		hw_dbg(hw, "Auto Read Done did not complete\n");
-	}
-
-	ew32(IMC, 0xffffffff);
-	icr = er32(ICR);
-
-	kab = er32(KABGTXD);
-	kab |= E1000_KABGTXD_BGSQLBIAS;
-	ew32(KABGTXD, kab);
-
-	return ret_val;
-}
-
-/**
- *  e1000_init_hw_ich8lan - Initialize the hardware
- *  @hw: pointer to the HW structure
- *
- *  Prepares the hardware for transmit and receive by doing the following:
- *   - initialize hardware bits
- *   - initialize LED identification
- *   - setup receive address registers
- *   - setup flow control
- *   - setup transmit discriptors
- *   - clear statistics
- **/
-static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl_ext, txdctl, snoop;
-	s32 ret_val;
-	u16 i;
-
-	e1000_initialize_hw_bits_ich8lan(hw);
-
-	/* Initialize identification LED */
-	ret_val = e1000e_id_led_init(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error initializing identification LED\n");
-		return ret_val;
-	}
-
-	/* Setup the receive address. */
-	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	hw_dbg(hw, "Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/* Setup link and flow control */
-	ret_val = e1000_setup_link_ich8lan(hw);
-
-	/* Set the transmit descriptor write-back policy for both queues */
-	txdctl = er32(TXDCTL);
-	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
-		 E1000_TXDCTL_FULL_TX_DESC_WB;
-	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
-		 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
-	ew32(TXDCTL, txdctl);
-	txdctl = er32(TXDCTL1);
-	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
-		 E1000_TXDCTL_FULL_TX_DESC_WB;
-	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
-		 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
-	ew32(TXDCTL1, txdctl);
-
-	/* ICH8 has opposite polarity of no_snoop bits.
-	 * By default, we should use snoop behavior. */
-	if (mac->type == e1000_ich8lan)
-		snoop = PCIE_ICH8_SNOOP_ALL;
-	else
-		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
-	e1000e_set_pcie_no_snoop(hw, snoop);
-
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
-	ew32(CTRL_EXT, ctrl_ext);
-
-	/* Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_ich8lan(hw);
-
-	return 0;
-}
-/**
- *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
- *  @hw: pointer to the HW structure
- *
- *  Sets/Clears required hardware bits necessary for correctly setting up the
- *  hardware for transmit and receive.
- **/
-static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
-{
-	u32 reg;
-
-	/* Extended Device Control */
-	reg = er32(CTRL_EXT);
-	reg |= (1 << 22);
-	ew32(CTRL_EXT, reg);
-
-	/* Transmit Descriptor Control 0 */
-	reg = er32(TXDCTL);
-	reg |= (1 << 22);
-	ew32(TXDCTL, reg);
-
-	/* Transmit Descriptor Control 1 */
-	reg = er32(TXDCTL1);
-	reg |= (1 << 22);
-	ew32(TXDCTL1, reg);
-
-	/* Transmit Arbitration Control 0 */
-	reg = er32(TARC0);
-	if (hw->mac.type == e1000_ich8lan)
-		reg |= (1 << 28) | (1 << 29);
-	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
-	ew32(TARC0, reg);
-
-	/* Transmit Arbitration Control 1 */
-	reg = er32(TARC1);
-	if (er32(TCTL) & E1000_TCTL_MULR)
-		reg &= ~(1 << 28);
-	else
-		reg |= (1 << 28);
-	reg |= (1 << 24) | (1 << 26) | (1 << 30);
-	ew32(TARC1, reg);
-
-	/* Device Status */
-	if (hw->mac.type == e1000_ich8lan) {
-		reg = er32(STATUS);
-		reg &= ~(1 << 31);
-		ew32(STATUS, reg);
-	}
-}
-
-/**
- *  e1000_setup_link_ich8lan - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-
-	if (e1000_check_reset_block(hw))
-		return 0;
-
-	/* ICH parts do not have a word in the NVM to determine
-	 * the default flow control setting, so we explicitly
-	 * set it to full.
-	 */
-	if (mac->fc == e1000_fc_default)
-		mac->fc = e1000_fc_full;
-
-	mac->original_fc = mac->fc;
-
-	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
-
-	/* Continue to configure the copper link. */
-	ret_val = e1000_setup_copper_link_ich8lan(hw);
-	if (ret_val)
-		return ret_val;
-
-	ew32(FCTTV, mac->fc_pause_time);
-
-	return e1000e_set_fc_watermarks(hw);
-}
-
-/**
- *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
- *  @hw: pointer to the HW structure
- *
- *  Configures the kumeran interface to the PHY to wait the appropriate time
- *  when polling the PHY, then call the generic setup_copper_link to finish
- *  configuring the copper link.
- **/
-static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-	u16 reg_data;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ew32(CTRL, ctrl);
-
-	/* Set the mac to wait the maximum time between each iteration
-	 * and increase the max iterations when polling the phy;
-	 * this fixes erroneous timeouts at 10Mbps. */
-	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
-	if (ret_val)
-		return ret_val;
-	ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
-	if (ret_val)
-		return ret_val;
-	reg_data |= 0x3F;
-	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
-	if (ret_val)
-		return ret_val;
-
-	if (hw->phy.type == e1000_phy_igp_3) {
-		ret_val = e1000e_copper_link_setup_igp(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	return e1000e_setup_copper_link(hw);
-}
-
-/**
- *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
- *  @hw: pointer to the HW structure
- *  @speed: pointer to store current link speed
- *  @duplex: pointer to store the current link duplex
- *
- *  Calls the generic get_speed_and_duplex to retreive the current link
- *  information and then calls the Kumeran lock loss workaround for links at
- *  gigabit speeds.
- **/
-static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
-					  u16 *duplex)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
-	if (ret_val)
-		return ret_val;
-
-	if ((hw->mac.type == e1000_ich8lan) &&
-	    (hw->phy.type == e1000_phy_igp_3) &&
-	    (*speed == SPEED_1000)) {
-		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
- *  @hw: pointer to the HW structure
- *
- *  Work-around for 82566 Kumeran PCS lock loss:
- *  On link status change (i.e. PCI reset, speed change) and link is up and
- *  speed is gigabit-
- *    0) if workaround is optionally disabled do nothing
- *    1) wait 1ms for Kumeran link to come up
- *    2) check Kumeran Diagnostic register PCS lock loss bit
- *    3) if not set the link is locked (all is good), otherwise...
- *    4) reset the PHY
- *    5) repeat up to 10 times
- *  Note: this is only called for IGP3 copper when speed is 1gb.
- **/
-static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 phy_ctrl;
-	s32 ret_val;
-	u16 i, data;
-	bool link;
-
-	if (!dev_spec->kmrn_lock_loss_workaround_enabled)
-		return 0;
-
-	/* Make sure link is up before proceeding.  If not just return.
-	 * Attempting this while link is negotiating fouled up link
-	 * stability */
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (!link)
-		return 0;
-
-	for (i = 0; i < 10; i++) {
-		/* read once to clear */
-		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
-		if (ret_val)
-			return ret_val;
-		/* and again to get new status */
-		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
-		if (ret_val)
-			return ret_val;
-
-		/* check for PCS lock */
-		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
-			return 0;
-
-		/* Issue PHY reset */
-		e1000_phy_hw_reset(hw);
-		mdelay(5);
-	}
-	/* Disable GigE link negotiation */
-	phy_ctrl = er32(PHY_CTRL);
-	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
-		     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
-	ew32(PHY_CTRL, phy_ctrl);
-
-	/* Call gig speed drop workaround on Giga disable before accessing
-	 * any PHY registers */
-	e1000e_gig_downshift_workaround_ich8lan(hw);
-
-	/* unable to acquire PCS lock */
-	return -E1000_ERR_PHY;
-}
-
-/**
- *  e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state
- *  @hw: pointer to the HW structure
- *  @state: boolean value used to set the current Kumaran workaround state
- *
- *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
- *  /disabled - FALSE).
- **/
-void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
-						 bool state)
-{
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-
-	if (hw->mac.type != e1000_ich8lan) {
-		hw_dbg(hw, "Workaround applies to ICH8 only.\n");
-		return;
-	}
-
-	dev_spec->kmrn_lock_loss_workaround_enabled = state;
-}
-
-/**
- *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
- *  @hw: pointer to the HW structure
- *
- *  Workaround for 82566 power-down on D3 entry:
- *    1) disable gigabit link
- *    2) write VR power-down enable
- *    3) read it back
- *  Continue if successful, else issue LCD reset and repeat
- **/
-void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
-{
-	u32 reg;
-	u16 data;
-	u8  retry = 0;
-
-	if (hw->phy.type != e1000_phy_igp_3)
-		return;
-
-	/* Try the workaround twice (if needed) */
-	do {
-		/* Disable link */
-		reg = er32(PHY_CTRL);
-		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
-			E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
-		ew32(PHY_CTRL, reg);
-
-		/* Call gig speed drop workaround on Giga disable before
-		 * accessing any PHY registers */
-		if (hw->mac.type == e1000_ich8lan)
-			e1000e_gig_downshift_workaround_ich8lan(hw);
-
-		/* Write VR power-down enable */
-		e1e_rphy(hw, IGP3_VR_CTRL, &data);
-		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
-		e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN);
-
-		/* Read it back and test */
-		e1e_rphy(hw, IGP3_VR_CTRL, &data);
-		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
-		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
-			break;
-
-		/* Issue PHY reset and repeat at most one more time */
-		reg = er32(CTRL);
-		ew32(CTRL, reg | E1000_CTRL_PHY_RST);
-		retry++;
-	} while (retry);
-}
-
-/**
- *  e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working
- *  @hw: pointer to the HW structure
- *
- *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
- *  LPLU, Giga disable, MDIC PHY reset):
- *    1) Set Kumeran Near-end loopback
- *    2) Clear Kumeran Near-end loopback
- *  Should only be called for ICH8[m] devices with IGP_3 Phy.
- **/
-void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 reg_data;
-
-	if ((hw->mac.type != e1000_ich8lan) ||
-	    (hw->phy.type != e1000_phy_igp_3))
-		return;
-
-	ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
-				      &reg_data);
-	if (ret_val)
-		return;
-	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
-				       reg_data);
-	if (ret_val)
-		return;
-	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
-	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
-				       reg_data);
-}
-
-/**
- *  e1000_cleanup_led_ich8lan - Restore the default LED operation
- *  @hw: pointer to the HW structure
- *
- *  Return the LED back to the default configuration.
- **/
-static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
-{
-	if (hw->phy.type == e1000_phy_ife)
-		return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
-
-	ew32(LEDCTL, hw->mac.ledctl_default);
-	return 0;
-}
-
-/**
- *  e1000_led_on_ich8lan - Turn LED's on
- *  @hw: pointer to the HW structure
- *
- *  Turn on the LED's.
- **/
-static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
-{
-	if (hw->phy.type == e1000_phy_ife)
-		return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
-				(IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
-
-	ew32(LEDCTL, hw->mac.ledctl_mode2);
-	return 0;
-}
-
-/**
- *  e1000_led_off_ich8lan - Turn LED's off
- *  @hw: pointer to the HW structure
- *
- *  Turn off the LED's.
- **/
-static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
-{
-	if (hw->phy.type == e1000_phy_ife)
-		return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
-			       (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
-
-	ew32(LEDCTL, hw->mac.ledctl_mode1);
-	return 0;
-}
-
-/**
- *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
- *  @hw: pointer to the HW structure
- *
- *  Clears hardware counters specific to the silicon family and calls
- *  clear_hw_cntrs_generic to clear all general purpose counters.
- **/
-static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
-{
-	u32 temp;
-
-	e1000e_clear_hw_cntrs_base(hw);
-
-	temp = er32(ALGNERRC);
-	temp = er32(RXERRC);
-	temp = er32(TNCRS);
-	temp = er32(CEXTERR);
-	temp = er32(TSCTC);
-	temp = er32(TSCTFC);
-
-	temp = er32(MGTPRC);
-	temp = er32(MGTPDC);
-	temp = er32(MGTPTC);
-
-	temp = er32(IAC);
-	temp = er32(ICRXOC);
-
-}
-
-static struct e1000_mac_operations ich8_mac_ops = {
-	.mng_mode_enab		= E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
-	.check_for_link		= e1000e_check_for_copper_link,
-	.cleanup_led		= e1000_cleanup_led_ich8lan,
-	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
-	.get_bus_info		= e1000_get_bus_info_ich8lan,
-	.get_link_up_info	= e1000_get_link_up_info_ich8lan,
-	.led_on			= e1000_led_on_ich8lan,
-	.led_off		= e1000_led_off_ich8lan,
-	.mc_addr_list_update	= e1000e_mc_addr_list_update_generic,
-	.reset_hw		= e1000_reset_hw_ich8lan,
-	.init_hw		= e1000_init_hw_ich8lan,
-	.setup_link		= e1000_setup_link_ich8lan,
-	.setup_physical_interface= e1000_setup_copper_link_ich8lan,
-};
-
-static struct e1000_phy_operations ich8_phy_ops = {
-	.acquire_phy		= e1000_acquire_swflag_ich8lan,
-	.check_reset_block	= e1000_check_reset_block_ich8lan,
-	.commit_phy		= NULL,
-	.force_speed_duplex	= e1000_phy_force_speed_duplex_ich8lan,
-	.get_cfg_done		= e1000e_get_cfg_done,
-	.get_cable_length	= e1000e_get_cable_length_igp_2,
-	.get_phy_info		= e1000_get_phy_info_ich8lan,
-	.read_phy_reg		= e1000e_read_phy_reg_igp,
-	.release_phy		= e1000_release_swflag_ich8lan,
-	.reset_phy		= e1000_phy_hw_reset_ich8lan,
-	.set_d0_lplu_state	= e1000_set_d0_lplu_state_ich8lan,
-	.set_d3_lplu_state	= e1000_set_d3_lplu_state_ich8lan,
-	.write_phy_reg		= e1000e_write_phy_reg_igp,
-};
-
-static struct e1000_nvm_operations ich8_nvm_ops = {
-	.acquire_nvm		= e1000_acquire_swflag_ich8lan,
-	.read_nvm	 	= e1000_read_nvm_ich8lan,
-	.release_nvm		= e1000_release_swflag_ich8lan,
-	.update_nvm		= e1000_update_nvm_checksum_ich8lan,
-	.valid_led_default	= e1000_valid_led_default_ich8lan,
-	.validate_nvm		= e1000_validate_nvm_checksum_ich8lan,
-	.write_nvm		= e1000_write_nvm_ich8lan,
-};
-
-struct e1000_info e1000_ich8_info = {
-	.mac			= e1000_ich8lan,
-	.flags			= FLAG_HAS_WOL
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_FLASH
-				  | FLAG_APME_IN_WUC,
-	.pba			= 8,
-	.get_invariants		= e1000_get_invariants_ich8lan,
-	.mac_ops		= &ich8_mac_ops,
-	.phy_ops		= &ich8_phy_ops,
-	.nvm_ops		= &ich8_nvm_ops,
-};
-
-struct e1000_info e1000_ich9_info = {
-	.mac			= e1000_ich9lan,
-	.flags			= FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_WOL
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_ERT
-				  | FLAG_HAS_FLASH
-				  | FLAG_APME_IN_WUC,
-	.pba			= 10,
-	.get_invariants		= e1000_get_invariants_ich8lan,
-	.mac_ops		= &ich8_mac_ops,
-	.phy_ops		= &ich8_phy_ops,
-	.nvm_ops		= &ich8_nvm_ops,
-};
-
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/kcompat.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/kcompat.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/kcompat.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/kcompat.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,318 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+
+#ifdef DRIVER_E1000E
+#include "e1000.h"
+#endif
+
+
+
+
+#include "kcompat.h"
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) )
+
+/**************************************/
+/* PCI DMA MAPPING */
+
+#if defined(CONFIG_HIGHMEM)
+
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+
+u64
+_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset,
+                 size_t size, int direction)
+{
+	return (((u64) (page - mem_map) << PAGE_SHIFT) + offset +
+		PCI_DRAM_OFFSET);
+}
+
+#else /* CONFIG_HIGHMEM */
+
+u64
+_kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset,
+                 size_t size, int direction)
+{
+	return pci_map_single(dev, (void *)page_address(page) + offset, size,
+			      direction);
+}
+
+#endif /* CONFIG_HIGHMEM */
+
+void
+_kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size,
+                   int direction)
+{
+	return pci_unmap_single(dev, dma_addr, size, direction);
+}
+
+#endif /* 2.4.13 => 2.4.3 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) )
+
+/**************************************/
+/* PCI DRIVER API */
+
+int
+_kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
+{
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
+	dev->dma_mask = mask;
+	return 0;
+}
+
+int
+_kc_pci_request_regions(struct pci_dev *dev, char *res_name)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		if (pci_resource_len(dev, i) == 0)
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+			if (!request_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) {
+				pci_release_regions(dev);
+				return -EBUSY;
+			}
+		} else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
+			if (!request_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i), res_name)) {
+				pci_release_regions(dev);
+				return -EBUSY;
+			}
+		}
+	}
+	return 0;
+}
+
+void
+_kc_pci_release_regions(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		if (pci_resource_len(dev, i) == 0)
+			continue;
+
+		if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+			release_region(pci_resource_start(dev, i), pci_resource_len(dev, i));
+
+		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+			release_mem_region(pci_resource_start(dev, i), pci_resource_len(dev, i));
+	}
+}
+
+/**************************************/
+/* NETWORK DRIVER API */
+
+struct net_device *
+_kc_alloc_etherdev(int sizeof_priv)
+{
+	struct net_device *dev;
+	int alloc_size;
+
+	alloc_size = sizeof(*dev) + sizeof_priv + IFNAMSIZ + 31;
+	dev = kmalloc(alloc_size, GFP_KERNEL);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, alloc_size);
+
+	if (sizeof_priv)
+		dev->priv = (void *) (((unsigned long)(dev + 1) + 31) & ~31);
+	dev->name[0] = '\0';
+	ether_setup(dev);
+
+	return dev;
+}
+
+int
+_kc_is_valid_ether_addr(u8 *addr)
+{
+	const char zaddr[6] = { 0, };
+
+	return !(addr[0] & 1) && memcmp(addr, zaddr, 6);
+}
+
+#endif /* 2.4.3 => 2.4.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) )
+
+int
+_kc_pci_set_power_state(struct pci_dev *dev, int state)
+{
+	return 0;
+}
+
+int
+_kc_pci_save_state(struct pci_dev *dev, u32 *buffer)
+{
+	return 0;
+}
+
+int
+_kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer)
+{
+	return 0;
+}
+
+int
+_kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+{
+	return 0;
+}
+
+#endif /* 2.4.6 => 2.4.3 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
+void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page,
+                            int off, int size)
+{
+	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+	frag->page = page;
+	frag->page_offset = off;
+	frag->size = size;
+	skb_shinfo(skb)->nr_frags = i + 1;
+}
+
+/*
+ * Original Copyright:
+ * find_next_bit.c: fallback find next bit implementation
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+                            unsigned long offset)
+{
+	const unsigned long *p = addr + BITOP_WORD(offset);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset %= BITS_PER_LONG;
+	if (offset) {
+		tmp = *(p++);
+		tmp &= (~0UL << offset);
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+	while (size & ~(BITS_PER_LONG-1)) {
+		if ((tmp = *(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp &= (~0UL >> (BITS_PER_LONG - size));
+	if (tmp == 0UL)		/* Are any bits set? */
+		return result + size;	/* Nope. */
+found_middle:
+	return result + ffs(tmp);
+}
+
+#endif /* 2.6.0 => 2.4.6 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) )
+void *_kc_kzalloc(size_t size, int flags)
+{
+	void *ret = kmalloc(size, flags);
+	if (ret)
+		memset(ret, 0, size);
+	return ret;
+}
+#endif /* <= 2.6.13 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) )
+struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev,
+                                     unsigned int length)
+{
+	/* 16 == NET_PAD_SKB */
+	struct sk_buff *skb;
+	skb = alloc_skb(length + 16, GFP_ATOMIC);
+	if (likely(skb != NULL)) {
+		skb_reserve(skb, 16);
+		skb->dev = dev;
+	}
+	return skb;
+}
+#endif /* <= 2.6.17 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) )
+#endif /* < 2.6.23 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) )
+#ifdef NAPI
+int __kc_adapter_clean(struct net_device *netdev, int *budget)
+{
+	int work_done;
+	int work_to_do = min(*budget, netdev->quota);
+	struct adapter_struct *adapter = netdev_priv(netdev);
+#ifdef DRIVER_E1000E
+	struct napi_struct *napi = &adapter->napi;
+#else
+	struct napi_struct *napi = &adapter->rx_ring[0].napi;
+#endif
+
+	work_done = napi->poll(napi, work_to_do);
+	*budget -= work_done;
+	netdev->quota -= work_done;
+	return work_done ? 1 : 0;
+}
+#endif /* NAPI */
+#endif /* <= 2.6.24 */
+
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/kcompat_ethtool.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/kcompat_ethtool.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/kcompat_ethtool.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/kcompat_ethtool.c	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,1169 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * net/core/ethtool.c - Ethtool ioctl handler
+ * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
+ *
+ * This file is where we call all the ethtool_ops commands to get
+ * the information ethtool needs.  We fall back to calling do_ioctl()
+ * for drivers which haven't been converted to ethtool_ops yet.
+ *
+ * It's GPL, stupid.
+ *
+ * Modification by sfeldma@pobox.com to work as backward compat
+ * solution for pre-ethtool_ops kernels.
+ * 	- copied struct ethtool_ops from ethtool.h
+ * 	- defined SET_ETHTOOL_OPS
+ * 	- put in some #ifndef NETIF_F_xxx wrappers
+ * 	- changes refs to dev->ethtool_ops to ethtool_ops
+ * 	- changed dev_ethtool to ethtool_ioctl
+ *      - remove EXPORT_SYMBOL()s
+ *      - added _kc_ prefix in built-in ethtool_op_xxx ops.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <asm/uaccess.h>
+
+#include "kcompat.h"
+
+#undef SUPPORTED_10000baseT_Full
+#define SUPPORTED_10000baseT_Full	(1 << 12)
+#undef ADVERTISED_10000baseT_Full
+#define ADVERTISED_10000baseT_Full	(1 << 12)
+#undef SPEED_10000
+#define SPEED_10000		10000
+
+#undef ethtool_ops
+#define ethtool_ops _kc_ethtool_ops
+
+struct _kc_ethtool_ops {
+	int  (*get_settings)(struct net_device *, struct ethtool_cmd *);
+	int  (*set_settings)(struct net_device *, struct ethtool_cmd *);
+	void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
+	int  (*get_regs_len)(struct net_device *);
+	void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
+	void (*get_wol)(struct net_device *, struct ethtool_wolinfo *);
+	int  (*set_wol)(struct net_device *, struct ethtool_wolinfo *);
+	u32  (*get_msglevel)(struct net_device *);
+	void (*set_msglevel)(struct net_device *, u32);
+	int  (*nway_reset)(struct net_device *);
+	u32  (*get_link)(struct net_device *);
+	int  (*get_eeprom_len)(struct net_device *);
+	int  (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+	int  (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+	int  (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
+	int  (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
+	void (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
+	int  (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
+	void (*get_pauseparam)(struct net_device *,
+	                       struct ethtool_pauseparam*);
+	int  (*set_pauseparam)(struct net_device *,
+	                       struct ethtool_pauseparam*);
+	u32  (*get_rx_csum)(struct net_device *);
+	int  (*set_rx_csum)(struct net_device *, u32);
+	u32  (*get_tx_csum)(struct net_device *);
+	int  (*set_tx_csum)(struct net_device *, u32);
+	u32  (*get_sg)(struct net_device *);
+	int  (*set_sg)(struct net_device *, u32);
+	u32  (*get_tso)(struct net_device *);
+	int  (*set_tso)(struct net_device *, u32);
+	int  (*self_test_count)(struct net_device *);
+	void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
+	void (*get_strings)(struct net_device *, u32 stringset, u8 *);
+	int  (*phys_id)(struct net_device *, u32);
+	int  (*get_stats_count)(struct net_device *);
+	void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *,
+	                          u64 *);
+} *ethtool_ops = NULL;
+
+#undef SET_ETHTOOL_OPS
+#define SET_ETHTOOL_OPS(netdev, ops) (ethtool_ops = (ops))
+
+/*
+ * Some useful ethtool_ops methods that are device independent. If we find that
+ * all drivers want to do the same thing here, we can turn these into dev_()
+ * function calls.
+ */
+
+#undef ethtool_op_get_link
+#define ethtool_op_get_link _kc_ethtool_op_get_link
+u32 _kc_ethtool_op_get_link(struct net_device *dev)
+{
+	return netif_carrier_ok(dev) ? 1 : 0;
+}
+
+#undef ethtool_op_get_tx_csum
+#define ethtool_op_get_tx_csum _kc_ethtool_op_get_tx_csum
+u32 _kc_ethtool_op_get_tx_csum(struct net_device *dev)
+{
+#ifdef NETIF_F_IP_CSUM
+	return (dev->features & NETIF_F_IP_CSUM) != 0;
+#else
+	return 0;
+#endif
+}
+
+#undef ethtool_op_set_tx_csum
+#define ethtool_op_set_tx_csum _kc_ethtool_op_set_tx_csum
+int _kc_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+{
+#ifdef NETIF_F_IP_CSUM
+	if (data)
+#ifdef NETIF_F_IPV6_CSUM
+		dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+	else
+		dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+#else
+		dev->features |= NETIF_F_IP_CSUM;
+	else
+		dev->features &= ~NETIF_F_IP_CSUM;
+#endif
+#endif
+
+	return 0;
+}
+
+#undef ethtool_op_get_sg
+#define ethtool_op_get_sg _kc_ethtool_op_get_sg
+u32 _kc_ethtool_op_get_sg(struct net_device *dev)
+{
+#ifdef NETIF_F_SG
+	return (dev->features & NETIF_F_SG) != 0;
+#else
+	return 0;
+#endif
+}
+
+#undef ethtool_op_set_sg
+#define ethtool_op_set_sg _kc_ethtool_op_set_sg
+int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data)
+{
+#ifdef NETIF_F_SG
+	if (data)
+		dev->features |= NETIF_F_SG;
+	else
+		dev->features &= ~NETIF_F_SG;
+#endif
+
+	return 0;
+}
+
+#undef ethtool_op_get_tso
+#define ethtool_op_get_tso _kc_ethtool_op_get_tso
+u32 _kc_ethtool_op_get_tso(struct net_device *dev)
+{
+#ifdef NETIF_F_TSO
+	return (dev->features & NETIF_F_TSO) != 0;
+#else
+	return 0;
+#endif
+}
+
+#undef ethtool_op_set_tso
+#define ethtool_op_set_tso _kc_ethtool_op_set_tso
+int _kc_ethtool_op_set_tso(struct net_device *dev, u32 data)
+{
+#ifdef NETIF_F_TSO
+	if (data)
+		dev->features |= NETIF_F_TSO;
+	else
+		dev->features &= ~NETIF_F_TSO;
+#endif
+
+	return 0;
+}
+
+/* Handlers for each ethtool command */
+
+static int ethtool_get_settings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd cmd = { ETHTOOL_GSET };
+	int err;
+
+	if (!ethtool_ops->get_settings)
+		return -EOPNOTSUPP;
+
+	err = ethtool_ops->get_settings(dev, &cmd);
+	if (err < 0)
+		return err;
+
+	if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_settings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd cmd;
+
+	if (!ethtool_ops->set_settings)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+		return -EFAULT;
+
+	return ethtool_ops->set_settings(dev, &cmd);
+}
+
+static int ethtool_get_drvinfo(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_drvinfo info;
+	struct ethtool_ops *ops = ethtool_ops;
+
+	if (!ops->get_drvinfo)
+		return -EOPNOTSUPP;
+
+	memset(&info, 0, sizeof(info));
+	info.cmd = ETHTOOL_GDRVINFO;
+	ops->get_drvinfo(dev, &info);
+
+	if (ops->self_test_count)
+		info.testinfo_len = ops->self_test_count(dev);
+	if (ops->get_stats_count)
+		info.n_stats = ops->get_stats_count(dev);
+	if (ops->get_regs_len)
+		info.regdump_len = ops->get_regs_len(dev);
+	if (ops->get_eeprom_len)
+		info.eedump_len = ops->get_eeprom_len(dev);
+
+	if (copy_to_user(useraddr, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_get_regs(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_regs regs;
+	struct ethtool_ops *ops = ethtool_ops;
+	void *regbuf;
+	int reglen, ret;
+
+	if (!ops->get_regs || !ops->get_regs_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&regs, useraddr, sizeof(regs)))
+		return -EFAULT;
+
+	reglen = ops->get_regs_len(dev);
+	if (regs.len > reglen)
+		regs.len = reglen;
+
+	regbuf = kmalloc(reglen, GFP_USER);
+	if (!regbuf)
+		return -ENOMEM;
+
+	ops->get_regs(dev, &regs, regbuf);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &regs, sizeof(regs)))
+		goto out;
+	useraddr += offsetof(struct ethtool_regs, data);
+	if (copy_to_user(useraddr, regbuf, reglen))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(regbuf);
+	return ret;
+}
+
+static int ethtool_get_wol(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+
+	if (!ethtool_ops->get_wol)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_wol(dev, &wol);
+
+	if (copy_to_user(useraddr, &wol, sizeof(wol)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_wol(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_wolinfo wol;
+
+	if (!ethtool_ops->set_wol)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&wol, useraddr, sizeof(wol)))
+		return -EFAULT;
+
+	return ethtool_ops->set_wol(dev, &wol);
+}
+
+static int ethtool_get_msglevel(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+
+	if (!ethtool_ops->get_msglevel)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_msglevel(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_msglevel(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_msglevel)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	ethtool_ops->set_msglevel(dev, edata.data);
+	return 0;
+}
+
+static int ethtool_nway_reset(struct net_device *dev)
+{
+	if (!ethtool_ops->nway_reset)
+		return -EOPNOTSUPP;
+
+	return ethtool_ops->nway_reset(dev);
+}
+
+static int ethtool_get_link(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GLINK };
+
+	if (!ethtool_ops->get_link)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_link(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_get_eeprom(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_eeprom eeprom;
+	struct ethtool_ops *ops = ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->get_eeprom || !ops->get_eeprom_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+		return -EFAULT;
+
+	/* Check for wrap and zero */
+	if (eeprom.offset + eeprom.len <= eeprom.offset)
+		return -EINVAL;
+
+	/* Check for exceeding total eeprom len */
+	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
+		return -EINVAL;
+
+	data = kmalloc(eeprom.len, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
+		goto out;
+
+	ret = ops->get_eeprom(dev, &eeprom, data);
+	if (ret)
+		goto out;
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
+		goto out;
+	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_set_eeprom(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_eeprom eeprom;
+	struct ethtool_ops *ops = ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->set_eeprom || !ops->get_eeprom_len)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+		return -EFAULT;
+
+	/* Check for wrap and zero */
+	if (eeprom.offset + eeprom.len <= eeprom.offset)
+		return -EINVAL;
+
+	/* Check for exceeding total eeprom len */
+	if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev))
+		return -EINVAL;
+
+	data = kmalloc(eeprom.len, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len))
+		goto out;
+
+	ret = ops->set_eeprom(dev, &eeprom, data);
+	if (ret)
+		goto out;
+
+	if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len))
+		ret = -EFAULT;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_get_coalesce(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
+
+	if (!ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_coalesce(dev, &coalesce);
+
+	if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_coalesce(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_coalesce coalesce;
+
+	if (!ethtool_ops->get_coalesce)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&coalesce, useraddr, sizeof(coalesce)))
+		return -EFAULT;
+
+	return ethtool_ops->set_coalesce(dev, &coalesce);
+}
+
+static int ethtool_get_ringparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
+
+	if (!ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_ringparam(dev, &ringparam);
+
+	if (copy_to_user(useraddr, &ringparam, sizeof(ringparam)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_ringparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_ringparam ringparam;
+
+	if (!ethtool_ops->get_ringparam)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
+		return -EFAULT;
+
+	return ethtool_ops->set_ringparam(dev, &ringparam);
+}
+
+static int ethtool_get_pauseparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM };
+
+	if (!ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+
+	ethtool_ops->get_pauseparam(dev, &pauseparam);
+
+	if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_pauseparam(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_pauseparam pauseparam;
+
+	if (!ethtool_ops->get_pauseparam)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam)))
+		return -EFAULT;
+
+	return ethtool_ops->set_pauseparam(dev, &pauseparam);
+}
+
+static int ethtool_get_rx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GRXCSUM };
+
+	if (!ethtool_ops->get_rx_csum)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_rx_csum(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_rx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_rx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	ethtool_ops->set_rx_csum(dev, edata.data);
+	return 0;
+}
+
+static int ethtool_get_tx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GTXCSUM };
+
+	if (!ethtool_ops->get_tx_csum)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_tx_csum(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_tx_csum(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_tx_csum)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return ethtool_ops->set_tx_csum(dev, edata.data);
+}
+
+static int ethtool_get_sg(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GSG };
+
+	if (!ethtool_ops->get_sg)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_sg(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_sg(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_sg)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return ethtool_ops->set_sg(dev, edata.data);
+}
+
+static int ethtool_get_tso(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GTSO };
+
+	if (!ethtool_ops->get_tso)
+		return -EOPNOTSUPP;
+
+	edata.data = ethtool_ops->get_tso(dev);
+
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_tso(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (!ethtool_ops->set_tso)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return ethtool_ops->set_tso(dev, edata.data);
+}
+
+static int ethtool_self_test(struct net_device *dev, char *useraddr)
+{
+	struct ethtool_test test;
+	struct ethtool_ops *ops = ethtool_ops;
+	u64 *data;
+	int ret;
+
+	if (!ops->self_test || !ops->self_test_count)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&test, useraddr, sizeof(test)))
+		return -EFAULT;
+
+	test.len = ops->self_test_count(dev);
+	data = kmalloc(test.len * sizeof(u64), GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->self_test(dev, &test, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &test, sizeof(test)))
+		goto out;
+	useraddr += sizeof(test);
+	if (copy_to_user(useraddr, data, test.len * sizeof(u64)))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_get_strings(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_gstrings gstrings;
+	struct ethtool_ops *ops = ethtool_ops;
+	u8 *data;
+	int ret;
+
+	if (!ops->get_strings)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
+		return -EFAULT;
+
+	switch (gstrings.string_set) {
+	case ETH_SS_TEST:
+		if (!ops->self_test_count)
+			return -EOPNOTSUPP;
+		gstrings.len = ops->self_test_count(dev);
+		break;
+	case ETH_SS_STATS:
+		if (!ops->get_stats_count)
+			return -EOPNOTSUPP;
+		gstrings.len = ops->get_stats_count(dev);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->get_strings(dev, gstrings.string_set, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
+		goto out;
+	useraddr += sizeof(gstrings);
+	if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+static int ethtool_phys_id(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_value id;
+
+	if (!ethtool_ops->phys_id)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&id, useraddr, sizeof(id)))
+		return -EFAULT;
+
+	return ethtool_ops->phys_id(dev, id.data);
+}
+
+static int ethtool_get_stats(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_stats stats;
+	struct ethtool_ops *ops = ethtool_ops;
+	u64 *data;
+	int ret;
+
+	if (!ops->get_ethtool_stats || !ops->get_stats_count)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&stats, useraddr, sizeof(stats)))
+		return -EFAULT;
+
+	stats.n_stats = ops->get_stats_count(dev);
+	data = kmalloc(stats.n_stats * sizeof(u64), GFP_USER);
+	if (!data)
+		return -ENOMEM;
+
+	ops->get_ethtool_stats(dev, &stats, data);
+
+	ret = -EFAULT;
+	if (copy_to_user(useraddr, &stats, sizeof(stats)))
+		goto out;
+	useraddr += sizeof(stats);
+	if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64)))
+		goto out;
+	ret = 0;
+
+out:
+	kfree(data);
+	return ret;
+}
+
+/* The main entry point in this file.  Called from net/core/dev.c */
+
+#define ETHTOOL_OPS_COMPAT
+int ethtool_ioctl(struct ifreq *ifr)
+{
+	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
+	void *useraddr = (void *) ifr->ifr_data;
+	u32 ethcmd;
+
+	/*
+	 * XXX: This can be pushed down into the ethtool_* handlers that
+	 * need it.  Keep existing behavior for the moment.
+	 */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (!dev || !netif_device_present(dev))
+		return -ENODEV;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GSET:
+		return ethtool_get_settings(dev, useraddr);
+	case ETHTOOL_SSET:
+		return ethtool_set_settings(dev, useraddr);
+	case ETHTOOL_GDRVINFO:
+		return ethtool_get_drvinfo(dev, useraddr);
+	case ETHTOOL_GREGS:
+		return ethtool_get_regs(dev, useraddr);
+	case ETHTOOL_GWOL:
+		return ethtool_get_wol(dev, useraddr);
+	case ETHTOOL_SWOL:
+		return ethtool_set_wol(dev, useraddr);
+	case ETHTOOL_GMSGLVL:
+		return ethtool_get_msglevel(dev, useraddr);
+	case ETHTOOL_SMSGLVL:
+		return ethtool_set_msglevel(dev, useraddr);
+	case ETHTOOL_NWAY_RST:
+		return ethtool_nway_reset(dev);
+	case ETHTOOL_GLINK:
+		return ethtool_get_link(dev, useraddr);
+	case ETHTOOL_GEEPROM:
+		return ethtool_get_eeprom(dev, useraddr);
+	case ETHTOOL_SEEPROM:
+		return ethtool_set_eeprom(dev, useraddr);
+	case ETHTOOL_GCOALESCE:
+		return ethtool_get_coalesce(dev, useraddr);
+	case ETHTOOL_SCOALESCE:
+		return ethtool_set_coalesce(dev, useraddr);
+	case ETHTOOL_GRINGPARAM:
+		return ethtool_get_ringparam(dev, useraddr);
+	case ETHTOOL_SRINGPARAM:
+		return ethtool_set_ringparam(dev, useraddr);
+	case ETHTOOL_GPAUSEPARAM:
+		return ethtool_get_pauseparam(dev, useraddr);
+	case ETHTOOL_SPAUSEPARAM:
+		return ethtool_set_pauseparam(dev, useraddr);
+	case ETHTOOL_GRXCSUM:
+		return ethtool_get_rx_csum(dev, useraddr);
+	case ETHTOOL_SRXCSUM:
+		return ethtool_set_rx_csum(dev, useraddr);
+	case ETHTOOL_GTXCSUM:
+		return ethtool_get_tx_csum(dev, useraddr);
+	case ETHTOOL_STXCSUM:
+		return ethtool_set_tx_csum(dev, useraddr);
+	case ETHTOOL_GSG:
+		return ethtool_get_sg(dev, useraddr);
+	case ETHTOOL_SSG:
+		return ethtool_set_sg(dev, useraddr);
+	case ETHTOOL_GTSO:
+		return ethtool_get_tso(dev, useraddr);
+	case ETHTOOL_STSO:
+		return ethtool_set_tso(dev, useraddr);
+	case ETHTOOL_TEST:
+		return ethtool_self_test(dev, useraddr);
+	case ETHTOOL_GSTRINGS:
+		return ethtool_get_strings(dev, useraddr);
+	case ETHTOOL_PHYS_ID:
+		return ethtool_phys_id(dev, useraddr);
+	case ETHTOOL_GSTATS:
+		return ethtool_get_stats(dev, useraddr);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+#define mii_if_info _kc_mii_if_info
+struct _kc_mii_if_info {
+	int phy_id;
+	int advertising;
+	int phy_id_mask;
+	int reg_num_mask;
+
+	unsigned int full_duplex : 1;	/* is full duplex? */
+	unsigned int force_media : 1;	/* is autoneg. disabled? */
+
+	struct net_device *dev;
+	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
+	void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
+};
+
+struct ethtool_cmd;
+struct mii_ioctl_data;
+
+#undef mii_link_ok
+#define mii_link_ok _kc_mii_link_ok
+#undef mii_nway_restart
+#define mii_nway_restart _kc_mii_nway_restart
+#undef mii_ethtool_gset
+#define mii_ethtool_gset _kc_mii_ethtool_gset
+#undef mii_ethtool_sset
+#define mii_ethtool_sset _kc_mii_ethtool_sset
+#undef mii_check_link
+#define mii_check_link _kc_mii_check_link
+#undef generic_mii_ioctl
+#define generic_mii_ioctl _kc_generic_mii_ioctl
+extern int _kc_mii_link_ok (struct mii_if_info *mii);
+extern int _kc_mii_nway_restart (struct mii_if_info *mii);
+extern int _kc_mii_ethtool_gset(struct mii_if_info *mii,
+                                struct ethtool_cmd *ecmd);
+extern int _kc_mii_ethtool_sset(struct mii_if_info *mii,
+                                struct ethtool_cmd *ecmd);
+extern void _kc_mii_check_link (struct mii_if_info *mii);
+extern int _kc_generic_mii_ioctl(struct mii_if_info *mii_if,
+                                 struct mii_ioctl_data *mii_data, int cmd,
+                                 unsigned int *duplex_changed);
+
+
+struct _kc_pci_dev_ext {
+	struct pci_dev *dev;
+	void *pci_drvdata;
+	struct pci_driver *driver;
+};
+
+struct _kc_net_dev_ext {
+	struct net_device *dev;
+	unsigned int carrier;
+};
+
+
+/**************************************/
+/* mii support */
+
+int _kc_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+{
+	struct net_device *dev = mii->dev;
+	u32 advert, bmcr, lpa, nego;
+
+	ecmd->supported =
+	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
+
+	/* only supports twisted-pair */
+	ecmd->port = PORT_MII;
+
+	/* only supports internal transceiver */
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	/* this isn't fully supported at higher layers */
+	ecmd->phy_address = mii->phy_id;
+
+	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+	advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+	if (advert & ADVERTISE_10HALF)
+		ecmd->advertising |= ADVERTISED_10baseT_Half;
+	if (advert & ADVERTISE_10FULL)
+		ecmd->advertising |= ADVERTISED_10baseT_Full;
+	if (advert & ADVERTISE_100HALF)
+		ecmd->advertising |= ADVERTISED_100baseT_Half;
+	if (advert & ADVERTISE_100FULL)
+		ecmd->advertising |= ADVERTISED_100baseT_Full;
+
+	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+	lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
+	if (bmcr & BMCR_ANENABLE) {
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		ecmd->autoneg = AUTONEG_ENABLE;
+		
+		nego = mii_nway_result(advert & lpa);
+		if (nego == LPA_100FULL || nego == LPA_100HALF)
+			ecmd->speed = SPEED_100;
+		else
+			ecmd->speed = SPEED_10;
+		if (nego == LPA_100FULL || nego == LPA_10FULL) {
+			ecmd->duplex = DUPLEX_FULL;
+			mii->full_duplex = 1;
+		} else {
+			ecmd->duplex = DUPLEX_HALF;
+			mii->full_duplex = 0;
+		}
+	} else {
+		ecmd->autoneg = AUTONEG_DISABLE;
+
+		ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
+		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+	}
+
+	/* ignore maxtxpkt, maxrxpkt for now */
+
+	return 0;
+}
+
+int _kc_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
+{
+	struct net_device *dev = mii->dev;
+
+	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+		return -EINVAL;
+	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+		return -EINVAL;
+	if (ecmd->port != PORT_MII)
+		return -EINVAL;
+	if (ecmd->transceiver != XCVR_INTERNAL)
+		return -EINVAL;
+	if (ecmd->phy_address != mii->phy_id)
+		return -EINVAL;
+	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+				  
+	/* ignore supported, maxtxpkt, maxrxpkt */
+	
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		u32 bmcr, advert, tmp;
+
+		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
+					  ADVERTISED_10baseT_Full |
+					  ADVERTISED_100baseT_Half |
+					  ADVERTISED_100baseT_Full)) == 0)
+			return -EINVAL;
+
+		/* advertise only what has been requested */
+		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
+		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+		if (ADVERTISED_10baseT_Half)
+			tmp |= ADVERTISE_10HALF;
+		if (ADVERTISED_10baseT_Full)
+			tmp |= ADVERTISE_10FULL;
+		if (ADVERTISED_100baseT_Half)
+			tmp |= ADVERTISE_100HALF;
+		if (ADVERTISED_100baseT_Full)
+			tmp |= ADVERTISE_100FULL;
+		if (advert != tmp) {
+			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
+			mii->advertising = tmp;
+		}
+		
+		/* turn on autonegotiation, and force a renegotiate */
+		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+
+		mii->force_media = 0;
+	} else {
+		u32 bmcr, tmp;
+
+		/* turn off auto negotiation, set speed and duplexity */
+		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
+		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
+		if (ecmd->speed == SPEED_100)
+			tmp |= BMCR_SPEED100;
+		if (ecmd->duplex == DUPLEX_FULL) {
+			tmp |= BMCR_FULLDPLX;
+			mii->full_duplex = 1;
+		} else
+			mii->full_duplex = 0;
+		if (bmcr != tmp)
+			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
+
+		mii->force_media = 1;
+	}
+	return 0;
+}
+
+int _kc_mii_link_ok (struct mii_if_info *mii)
+{
+	/* first, a dummy read, needed to latch some MII phys */
+	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
+	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
+		return 1;
+	return 0;
+}
+
+int _kc_mii_nway_restart (struct mii_if_info *mii)
+{
+	int bmcr;
+	int r = -EINVAL;
+
+	/* if autoneg is off, it's an error */
+	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
+
+	if (bmcr & BMCR_ANENABLE) {
+		bmcr |= BMCR_ANRESTART;
+		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
+		r = 0;
+	}
+
+	return r;
+}
+
+void _kc_mii_check_link (struct mii_if_info *mii)
+{
+	int cur_link = mii_link_ok(mii);
+	int prev_link = netif_carrier_ok(mii->dev);
+
+	if (cur_link && !prev_link)
+		netif_carrier_on(mii->dev);
+	else if (prev_link && !cur_link)
+		netif_carrier_off(mii->dev);
+}
+
+int _kc_generic_mii_ioctl(struct mii_if_info *mii_if,
+                          struct mii_ioctl_data *mii_data, int cmd,
+                          unsigned int *duplex_chg_out)
+{
+	int rc = 0;
+	unsigned int duplex_changed = 0;
+
+	if (duplex_chg_out)
+		*duplex_chg_out = 0;
+
+	mii_data->phy_id &= mii_if->phy_id_mask;
+	mii_data->reg_num &= mii_if->reg_num_mask;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
+	case SIOCGMIIPHY:
+		mii_data->phy_id = mii_if->phy_id;
+		/* fall through */
+
+	case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */
+	case SIOCGMIIREG:
+		mii_data->val_out =
+			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
+					  mii_data->reg_num);
+		break;
+
+	case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */
+	case SIOCSMIIREG: {
+		u16 val = mii_data->val_in;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (mii_data->phy_id == mii_if->phy_id) {
+			switch(mii_data->reg_num) {
+			case MII_BMCR: {
+				unsigned int new_duplex = 0;
+				if (val & (BMCR_RESET|BMCR_ANENABLE))
+					mii_if->force_media = 0;
+				else
+					mii_if->force_media = 1;
+				if (mii_if->force_media &&
+				    (val & BMCR_FULLDPLX))
+					new_duplex = 1;
+				if (mii_if->full_duplex != new_duplex) {
+					duplex_changed = 1;
+					mii_if->full_duplex = new_duplex;
+				}
+				break;
+			}
+			case MII_ADVERTISE:
+				mii_if->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
+				   mii_data->reg_num, val);
+		break;
+	}
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
+		*duplex_chg_out = 1;
+
+	return rc;
+}
+
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/kcompat.h linux-2.6.24.7-rt20-atom/drivers/net/e1000e/kcompat.h
--- linux-2.6.24.7-rt20/drivers/net/e1000e/kcompat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/kcompat.h	2008-06-23 18:27:33.000000000 +0200
@@ -0,0 +1,1612 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2008 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _KCOMPAT_H_
+#define _KCOMPAT_H_
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/mii.h>
+#include <asm/io.h>
+
+/* NAPI enable/disable flags here */
+
+#ifdef DRIVER_E1000E
+#define CONFIG_E1000E_NAPI
+#define NAPI
+#endif
+
+#ifdef _E1000_H_
+#ifdef CONFIG_E1000_NAPI
+#define NAPI
+#endif
+#ifdef E1000_NAPI
+#undef NAPI
+#define NAPI
+#endif
+#ifdef E1000E_NAPI
+#undef NAPI
+#define NAPI
+#endif
+#ifdef E1000_NO_NAPI
+#undef NAPI
+#endif
+#ifdef E1000E_NO_NAPI
+#undef NAPI
+#endif
+#endif
+
+
+
+
+
+
+#ifdef DRIVER_E1000E
+#define adapter_struct e1000_adapter
+#define CONFIG_E1000E_MSIX
+#endif
+
+
+
+
+/* and finally set defines so that the code sees the changes */
+#ifdef NAPI
+#ifndef CONFIG_E1000_NAPI
+#define CONFIG_E1000_NAPI
+#endif
+#ifndef CONFIG_E1000E_NAPI
+#define CONFIG_E1000E_NAPI
+#endif
+#else
+#undef CONFIG_E1000_NAPI
+#undef CONFIG_E1000E_NAPI
+#undef CONFIG_IXGB_NAPI
+#endif
+
+/* packet split disable/enable */
+#ifdef DISABLE_PACKET_SPLIT
+#undef CONFIG_E1000_DISABLE_PACKET_SPLIT
+#define CONFIG_E1000_DISABLE_PACKET_SPLIT
+#undef CONFIG_IGB_DISABLE_PACKET_SPLIT
+#define CONFIG_IGB_DISABLE_PACKET_SPLIT
+#endif
+
+/* MSI compatibility code for all kernels and drivers */
+#ifdef DISABLE_PCI_MSI
+#undef CONFIG_PCI_MSI
+#endif
+#ifndef CONFIG_PCI_MSI
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) )
+struct msix_entry {
+	u16 vector; /* kernel uses to write allocated vector */
+	u16 entry;  /* driver uses to specify entry, OS writes */
+};
+#endif
+#define pci_enable_msi(a) -ENOTSUPP
+#define pci_disable_msi(a) do {} while (0)
+#define pci_enable_msix(a, b, c) -ENOTSUPP
+#define pci_disable_msix(a) do {} while (0)
+#define msi_remove_pci_irq_vectors(a) do {} while (0)
+#endif /* CONFIG_PCI_MSI */
+#ifdef DISABLE_PM
+#undef CONFIG_PM
+#endif
+
+#ifdef DISABLE_NET_POLL_CONTROLLER
+#undef CONFIG_NET_POLL_CONTROLLER
+#endif
+
+#ifndef PMSG_SUSPEND
+#define PMSG_SUSPEND 3
+#endif
+
+/* generic boolean compatibility */
+#undef TRUE
+#undef FALSE
+#define TRUE true
+#define FALSE false
+#ifdef GCC_VERSION
+#if ( GCC_VERSION < 3000 )
+#define _Bool char
+#endif
+#endif
+#ifndef bool
+#define bool _Bool
+#define true 1
+#define false 0
+#endif
+
+
+#ifndef module_param
+#define module_param(v,t,p) MODULE_PARM(v, "i");
+#endif
+
+#ifndef DMA_64BIT_MASK
+#define DMA_64BIT_MASK  0xffffffffffffffffULL
+#endif
+
+#ifndef DMA_32BIT_MASK
+#define DMA_32BIT_MASK  0x00000000ffffffffULL
+#endif
+
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+
+#ifndef mmiowb
+#ifdef CONFIG_IA64
+#define mmiowb() asm volatile ("mf.a" ::: "memory")
+#else
+#define mmiowb()
+#endif
+#endif
+
+#ifndef IRQ_HANDLED
+#define irqreturn_t void
+#define IRQ_HANDLED
+#define IRQ_NONE
+#endif
+
+#ifndef SET_NETDEV_DEV
+#define SET_NETDEV_DEV(net, pdev)
+#endif
+
+#ifndef HAVE_FREE_NETDEV
+#define free_netdev(x)	kfree(x)
+#endif
+
+#ifdef HAVE_POLL_CONTROLLER
+#define CONFIG_NET_POLL_CONTROLLER
+#endif
+
+#ifndef NETDEV_TX_OK
+#define NETDEV_TX_OK 0
+#endif
+
+#ifndef NETDEV_TX_BUSY
+#define NETDEV_TX_BUSY 1
+#endif
+
+#ifndef NETDEV_TX_LOCKED
+#define NETDEV_TX_LOCKED -1
+#endif
+
+#ifndef SKB_DATAREF_SHIFT
+/* if we do not have the infrastructure to detect if skb_header is cloned
+   just return false in all cases */
+#define skb_header_cloned(x) 0
+#endif
+
+#ifndef NETIF_F_GSO
+#define gso_size tso_size
+#define gso_segs tso_segs
+#endif
+
+#ifndef CHECKSUM_PARTIAL
+#define CHECKSUM_PARTIAL CHECKSUM_HW
+#define CHECKSUM_COMPLETE CHECKSUM_HW
+#endif
+
+#ifndef __read_mostly
+#define __read_mostly
+#endif
+
+#ifndef HAVE_NETIF_MSG
+#define HAVE_NETIF_MSG 1
+enum {
+	NETIF_MSG_DRV		= 0x0001,
+	NETIF_MSG_PROBE		= 0x0002,
+	NETIF_MSG_LINK		= 0x0004,
+	NETIF_MSG_TIMER		= 0x0008,
+	NETIF_MSG_IFDOWN	= 0x0010,
+	NETIF_MSG_IFUP		= 0x0020,
+	NETIF_MSG_RX_ERR	= 0x0040,
+	NETIF_MSG_TX_ERR	= 0x0080,
+	NETIF_MSG_TX_QUEUED	= 0x0100,
+	NETIF_MSG_INTR		= 0x0200,
+	NETIF_MSG_TX_DONE	= 0x0400,
+	NETIF_MSG_RX_STATUS	= 0x0800,
+	NETIF_MSG_PKTDATA	= 0x1000,
+	NETIF_MSG_HW		= 0x2000,
+	NETIF_MSG_WOL		= 0x4000,
+};
+
+#else
+#define NETIF_MSG_HW	0x2000
+#define NETIF_MSG_WOL	0x4000
+#endif /* HAVE_NETIF_MSG */
+
+#ifndef MII_RESV1
+#define MII_RESV1		0x17		/* Reserved...		*/
+#endif
+
+#ifndef unlikely
+#define unlikely(_x) _x
+#define likely(_x) _x
+#endif
+
+#ifndef WARN_ON
+#define WARN_ON(x)
+#endif
+
+#ifndef PCI_DEVICE
+#define PCI_DEVICE(vend,dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+#endif
+
+#ifndef num_online_cpus
+#define num_online_cpus() smp_num_cpus
+#endif
+
+#ifndef _LINUX_RANDOM_H
+#include <linux/random.h>
+#endif
+
+#ifndef DECLARE_BITMAP
+#ifndef BITS_TO_LONGS
+#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#endif
+#define DECLARE_BITMAP(name,bits) long name[BITS_TO_LONGS(bits)]
+#endif
+
+#ifndef VLAN_HLEN
+#define VLAN_HLEN 4
+#endif
+
+#ifndef VLAN_ETH_HLEN
+#define VLAN_ETH_HLEN 18
+#endif
+
+#ifndef VLAN_ETH_FRAME_LEN
+#define VLAN_ETH_FRAME_LEN 1518
+#endif
+
+#ifndef DCA_GET_TAG_TWO_ARGS
+#define dca3_get_tag(a,b) dca_get_tag(b)
+#endif
+
+
+/*****************************************************************************/
+/* Installations with ethtool version without eeprom, adapter id, or statistics
+ * support */
+
+#ifndef ETH_GSTRING_LEN
+#define ETH_GSTRING_LEN 32
+#endif
+
+#ifndef ETHTOOL_GSTATS
+#define ETHTOOL_GSTATS 0x1d
+#undef ethtool_drvinfo
+#define ethtool_drvinfo k_ethtool_drvinfo
+struct k_ethtool_drvinfo {
+	u32 cmd;
+	char driver[32];
+	char version[32];
+	char fw_version[32];
+	char bus_info[32];
+	char reserved1[32];
+	char reserved2[16];
+	u32 n_stats;
+	u32 testinfo_len;
+	u32 eedump_len;
+	u32 regdump_len;
+};
+
+struct ethtool_stats {
+	u32 cmd;
+	u32 n_stats;
+	u64 data[0];
+};
+#endif /* ETHTOOL_GSTATS */
+
+#ifndef ETHTOOL_PHYS_ID
+#define ETHTOOL_PHYS_ID 0x1c
+#endif /* ETHTOOL_PHYS_ID */
+
+#ifndef ETHTOOL_GSTRINGS
+#define ETHTOOL_GSTRINGS 0x1b
+enum ethtool_stringset {
+	ETH_SS_TEST             = 0,
+	ETH_SS_STATS,
+};
+struct ethtool_gstrings {
+	u32 cmd;            /* ETHTOOL_GSTRINGS */
+	u32 string_set;     /* string set id e.c. ETH_SS_TEST, etc*/
+	u32 len;            /* number of strings in the string set */
+	u8 data[0];
+};
+#endif /* ETHTOOL_GSTRINGS */
+
+#ifndef ETHTOOL_TEST
+#define ETHTOOL_TEST 0x1a
+enum ethtool_test_flags {
+	ETH_TEST_FL_OFFLINE	= (1 << 0),
+	ETH_TEST_FL_FAILED	= (1 << 1),
+};
+struct ethtool_test {
+	u32 cmd;
+	u32 flags;
+	u32 reserved;
+	u32 len;
+	u64 data[0];
+};
+#endif /* ETHTOOL_TEST */
+
+#ifndef ETHTOOL_GEEPROM
+#define ETHTOOL_GEEPROM 0xb
+#undef ETHTOOL_GREGS
+struct ethtool_eeprom {
+	u32 cmd;
+	u32 magic;
+	u32 offset;
+	u32 len;
+	u8 data[0];
+};
+
+struct ethtool_value {
+	u32 cmd;
+	u32 data;
+};
+#endif /* ETHTOOL_GEEPROM */
+
+#ifndef ETHTOOL_GLINK
+#define ETHTOOL_GLINK 0xa
+#endif /* ETHTOOL_GLINK */
+
+#ifndef ETHTOOL_GREGS
+#define ETHTOOL_GREGS		0x00000004 /* Get NIC registers */
+#define ethtool_regs _kc_ethtool_regs
+/* for passing big chunks of data */
+struct _kc_ethtool_regs {
+	u32 cmd;
+	u32 version; /* driver-specific, indicates different chips/revs */
+	u32 len; /* bytes */
+	u8 data[0];
+};
+#endif /* ETHTOOL_GREGS */
+
+#ifndef ETHTOOL_GMSGLVL
+#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
+#endif
+#ifndef ETHTOOL_SMSGLVL
+#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level, priv. */
+#endif
+#ifndef ETHTOOL_NWAY_RST
+#define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation, priv */
+#endif
+#ifndef ETHTOOL_GLINK
+#define ETHTOOL_GLINK		0x0000000a /* Get link status */
+#endif
+#ifndef ETHTOOL_GEEPROM
+#define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
+#endif
+#ifndef ETHTOOL_SEEPROM
+#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data */
+#endif
+#ifndef ETHTOOL_GCOALESCE
+#define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
+/* for configuring coalescing parameters of chip */
+#define ethtool_coalesce _kc_ethtool_coalesce
+struct _kc_ethtool_coalesce {
+	u32	cmd;	/* ETHTOOL_{G,S}COALESCE */
+
+	/* How many usecs to delay an RX interrupt after
+	 * a packet arrives.  If 0, only rx_max_coalesced_frames
+	 * is used.
+	 */
+	u32	rx_coalesce_usecs;
+
+	/* How many packets to delay an RX interrupt after
+	 * a packet arrives.  If 0, only rx_coalesce_usecs is
+	 * used.  It is illegal to set both usecs and max frames
+	 * to zero as this would cause RX interrupts to never be
+	 * generated.
+	 */
+	u32	rx_max_coalesced_frames;
+
+	/* Same as above two parameters, except that these values
+	 * apply while an IRQ is being serviced by the host.  Not
+	 * all cards support this feature and the values are ignored
+	 * in that case.
+	 */
+	u32	rx_coalesce_usecs_irq;
+	u32	rx_max_coalesced_frames_irq;
+
+	/* How many usecs to delay a TX interrupt after
+	 * a packet is sent.  If 0, only tx_max_coalesced_frames
+	 * is used.
+	 */
+	u32	tx_coalesce_usecs;
+
+	/* How many packets to delay a TX interrupt after
+	 * a packet is sent.  If 0, only tx_coalesce_usecs is
+	 * used.  It is illegal to set both usecs and max frames
+	 * to zero as this would cause TX interrupts to never be
+	 * generated.
+	 */
+	u32	tx_max_coalesced_frames;
+
+	/* Same as above two parameters, except that these values
+	 * apply while an IRQ is being serviced by the host.  Not
+	 * all cards support this feature and the values are ignored
+	 * in that case.
+	 */
+	u32	tx_coalesce_usecs_irq;
+	u32	tx_max_coalesced_frames_irq;
+
+	/* How many usecs to delay in-memory statistics
+	 * block updates.  Some drivers do not have an in-memory
+	 * statistic block, and in such cases this value is ignored.
+	 * This value must not be zero.
+	 */
+	u32	stats_block_coalesce_usecs;
+
+	/* Adaptive RX/TX coalescing is an algorithm implemented by
+	 * some drivers to improve latency under low packet rates and
+	 * improve throughput under high packet rates.  Some drivers
+	 * only implement one of RX or TX adaptive coalescing.  Anything
+	 * not implemented by the driver causes these values to be
+	 * silently ignored.
+	 */
+	u32	use_adaptive_rx_coalesce;
+	u32	use_adaptive_tx_coalesce;
+
+	/* When the packet rate (measured in packets per second)
+	 * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+	 * used.
+	 */
+	u32	pkt_rate_low;
+	u32	rx_coalesce_usecs_low;
+	u32	rx_max_coalesced_frames_low;
+	u32	tx_coalesce_usecs_low;
+	u32	tx_max_coalesced_frames_low;
+
+	/* When the packet rate is below pkt_rate_high but above
+	 * pkt_rate_low (both measured in packets per second) the
+	 * normal {rx,tx}_* coalescing parameters are used.
+	 */
+
+	/* When the packet rate is (measured in packets per second)
+	 * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+	 * used.
+	 */
+	u32	pkt_rate_high;
+	u32	rx_coalesce_usecs_high;
+	u32	rx_max_coalesced_frames_high;
+	u32	tx_coalesce_usecs_high;
+	u32	tx_max_coalesced_frames_high;
+
+	/* How often to do adaptive coalescing packet rate sampling,
+	 * measured in seconds.  Must not be zero.
+	 */
+	u32	rate_sample_interval;
+};
+#endif /* ETHTOOL_GCOALESCE */
+
+#ifndef ETHTOOL_SCOALESCE
+#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config. */
+#endif
+#ifndef ETHTOOL_GRINGPARAM
+#define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
+/* for configuring RX/TX ring parameters */
+#define ethtool_ringparam _kc_ethtool_ringparam
+struct _kc_ethtool_ringparam {
+	u32	cmd;	/* ETHTOOL_{G,S}RINGPARAM */
+
+	/* Read only attributes.  These indicate the maximum number
+	 * of pending RX/TX ring entries the driver will allow the
+	 * user to set.
+	 */
+	u32	rx_max_pending;
+	u32	rx_mini_max_pending;
+	u32	rx_jumbo_max_pending;
+	u32	tx_max_pending;
+
+	/* Values changeable by the user.  The valid values are
+	 * in the range 1 to the "*_max_pending" counterpart above.
+	 */
+	u32	rx_pending;
+	u32	rx_mini_pending;
+	u32	rx_jumbo_pending;
+	u32	tx_pending;
+};
+#endif /* ETHTOOL_GRINGPARAM */
+
+#ifndef ETHTOOL_SRINGPARAM
+#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters, priv. */
+#endif
+#ifndef ETHTOOL_GPAUSEPARAM
+#define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
+/* for configuring link flow control parameters */
+#define ethtool_pauseparam _kc_ethtool_pauseparam
+struct _kc_ethtool_pauseparam {
+	u32	cmd;	/* ETHTOOL_{G,S}PAUSEPARAM */
+
+	/* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+	 * being true) the user may set 'autoneg' here non-zero to have the
+	 * pause parameters be auto-negotiated too.  In such a case, the
+	 * {rx,tx}_pause values below determine what capabilities are
+	 * advertised.
+	 *
+	 * If 'autoneg' is zero or the link is not being auto-negotiated,
+	 * then {rx,tx}_pause force the driver to use/not-use pause
+	 * flow control.
+	 */
+	u32	autoneg;
+	u32	rx_pause;
+	u32	tx_pause;
+};
+#endif /* ETHTOOL_GPAUSEPARAM */
+
+#ifndef ETHTOOL_SPAUSEPARAM
+#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters. */
+#endif
+#ifndef ETHTOOL_GRXCSUM
+#define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_SRXCSUM
+#define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_GTXCSUM
+#define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_STXCSUM
+#define ETHTOOL_STXCSUM		0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_GSG
+#define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
+					    * (ethtool_value) */
+#endif
+#ifndef ETHTOOL_SSG
+#define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
+					    * (ethtool_value). */
+#endif
+#ifndef ETHTOOL_TEST
+#define ETHTOOL_TEST		0x0000001a /* execute NIC self-test, priv. */
+#endif
+#ifndef ETHTOOL_GSTRINGS
+#define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
+#endif
+#ifndef ETHTOOL_PHYS_ID
+#define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
+#endif
+#ifndef ETHTOOL_GSTATS
+#define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
+#endif
+#ifndef ETHTOOL_GTSO
+#define ETHTOOL_GTSO		0x0000001e /* Get TSO enable (ethtool_value) */
+#endif
+#ifndef ETHTOOL_STSO
+#define ETHTOOL_STSO		0x0000001f /* Set TSO enable (ethtool_value) */
+#endif
+
+#ifndef ETHTOOL_BUSINFO_LEN
+#define ETHTOOL_BUSINFO_LEN	32
+#endif
+
+/*****************************************************************************/
+/* 2.4.3 => 2.4.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) )
+
+/**************************************/
+/* PCI DRIVER API */
+
+#ifndef pci_set_dma_mask
+#define pci_set_dma_mask _kc_pci_set_dma_mask
+extern int _kc_pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask);
+#endif
+
+#ifndef pci_request_regions
+#define pci_request_regions _kc_pci_request_regions
+extern int _kc_pci_request_regions(struct pci_dev *pdev, char *res_name);
+#endif
+
+#ifndef pci_release_regions
+#define pci_release_regions _kc_pci_release_regions
+extern void _kc_pci_release_regions(struct pci_dev *pdev);
+#endif
+
+/**************************************/
+/* NETWORK DRIVER API */
+
+#ifndef alloc_etherdev
+#define alloc_etherdev _kc_alloc_etherdev
+extern struct net_device * _kc_alloc_etherdev(int sizeof_priv);
+#endif
+
+#ifndef is_valid_ether_addr
+#define is_valid_ether_addr _kc_is_valid_ether_addr
+extern int _kc_is_valid_ether_addr(u8 *addr);
+#endif
+
+/**************************************/
+/* MISCELLANEOUS */
+
+#ifndef INIT_TQUEUE
+#define INIT_TQUEUE(_tq, _routine, _data)		\
+	do {						\
+		INIT_LIST_HEAD(&(_tq)->list);		\
+		(_tq)->sync = 0;			\
+		(_tq)->routine = _routine;		\
+		(_tq)->data = _data;			\
+	} while (0)
+#endif
+
+#endif /* 2.4.3 => 2.4.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5) )
+/* Generic MII registers. */
+#define MII_BMCR            0x00        /* Basic mode control register */
+#define MII_BMSR            0x01        /* Basic mode status register  */
+#define MII_PHYSID1         0x02        /* PHYS ID 1                   */
+#define MII_PHYSID2         0x03        /* PHYS ID 2                   */
+#define MII_ADVERTISE       0x04        /* Advertisement control reg   */
+#define MII_LPA             0x05        /* Link partner ability reg    */
+#define MII_EXPANSION       0x06        /* Expansion register          */
+/* Basic mode control register. */
+#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
+#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+/* Advertisement control register. */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+/* Expansion register for auto-negotiation. */
+#define EXPANSION_ENABLENPAGE   0x0004  /* This enables npage words    */
+#endif
+
+/*****************************************************************************/
+/* 2.4.6 => 2.4.3 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) )
+
+#ifndef pci_set_power_state
+#define pci_set_power_state _kc_pci_set_power_state
+extern int _kc_pci_set_power_state(struct pci_dev *dev, int state);
+#endif
+
+#ifndef pci_save_state
+#define pci_save_state _kc_pci_save_state
+extern int _kc_pci_save_state(struct pci_dev *dev, u32 *buffer);
+#endif
+
+#ifndef pci_restore_state
+#define pci_restore_state _kc_pci_restore_state
+extern int _kc_pci_restore_state(struct pci_dev *pdev, u32 *buffer);
+#endif
+
+#ifndef pci_enable_wake
+#define pci_enable_wake _kc_pci_enable_wake
+extern int _kc_pci_enable_wake(struct pci_dev *pdev, u32 state, int enable);
+#endif
+
+#ifndef pci_disable_device
+#define pci_disable_device _kc_pci_disable_device
+extern void _kc_pci_disable_device(struct pci_dev *pdev);
+#endif
+
+/* PCI PM entry point syntax changed, so don't support suspend/resume */
+#undef CONFIG_PM
+
+#endif /* 2.4.6 => 2.4.3 */
+
+#ifndef HAVE_PCI_SET_MWI
+#define pci_set_mwi(X) pci_write_config_word(X, \
+			       PCI_COMMAND, adapter->hw.bus.pci_cmd_word | \
+			       PCI_COMMAND_INVALIDATE);
+#define pci_clear_mwi(X) pci_write_config_word(X, \
+			       PCI_COMMAND, adapter->hw.bus.pci_cmd_word & \
+			       ~PCI_COMMAND_INVALIDATE);
+#endif
+
+/*****************************************************************************/
+/* 2.4.10 => 2.4.9 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) )
+
+/**************************************/
+/* MODULE API */
+
+#ifndef MODULE_LICENSE
+	#define MODULE_LICENSE(X)
+#endif
+
+/**************************************/
+/* OTHER */
+
+#undef min
+#define min(x,y) ({ \
+	const typeof(x) _x = (x);	\
+	const typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x < _y ? _x : _y; })
+
+#undef max
+#define max(x,y) ({ \
+	const typeof(x) _x = (x);	\
+	const typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x > _y ? _x : _y; })
+
+#ifndef list_for_each_safe
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+#endif
+
+#endif /* 2.4.10 -> 2.4.6 */
+
+
+/*****************************************************************************/
+/* 2.4.13 => 2.4.10 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) )
+
+/**************************************/
+/* PCI DMA MAPPING */
+
+#ifndef virt_to_page
+	#define virt_to_page(v) (mem_map + (virt_to_phys(v) >> PAGE_SHIFT))
+#endif
+
+#ifndef pci_map_page
+#define pci_map_page _kc_pci_map_page
+extern u64 _kc_pci_map_page(struct pci_dev *dev, struct page *page, unsigned long offset, size_t size, int direction);
+#endif
+
+#ifndef pci_unmap_page
+#define pci_unmap_page _kc_pci_unmap_page
+extern void _kc_pci_unmap_page(struct pci_dev *dev, u64 dma_addr, size_t size, int direction);
+#endif
+
+/* pci_set_dma_mask takes dma_addr_t, which is only 32-bits prior to 2.4.13 */
+
+#undef DMA_32BIT_MASK
+#define DMA_32BIT_MASK	0xffffffff
+#undef DMA_64BIT_MASK
+#define DMA_64BIT_MASK	0xffffffff
+
+/**************************************/
+/* OTHER */
+
+#ifndef cpu_relax
+#define cpu_relax()	rep_nop()
+#endif
+
+#endif /* 2.4.13 => 2.4.10 */
+
+/*****************************************************************************/
+/* 2.4.17 => 2.4.12 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,17) )
+
+#ifndef __devexit_p
+	#define __devexit_p(x) &(x)
+#endif
+
+#endif /* 2.4.17 => 2.4.13 */
+
+/*****************************************************************************/
+/* 2.4.20 => 2.4.19 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) )
+
+/* we won't support NAPI on less than 2.4.20 */
+#ifdef NAPI
+#undef CONFIG_E1000_NAPI
+#undef CONFIG_E1000E_NAPI
+#undef CONFIG_IXGB_NAPI
+#endif
+
+#endif /* 2.4.20 => 2.4.19 */
+/*****************************************************************************/
+/* 2.4.22 => 2.4.17 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) )
+#define pci_name(x)	((x)->slot_name)
+#endif
+
+/*****************************************************************************/
+/* 2.4.22 => 2.4.17 */
+
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,22) )
+#endif
+
+/*****************************************************************************/
+/*****************************************************************************/
+/* 2.4.23 => 2.4.22 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) )
+/*****************************************************************************/
+#ifdef NAPI
+#ifndef netif_poll_disable
+#define netif_poll_disable(x) _kc_netif_poll_disable(x)
+static inline void _kc_netif_poll_disable(struct net_device *netdev)
+{
+	while (test_and_set_bit(__LINK_STATE_RX_SCHED, &netdev->state)) {
+		/* No hurry */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+}
+#endif
+
+#ifndef netif_poll_enable
+#define netif_poll_enable(x) _kc_netif_poll_enable(x)
+static inline void _kc_netif_poll_enable(struct net_device *netdev)
+{
+	clear_bit(__LINK_STATE_RX_SCHED, &netdev->state);
+}
+#endif
+#endif /* NAPI */
+#ifndef netif_tx_disable
+#define netif_tx_disable(x) _kc_netif_tx_disable(x)
+static inline void _kc_netif_tx_disable(struct net_device *dev)
+{
+	spin_lock_bh(&dev->xmit_lock);
+	netif_stop_queue(dev);
+	spin_unlock_bh(&dev->xmit_lock);
+}
+#endif
+#endif /* 2.4.23 => 2.4.22 */
+
+/*****************************************************************************/
+/* 2.6.4 => 2.6.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25) || \
+    ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \
+      LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ) )
+#define ETHTOOL_OPS_COMPAT
+#endif /* 2.6.4 => 2.6.0 */
+
+/*****************************************************************************/
+/* 2.5.71 => 2.4.x */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71) )
+#include <net/sock.h>
+#define sk_protocol protocol
+
+#define pci_get_device pci_find_device
+#endif /* 2.5.70 => 2.4.x */
+
+/*****************************************************************************/
+/* < 2.4.27 or 2.6.0 <= 2.6.5 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) || \
+    ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \
+      LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) ) )
+
+#ifndef netif_msg_init
+#define netif_msg_init _kc_netif_msg_init
+static inline u32 _kc_netif_msg_init(int debug_value, int default_msg_enable_bits)
+{
+	/* use default */
+	if (debug_value < 0 || debug_value >= (sizeof(u32) * 8))
+		return default_msg_enable_bits;
+	if (debug_value == 0) /* no output */
+		return 0;
+	/* set low N bits */
+	return (1 << debug_value) -1;
+}
+#endif
+
+#endif /* < 2.4.27 or 2.6.0 <= 2.6.5 */
+/*****************************************************************************/
+#if (( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27) ) || \
+     (( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) && \
+      ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) )))
+#define netdev_priv(x) x->priv
+#endif
+
+/*****************************************************************************/
+/* <= 2.5.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) )
+#undef pci_register_driver
+#define pci_register_driver pci_module_init
+
+#define dev_err(__unused_dev, format, arg...)            \
+	printk(KERN_ERR "%s: " format, pci_name(adapter->pdev) , ## arg)
+
+/* hlist_* code - double linked lists */
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+	next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	__hlist_del(n);
+	n->next = NULL;
+	n->pprev = NULL;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+	h->next = NULL;
+	h->pprev = NULL;
+}
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each_entry(tpos, pos, head, member)                    \
+	for (pos = (head)->first;                                        \
+	     pos && ({ prefetch(pos->next); 1;}) &&                      \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member)            \
+	for (pos = (head)->first;                                        \
+	     pos && ({ n = pos->next; 1; }) &&                           \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = n)
+
+/* we ignore GFP here */
+#define dma_alloc_coherent(dv, sz, dma, gfp) \
+	pci_alloc_consistent(pdev, (sz), (dma))
+#define dma_free_coherent(dv, sz, addr, dma_addr) \
+	pci_free_consistent(pdev, (sz), (addr), (dma_addr))
+
+#ifndef might_sleep
+#define might_sleep()
+#endif
+
+#endif /* <= 2.5.0 */
+
+/*****************************************************************************/
+/* 2.5.28 => 2.4.23 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28) )
+
+static inline void _kc_synchronize_irq(void)
+{
+	synchronize_irq();
+}
+#undef synchronize_irq
+#define synchronize_irq(X) _kc_synchronize_irq()
+
+#include <linux/tqueue.h>
+#define work_struct tq_struct
+#undef INIT_WORK
+#define INIT_WORK(a,b) INIT_TQUEUE(a,(void (*)(void *))b,a)
+#undef container_of
+#define container_of list_entry
+#define schedule_work schedule_task
+#define flush_scheduled_work flush_scheduled_tasks
+
+#endif /* 2.5.28 => 2.4.17 */
+
+/*****************************************************************************/
+/* 2.6.0 => 2.5.28 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) )
+#define MODULE_INFO(version, _version)
+#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT
+#define CONFIG_E1000_DISABLE_PACKET_SPLIT 1
+#endif
+#ifndef CONFIG_IGB_DISABLE_PACKET_SPLIT
+#define CONFIG_IGB_DISABLE_PACKET_SPLIT 1
+#endif
+
+#define pci_set_consistent_dma_mask(dev,mask) 1
+
+#undef dev_put
+#define dev_put(dev) __dev_put(dev)
+
+#ifndef skb_fill_page_desc
+#define skb_fill_page_desc _kc_skb_fill_page_desc
+extern void _kc_skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size);
+#endif
+
+#ifndef pci_dma_mapping_error
+#define pci_dma_mapping_error _kc_pci_dma_mapping_error
+static inline int _kc_pci_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_addr == 0;
+}
+#endif
+
+#undef ALIGN
+#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
+
+/* find_first_bit and find_next bit are not defined for most
+ * 2.4 kernels (except for the redhat 2.4.21 kernels
+ */
+#include <linux/bitops.h>
+#define BITOP_WORD(nr)          ((nr) / BITS_PER_LONG)
+#undef find_next_bit
+#define find_next_bit _kc_find_next_bit
+extern unsigned long _kc_find_next_bit(const unsigned long *addr,
+                                       unsigned long size,
+                                       unsigned long offset);
+#define find_first_bit(addr, size) find_next_bit((addr), (size), 0)
+
+#endif /* 2.6.0 => 2.5.28 */
+
+/*****************************************************************************/
+/* 2.6.4 => 2.6.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) )
+#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#endif /* 2.6.4 => 2.6.0 */
+
+/*****************************************************************************/
+/* 2.6.5 => 2.6.0 */
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) )
+#define pci_dma_sync_single_for_cpu	pci_dma_sync_single
+#define pci_dma_sync_single_for_device	pci_dma_sync_single_for_cpu
+#endif /* 2.6.5 => 2.6.0 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) )
+/* taken from 2.6 include/linux/bitmap.h */
+#undef bitmap_zero
+#define bitmap_zero _kc_bitmap_zero
+static inline void _kc_bitmap_zero(unsigned long *dst, int nbits)
+{
+        if (nbits <= BITS_PER_LONG)
+                *dst = 0UL;
+        else {
+                int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+                memset(dst, 0, len);
+        }
+}
+#endif /* < 2.6.6 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) )
+#undef if_mii
+#define if_mii _kc_if_mii
+static inline struct mii_ioctl_data *_kc_if_mii(struct ifreq *rq)
+{
+	return (struct mii_ioctl_data *) &rq->ifr_ifru;
+}
+#endif /* < 2.6.7 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) )
+#define msleep(x)	do { set_current_state(TASK_UNINTERRUPTIBLE); \
+				schedule_timeout((x * HZ)/1000 + 2); \
+			} while (0)
+
+#endif /* < 2.6.8 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9))
+#include <net/dsfield.h>
+#define __iomem
+
+#ifndef kcalloc
+#define kcalloc(n, size, flags) _kc_kzalloc(((n) * (size)), flags)
+extern void *_kc_kzalloc(size_t size, int flags);
+#endif
+#define MSEC_PER_SEC    1000L
+static inline unsigned int _kc_jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+	return (MSEC_PER_SEC / HZ) * j;
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+	return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
+#else
+	return (j * MSEC_PER_SEC) / HZ;
+#endif
+}
+static inline unsigned long _kc_msecs_to_jiffies(const unsigned int m)
+{
+	if (m > _kc_jiffies_to_msecs(MAX_JIFFY_OFFSET))
+		return MAX_JIFFY_OFFSET;
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+	return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+	return m * (HZ / MSEC_PER_SEC);
+#else
+	return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
+#endif
+}
+
+#define msleep_interruptible _kc_msleep_interruptible
+static inline unsigned long _kc_msleep_interruptible(unsigned int msecs)
+{
+	unsigned long timeout = _kc_msecs_to_jiffies(msecs) + 1;
+
+	while (timeout && !signal_pending(current)) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+	}
+	return _kc_jiffies_to_msecs(timeout);
+}
+
+/* Basic mode control register. */
+#define BMCR_SPEED1000		0x0040  /* MSB of Speed (1000)         */
+#endif /* < 2.6.9 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,6) && \
+      LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) )
+#ifdef pci_save_state
+#undef pci_save_state
+#endif
+#define pci_save_state(X) { \
+        int i; \
+        if (adapter->pci_state) { \
+                for (i = 0; i < 16; i++) { \
+                        pci_read_config_dword((X), \
+                                              i * 4, \
+                                              &adapter->pci_state[i]); \
+                } \
+        } \
+}
+
+#ifdef pci_restore_state
+#undef pci_restore_state
+#endif
+#define pci_restore_state(X) { \
+        int i; \
+        if (adapter->pci_state) { \
+                for (i = 0; i < 16; i++) { \
+                        pci_write_config_dword((X), \
+                                               i * 4, \
+                                               adapter->pci_state[i]); \
+                } \
+        } else { \
+                for (i = 0; i < 6; i++) { \
+                        pci_write_config_dword((X), \
+                                               PCI_BASE_ADDRESS_0 + (i * 4), \
+                                               (X)->resource[i].start); \
+                } \
+        } \
+}
+#endif /* 2.4.6 <= x < 2.6.10 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) )
+#ifdef module_param_array_named
+#undef module_param_array_named
+#define module_param_array_named(name, array, type, nump, perm)          \
+	static struct kparam_array __param_arr_##name                    \
+	= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type, \
+	    sizeof(array[0]), array };                                   \
+	module_param_call(name, param_array_set, param_array_get,        \
+			  &__param_arr_##name, perm)
+#endif /* module_param_array_named */
+#endif /* < 2.6.10 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
+#define PCI_D0      0
+#define PCI_D1      1
+#define PCI_D2      2
+#define PCI_D3hot   3
+#define PCI_D3cold  4
+#define pci_choose_state(pdev,state) state
+#define PMSG_SUSPEND 3
+
+#undef NETIF_F_LLTX
+
+#ifndef ARCH_HAS_PREFETCH
+#define prefetch(X)
+#endif
+
+#ifndef NET_IP_ALIGN
+#define NET_IP_ALIGN 2
+#endif
+
+#define KC_USEC_PER_SEC	1000000L
+#define usecs_to_jiffies _kc_usecs_to_jiffies
+static inline unsigned int _kc_jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ)
+	return (KC_USEC_PER_SEC / HZ) * j;
+#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC)
+	return (j + (HZ / KC_USEC_PER_SEC) - 1)/(HZ / KC_USEC_PER_SEC);
+#else
+	return (j * KC_USEC_PER_SEC) / HZ;
+#endif
+}
+static inline unsigned long _kc_usecs_to_jiffies(const unsigned int m)
+{
+	if (m > _kc_jiffies_to_usecs(MAX_JIFFY_OFFSET))
+		return MAX_JIFFY_OFFSET;
+#if HZ <= KC_USEC_PER_SEC && !(KC_USEC_PER_SEC % HZ)
+	return (m + (KC_USEC_PER_SEC / HZ) - 1) / (KC_USEC_PER_SEC / HZ);
+#elif HZ > KC_USEC_PER_SEC && !(HZ % KC_USEC_PER_SEC)
+	return m * (HZ / KC_USEC_PER_SEC);
+#else
+	return (m * HZ + KC_USEC_PER_SEC - 1) / KC_USEC_PER_SEC;
+#endif
+}
+#endif /* < 2.6.11 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) )
+#include <linux/reboot.h>
+#define USE_REBOOT_NOTIFIER
+
+/* Generic MII registers. */
+#define MII_CTRL1000        0x09        /* 1000BASE-T control          */
+#define MII_STAT1000        0x0a        /* 1000BASE-T status           */
+/* Advertisement control register. */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymmetric pause     */
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
+#endif
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) )
+#define pm_message_t u32
+#ifndef kzalloc
+#define kzalloc _kc_kzalloc
+extern void *_kc_kzalloc(size_t size, int flags);
+#endif
+
+/* Generic MII registers. */
+#define MII_ESTATUS	    0x0f	/* Extended Status */
+/* Basic mode status register. */
+#define BMSR_ESTATEN		0x0100	/* Extended Status in R15 */
+/* Extended status register. */
+#define ESTATUS_1000_TFULL	0x2000	/* Can do 1000BT Full */
+#define ESTATUS_1000_THALF	0x1000	/* Can do 1000BT Half */
+#endif
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) )
+#undef HAVE_PCI_ERS
+#else /* 2.6.16 and above */
+#undef HAVE_PCI_ERS
+#define HAVE_PCI_ERS
+#endif
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) )
+
+#ifndef IRQF_PROBE_SHARED
+#ifdef SA_PROBEIRQ
+#define IRQF_PROBE_SHARED SA_PROBEIRQ
+#else
+#define IRQF_PROBE_SHARED 0
+#endif
+#endif
+
+#ifndef IRQF_SHARED
+#define IRQF_SHARED SA_SHIRQ
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#ifndef netdev_alloc_skb
+#define netdev_alloc_skb _kc_netdev_alloc_skb
+extern struct sk_buff *_kc_netdev_alloc_skb(struct net_device *dev,
+                                            unsigned int length);
+#endif
+
+#ifndef skb_is_gso
+#ifdef NETIF_F_TSO
+#define skb_is_gso _kc_skb_is_gso
+static inline int _kc_skb_is_gso(const struct sk_buff *skb)
+{
+	return skb_shinfo(skb)->gso_size;
+}
+#else
+#define skb_is_gso(a) 0
+#endif
+#endif
+
+#endif /* < 2.6.18 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) )
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#endif
+
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) )
+#ifndef RHEL_RELEASE_CODE
+#define RHEL_RELEASE_CODE 0
+#endif
+#ifndef RHEL_RELEASE_VERSION
+#define RHEL_RELEASE_VERSION(a,b) 0
+#endif
+#if (!(( RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(4,4) ) && ( RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(5,0) ) || ( RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(5,0) ))) 
+typedef irqreturn_t (*irq_handler_t)(int, void*, struct pt_regs *);
+#endif
+typedef irqreturn_t (*new_handler_t)(int, void*);
+static inline irqreturn_t _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id)
+#else /* 2.4.x */
+typedef void (*irq_handler_t)(int, void*, struct pt_regs *);
+typedef void (*new_handler_t)(int, void*);
+static inline int _kc_request_irq(unsigned int irq, new_handler_t handler, unsigned long flags, const char *devname, void *dev_id)
+#endif
+{
+	irq_handler_t new_handler = (irq_handler_t) handler;
+	return request_irq(irq, new_handler, flags, devname, dev_id);
+}
+
+#undef request_irq
+#define request_irq(irq, handler, flags, devname, dev_id) _kc_request_irq((irq), (handler), (flags), (devname), (dev_id))
+
+#define irq_handler_t new_handler_t
+
+/* pci_restore_state and pci_save_state handles MSI/PCIE from 2.6.19 */
+#define PCIE_CONFIG_SPACE_LEN 256
+#define PCI_CONFIG_SPACE_LEN 64
+#define PCIE_LINK_STATUS 0x12
+#ifdef DRIVER_E1000E
+#define pci_config_space_ich8lan() { \
+	if (adapter->flags & FLAG_IS_ICH) \
+		size = PCIE_CONFIG_SPACE_LEN; \
+}
+#else
+#define pci_config_space_ich8lan()
+#endif
+#undef pci_save_state
+#define pci_save_state(pdev) _kc_pci_save_state(adapter)
+#define _kc_pci_save_state(adapter) 0; { \
+	int size = PCI_CONFIG_SPACE_LEN, i; \
+	u16 pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP); \
+	u16 pcie_link_status; \
+	\
+	if (pcie_cap_offset) { \
+	if (!pci_read_config_word(pdev, pcie_cap_offset + PCIE_LINK_STATUS, \
+				  &pcie_link_status)) \
+		size = PCIE_CONFIG_SPACE_LEN; \
+	} \
+	pci_config_space_ich8lan(); \
+	WARN_ON(adapter->config_space != NULL); \
+	adapter->config_space = kmalloc(size, GFP_KERNEL); \
+	if (!adapter->config_space) { \
+		printk(KERN_ERR "Out of memory in pci_save_state\n"); \
+		return -ENOMEM; \
+	} \
+	for (i = 0; i < (size / 4); i++) \
+		pci_read_config_dword(pdev, i * 4, &adapter->config_space[i]); \
+}
+#undef pci_restore_state
+#define pci_restore_state(pdev) _kc_pci_restore_state(adapter)
+#define _kc_pci_restore_state(adapter) { \
+	int size = PCI_CONFIG_SPACE_LEN, i; \
+	u16 pcie_cap_offset; \
+	u16 pcie_link_status; \
+	\
+	if (adapter->config_space != NULL) { \
+	pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_EXP); \
+	if (pcie_cap_offset) { \
+	if (!pci_read_config_word(pdev, pcie_cap_offset + PCIE_LINK_STATUS, \
+				  &pcie_link_status)) \
+		size = PCIE_CONFIG_SPACE_LEN; \
+	} \
+	pci_config_space_ich8lan(); \
+	for (i = 0; i < (size / 4); i++) \
+		pci_write_config_dword(pdev, i * 4, adapter->config_space[i]); \
+	kfree(adapter->config_space); \
+	adapter->config_space = NULL; \
+	} \
+}
+
+#endif /* < 2.6.19 */
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) )
+#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) )
+#undef INIT_WORK
+#define INIT_WORK(_work, _func) \
+do { \
+	INIT_LIST_HEAD(&(_work)->entry); \
+	(_work)->pending = 0; \
+	(_work)->func = (void (*)(void *))_func; \
+	(_work)->data = _work; \
+	init_timer(&(_work)->timer); \
+} while (0)
+#endif
+
+#ifndef PCI_VDEVICE
+#define PCI_VDEVICE(ven, dev)        \
+	PCI_VENDOR_ID_##ven, (dev),  \
+	PCI_ANY_ID, PCI_ANY_ID, 0, 0
+#endif
+
+#ifndef round_jiffies
+#define round_jiffies(x) x
+#endif
+
+#define csum_offset csum
+
+#endif /* < 2.6.20 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) )
+#define vlan_group_get_device(vg, id) (vg->vlan_devices[id])
+#define vlan_group_set_device(vg, id, dev) if (vg) vg->vlan_devices[id] = dev;
+#define pci_channel_offline(pdev) (pdev->error_state && \
+	pdev->error_state != pci_channel_io_normal)
+#endif /* < 2.6.21 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) )
+#define tcp_hdr(skb) (skb->h.th)
+#define tcp_hdrlen(skb) (skb->h.th->doff << 2)
+#define skb_transport_offset(skb) (skb->h.raw - skb->data)
+#define skb_transport_header(skb) (skb->h.raw)
+#define ipv6_hdr(skb) (skb->nh.ipv6h)
+#define ip_hdr(skb) (skb->nh.iph)
+#define skb_network_offset(skb) (skb->nh.raw - skb->data)
+#define skb_network_header(skb) (skb->nh.raw)
+#define skb_tail_pointer(skb) skb->tail
+#define skb_copy_to_linear_data_offset(skb, offset, from, len) \
+                                 memcpy(skb->data + offset, from, len)
+#define skb_network_header_len(skb) (skb->h.raw - skb->nh.raw)
+#define pci_register_driver pci_module_init
+#define skb_mac_header(skb) skb->mac.raw
+
+#ifdef NETIF_F_MULTI_QUEUE
+#ifndef alloc_etherdev_mq
+#define alloc_etherdev_mq(_a, _b) alloc_etherdev(_a)
+#endif
+#endif /* NETIF_F_MULTI_QUEUE */
+
+#ifndef ETH_FCS_LEN
+#define ETH_FCS_LEN 4
+#endif
+#endif /* < 2.6.22 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) )
+#undef ETHTOOL_GPERMADDR
+#undef SET_MODULE_OWNER
+#define SET_MODULE_OWNER(dev) do { } while (0)
+#endif /* > 2.6.22 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) )
+/* NAPI API changes in 2.6.24 break everything */
+struct napi_struct {
+	/* used to look up the real NAPI polling routine */
+	int (*poll)(struct napi_struct *, int);
+	int weight;
+};
+#ifdef NAPI
+extern int __kc_adapter_clean(struct net_device *, int *);
+#define netif_rx_complete(netdev, napi) netif_rx_complete(netdev)
+#define netif_rx_schedule_prep(netdev, napi) netif_rx_schedule_prep(netdev)
+#define netif_rx_schedule(netdev, napi) netif_rx_schedule(netdev)
+#define __netif_rx_schedule(netdev, napi) __netif_rx_schedule(netdev)
+#define napi_enable(napi) netif_poll_enable(adapter->netdev)
+#define napi_disable(napi) netif_poll_disable(adapter->netdev)
+#define netif_napi_add(_netdev, _napi, _poll, _weight) \
+	do { \
+		struct napi_struct *__napi = _napi; \
+		_netdev->poll = &(__kc_adapter_clean); \
+		_netdev->weight = (_weight); \
+		__napi->poll = &(_poll); \
+		__napi->weight = (_weight); \
+		netif_poll_disable(_netdev); \
+	} while (0)
+#else /* NAPI */
+#define netif_napi_add(_netdev, _napi, _poll, _weight) \
+	do { \
+		struct napi_struct *__napi = _napi; \
+		_netdev->poll = &(_poll); \
+		_netdev->weight = (_weight); \
+		__napi->poll = &(_poll); \
+		__napi->weight = (_weight); \
+	} while (0)
+#endif /* NAPI */
+
+#undef dev_get_by_name
+#define dev_get_by_name(_a, _b) dev_get_by_name(_b)
+#define __netif_subqueue_stopped(_a, _b) netif_subqueue_stopped(_a, _b)
+#endif /* < 2.6.24 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) )
+#include <linux/pm_qos_params.h>
+#endif /* > 2.6.24 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) )
+#define PM_QOS_CPU_DMA_LATENCY	1
+
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) )
+#include <linux/latency.h>
+#define PM_QOS_DEFAULT_VALUE	INFINITE_LATENCY
+#define pm_qos_add_requirement(pm_qos_class, name, value) \
+		set_acceptable_latency(name, value)
+#define pm_qos_remove_requirement(pm_qos_class, name) \
+		remove_acceptable_latency(name)
+#define pm_qos_update_requirement(pm_qos_class, name, value) \
+		modify_acceptable_latency(name, value)
+#else
+#define PM_QOS_DEFAULT_VALUE	-1
+#define pm_qos_add_requirement(pm_qos_class, name, value)
+#define pm_qos_remove_requirement(pm_qos_class, name)
+#define pm_qos_update_requirement(pm_qos_class, name, value) { \
+	if (value != PM_QOS_DEFAULT_VALUE) { \
+		printk(KERN_WARNING "%s: unable to set PM QoS requirement\n", \
+			pci_name(adapter->pdev)); \
+	} \
+}
+#endif /* > 2.6.18 */
+
+#endif /* < 2.6.25 */
+
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) )
+#endif /* < 2.6.26 */
+
+#ifndef NETIF_F_MULTI_QUEUE
+#define NETIF_F_MULTI_QUEUE 0
+#define netif_is_multiqueue(a) 0
+#define netif_stop_subqueue(a, b)
+#define netif_wake_subqueue(a, b)
+#define netif_start_subqueue(a, b)
+#endif /* NETIF_F_MULTI_QUEUE */
+
+#endif /* _KCOMPAT_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/lib.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/lib.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/lib.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/lib.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,2493 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "e1000.h"
-
-enum e1000_mng_mode {
-	e1000_mng_mode_none = 0,
-	e1000_mng_mode_asf,
-	e1000_mng_mode_pt,
-	e1000_mng_mode_ipmi,
-	e1000_mng_mode_host_if_only
-};
-
-#define E1000_FACTPS_MNGCG		0x20000000
-
-#define E1000_IAMT_SIGNATURE		0x544D4149 /* Intel(R) Active Management
-						    * Technology signature */
-
-/**
- *  e1000e_get_bus_info_pcie - Get PCIe bus information
- *  @hw: pointer to the HW structure
- *
- *  Determines and stores the system bus information for a particular
- *  network interface.  The following bus information is determined and stored:
- *  bus speed, bus width, type (PCIe), and PCIe function.
- **/
-s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	struct e1000_adapter *adapter = hw->adapter;
-	u32 status;
-	u16 pcie_link_status, pci_header_type, cap_offset;
-
-	cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
-	if (!cap_offset) {
-		bus->width = e1000_bus_width_unknown;
-	} else {
-		pci_read_config_word(adapter->pdev,
-				     cap_offset + PCIE_LINK_STATUS,
-				     &pcie_link_status);
-		bus->width = (enum e1000_bus_width)((pcie_link_status &
-						     PCIE_LINK_WIDTH_MASK) >>
-						    PCIE_LINK_WIDTH_SHIFT);
-	}
-
-	pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER,
-			     &pci_header_type);
-	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
-		status = er32(STATUS);
-		bus->func = (status & E1000_STATUS_FUNC_MASK)
-			    >> E1000_STATUS_FUNC_SHIFT;
-	} else {
-		bus->func = 0;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_write_vfta - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: register offset in VLAN filter table
- *  @value: register value written to VLAN filter table
- *
- *  Writes value at the given offset in the register array which stores
- *  the VLAN filter table.
- **/
-void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
-	e1e_flush();
-}
-
-/**
- *  e1000e_init_rx_addrs - Initialize receive address's
- *  @hw: pointer to the HW structure
- *  @rar_count: receive address registers
- *
- *  Setups the receive address registers by setting the base receive address
- *  register to the devices MAC address and clearing all the other receive
- *  address registers to 0.
- **/
-void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
-{
-	u32 i;
-
-	/* Setup the receive address */
-	hw_dbg(hw, "Programming MAC Address into RAR[0]\n");
-
-	e1000e_rar_set(hw, hw->mac.addr, 0);
-
-	/* Zero out the other (rar_entry_count - 1) receive addresses */
-	hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1);
-	for (i = 1; i < rar_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0);
-		e1e_flush();
-		E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0);
-		e1e_flush();
-	}
-}
-
-/**
- *  e1000e_rar_set - Set receive address register
- *  @hw: pointer to the HW structure
- *  @addr: pointer to the receive address
- *  @index: receive address array register
- *
- *  Sets the receive address array register at index to the address passed
- *  in by addr.
- **/
-void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	u32 rar_low, rar_high;
-
-	/* HW expects these in little endian so we reverse the byte order
-	 * from network order (big endian) to little endian
-	 */
-	rar_low = ((u32) addr[0] |
-		   ((u32) addr[1] << 8) |
-		    ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
-
-	rar_high |= E1000_RAH_AV;
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
-	E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
-}
-
-/**
- *  e1000_mta_set - Set multicast filter table address
- *  @hw: pointer to the HW structure
- *  @hash_value: determines the MTA register and bit to set
- *
- *  The multicast table address is a register array of 32-bit registers.
- *  The hash_value is used to determine what register the bit is in, the
- *  current value is read, the new bit is OR'd in and the new value is
- *  written back into the register.
- **/
-static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
-{
-	u32 hash_bit, hash_reg, mta;
-
-	/* The MTA is a register array of 32-bit registers. It is
-	 * treated like an array of (32*mta_reg_count) bits.  We want to
-	 * set bit BitArray[hash_value]. So we figure out what register
-	 * the bit is in, read it, OR in the new bit, then write
-	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
-	 * mask to bits 31:5 of the hash value which gives us the
-	 * register we're modifying.  The hash bit within that register
-	 * is determined by the lower 5 bits of the hash value.
-	 */
-	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-	hash_bit = hash_value & 0x1F;
-
-	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
-
-	mta |= (1 << hash_bit);
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
-	e1e_flush();
-}
-
-/**
- *  e1000_hash_mc_addr - Generate a multicast hash value
- *  @hw: pointer to the HW structure
- *  @mc_addr: pointer to a multicast address
- *
- *  Generates a multicast address hash value which is used to determine
- *  the multicast filter table array address and new table value.  See
- *  e1000_mta_set_generic()
- **/
-static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
-{
-	u32 hash_value, hash_mask;
-	u8 bit_shift = 0;
-
-	/* Register count multiplied by bits per register */
-	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
-
-	/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
-	 * where 0xFF would still fall within the hash mask. */
-	while (hash_mask >> bit_shift != 0xFF)
-		bit_shift++;
-
-	/* The portion of the address that is used for the hash table
-	 * is determined by the mc_filter_type setting.
-	 * The algorithm is such that there is a total of 8 bits of shifting.
-	 * The bit_shift for a mc_filter_type of 0 represents the number of
-	 * left-shifts where the MSB of mc_addr[5] would still fall within
-	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
-	 * of 8 bits of shifting, then mc_addr[4] will shift right the
-	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
-	 * cases are a variation of this algorithm...essentially raising the
-	 * number of bits to shift mc_addr[5] left, while still keeping the
-	 * 8-bit shifting total.
-	 */
-	/* For example, given the following Destination MAC Address and an
-	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
-	 * we can see that the bit_shift for case 0 is 4.  These are the hash
-	 * values resulting from each mc_filter_type...
-	 * [0] [1] [2] [3] [4] [5]
-	 * 01  AA  00  12  34  56
-	 * LSB		 MSB
-	 *
-	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
-	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
-	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
-	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
-	 */
-	switch (hw->mac.mc_filter_type) {
-	default:
-	case 0:
-		break;
-	case 1:
-		bit_shift += 1;
-		break;
-	case 2:
-		bit_shift += 2;
-		break;
-	case 3:
-		bit_shift += 4;
-		break;
-	}
-
-	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
-				  (((u16) mc_addr[5]) << bit_shift)));
-
-	return hash_value;
-}
-
-/**
- *  e1000e_mc_addr_list_update_generic - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *  @rar_used_count: the first RAR register free to program
- *  @rar_count: total number of supported Receive Address Registers
- *
- *  Updates the Receive Address Registers and Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- *  The parameter rar_count will usually be hw->mac.rar_entry_count
- *  unless there are workarounds that change this.
- **/
-void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
-				       u8 *mc_addr_list, u32 mc_addr_count,
-				       u32 rar_used_count, u32 rar_count)
-{
-	u32 hash_value;
-	u32 i;
-
-	/* Load the first set of multicast addresses into the exact
-	 * filters (RAR).  If there are not enough to fill the RAR
-	 * array, clear the filters.
-	 */
-	for (i = rar_used_count; i < rar_count; i++) {
-		if (mc_addr_count) {
-			e1000e_rar_set(hw, mc_addr_list, i);
-			mc_addr_count--;
-			mc_addr_list += ETH_ALEN;
-		} else {
-			E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
-			e1e_flush();
-			E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
-			e1e_flush();
-		}
-	}
-
-	/* Clear the old settings from the MTA */
-	hw_dbg(hw, "Clearing MTA\n");
-	for (i = 0; i < hw->mac.mta_reg_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-		e1e_flush();
-	}
-
-	/* Load any remaining multicast addresses into the hash table. */
-	for (; mc_addr_count > 0; mc_addr_count--) {
-		hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
-		hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
-		e1000_mta_set(hw, hash_value);
-		mc_addr_list += ETH_ALEN;
-	}
-}
-
-/**
- *  e1000e_clear_hw_cntrs_base - Clear base hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the base hardware counters by reading the counter registers.
- **/
-void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
-{
-	u32 temp;
-
-	temp = er32(CRCERRS);
-	temp = er32(SYMERRS);
-	temp = er32(MPC);
-	temp = er32(SCC);
-	temp = er32(ECOL);
-	temp = er32(MCC);
-	temp = er32(LATECOL);
-	temp = er32(COLC);
-	temp = er32(DC);
-	temp = er32(SEC);
-	temp = er32(RLEC);
-	temp = er32(XONRXC);
-	temp = er32(XONTXC);
-	temp = er32(XOFFRXC);
-	temp = er32(XOFFTXC);
-	temp = er32(FCRUC);
-	temp = er32(GPRC);
-	temp = er32(BPRC);
-	temp = er32(MPRC);
-	temp = er32(GPTC);
-	temp = er32(GORCL);
-	temp = er32(GORCH);
-	temp = er32(GOTCL);
-	temp = er32(GOTCH);
-	temp = er32(RNBC);
-	temp = er32(RUC);
-	temp = er32(RFC);
-	temp = er32(ROC);
-	temp = er32(RJC);
-	temp = er32(TORL);
-	temp = er32(TORH);
-	temp = er32(TOTL);
-	temp = er32(TOTH);
-	temp = er32(TPR);
-	temp = er32(TPT);
-	temp = er32(MPTC);
-	temp = er32(BPTC);
-}
-
-/**
- *  e1000e_check_for_copper_link - Check for link (Copper)
- *  @hw: pointer to the HW structure
- *
- *  Checks to see of the link status of the hardware has changed.  If a
- *  change in link status has been detected, then we read the PHY registers
- *  to get the current speed/duplex if link exists.
- **/
-s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	bool link;
-
-	/* We only want to go out to the PHY registers to see if Auto-Neg
-	 * has completed and/or if our link status has changed.  The
-	 * get_link_status flag is set upon receiving a Link Status
-	 * Change or Rx Sequence Error interrupt.
-	 */
-	if (!mac->get_link_status)
-		return 0;
-
-	/* First we want to see if the MII Status Register reports
-	 * link.  If so, then we want to get the current speed/duplex
-	 * of the PHY.
-	 */
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		return ret_val;
-
-	if (!link)
-		return ret_val; /* No link detected */
-
-	mac->get_link_status = 0;
-
-	/* Check if there was DownShift, must be checked
-	 * immediately after link-up */
-	e1000e_check_downshift(hw);
-
-	/* If we are forcing speed/duplex, then we simply return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		ret_val = -E1000_ERR_CONFIG;
-		return ret_val;
-	}
-
-	/* Auto-Neg is enabled.  Auto Speed Detection takes care
-	 * of MAC speed/duplex configuration.  So we only need to
-	 * configure Collision Distance in the MAC.
-	 */
-	e1000e_config_collision_dist(hw);
-
-	/* Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = e1000e_config_fc_after_link_up(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error configuring flow control\n");
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_check_for_fiber_link - Check for link (Fiber)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val;
-
-	ctrl = er32(CTRL);
-	status = er32(STATUS);
-	rxcw = er32(RXCW);
-
-	/* If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), the cable is plugged in (we have signal),
-	 * and our link partner is not trying to auto-negotiate with us (we
-	 * are receiving idles or data), we need to force link up. We also
-	 * need to give auto-negotiation time to complete, in case the cable
-	 * was just plugged in. The autoneg_failed flag does this.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
-	    (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			return 0;
-		}
-		hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = er32(CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		ew32(CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000e_config_fc_after_link_up(hw);
-		if (ret_val) {
-			hw_dbg(hw, "Error configuring flow control\n");
-			return ret_val;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/* If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
-		ew32(TXCW, mac->txcw);
-		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = 1;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_check_for_serdes_link - Check for link (Serdes)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val;
-
-	ctrl = er32(CTRL);
-	status = er32(STATUS);
-	rxcw = er32(RXCW);
-
-	/* If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), and our link partner is not trying to
-	 * auto-negotiate with us (we are receiving idles or data),
-	 * we need to force link up. We also need to give auto-negotiation
-	 * time to complete.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			return 0;
-		}
-		hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = er32(CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		ew32(CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000e_config_fc_after_link_up(hw);
-		if (ret_val) {
-			hw_dbg(hw, "Error configuring flow control\n");
-			return ret_val;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/* If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
-		ew32(TXCW, mac->txcw);
-		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = 1;
-	} else if (!(E1000_TXCW_ANE & er32(TXCW))) {
-		/* If we force link for non-auto-negotiation switch, check
-		 * link status based on MAC synchronization for internal
-		 * serdes media type.
-		 */
-		/* SYNCH bit and IV bit are sticky. */
-		udelay(10);
-		if (E1000_RXCW_SYNCH & er32(RXCW)) {
-			if (!(rxcw & E1000_RXCW_IV)) {
-				mac->serdes_has_link = 1;
-				hw_dbg(hw, "SERDES: Link is up.\n");
-			}
-		} else {
-			mac->serdes_has_link = 0;
-			hw_dbg(hw, "SERDES: Link is down.\n");
-		}
-	}
-
-	if (E1000_TXCW_ANE & er32(TXCW)) {
-		status = er32(STATUS);
-		mac->serdes_has_link = (status & E1000_STATUS_LU);
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_set_default_fc_generic - Set flow control default values
- *  @hw: pointer to the HW structure
- *
- *  Read the EEPROM for the default values for flow control and store the
- *  values.
- **/
-static s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	u16 nvm_data;
-
-	if (mac->fc != e1000_fc_default)
-		return 0;
-
-	/* Read and store word 0x0F of the EEPROM. This word contains bits
-	 * that determine the hardware's default PAUSE (flow control) mode,
-	 * a bit that determines whether the HW defaults to enabling or
-	 * disabling auto-negotiation, and the direction of the
-	 * SW defined pins. If there is no SW over-ride of the flow
-	 * control setting, then the variable hw->fc will
-	 * be initialized based on a value in the EEPROM.
-	 */
-	ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
-
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-
-	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
-		mac->fc = e1000_fc_none;
-	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
-		 NVM_WORD0F_ASM_DIR)
-		mac->fc = e1000_fc_tx_pause;
-	else
-		mac->fc = e1000_fc_full;
-
-	return 0;
-}
-
-/**
- *  e1000e_setup_link - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-s32 e1000e_setup_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-
-	/* In the case of the phy reset being blocked, we already have a link.
-	 * We do not need to set it up again.
-	 */
-	if (e1000_check_reset_block(hw))
-		return 0;
-
-	/*
-	 * If flow control is set to default, set flow control based on
-	 * the EEPROM flow control settings.
-	 */
-	if (mac->fc == e1000_fc_default) {
-		ret_val = e1000_set_default_fc_generic(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* We want to save off the original Flow Control configuration just
-	 * in case we get disconnected and then reconnected into a different
-	 * hub or switch with different Flow Control capabilities.
-	 */
-	mac->original_fc = mac->fc;
-
-	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
-
-	/* Call the necessary media_type subroutine to configure the link. */
-	ret_val = mac->ops.setup_physical_interface(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Initialize the flow control address, type, and PAUSE timer
-	 * registers to their default values.  This is done even if flow
-	 * control is disabled, because it does not hurt anything to
-	 * initialize these registers.
-	 */
-	hw_dbg(hw, "Initializing the Flow Control address, type and timer regs\n");
-	ew32(FCT, FLOW_CONTROL_TYPE);
-	ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-	ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW);
-
-	ew32(FCTTV, mac->fc_pause_time);
-
-	return e1000e_set_fc_watermarks(hw);
-}
-
-/**
- *  e1000_commit_fc_settings_generic - Configure flow control
- *  @hw: pointer to the HW structure
- *
- *  Write the flow control settings to the Transmit Config Word Register (TXCW)
- *  base on the flow control settings in e1000_mac_info.
- **/
-static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 txcw;
-
-	/* Check for a software override of the flow control settings, and
-	 * setup the device accordingly.  If auto-negotiation is enabled, then
-	 * software will have to set the "PAUSE" bits to the correct value in
-	 * the Transmit Config Word Register (TXCW) and re-start auto-
-	 * negotiation.  However, if auto-negotiation is disabled, then
-	 * software will have to manually configure the two flow control enable
-	 * bits in the CTRL register.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames,
-	 *	  but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames but we
-	 *	  do not support receiving pause frames).
-	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
-	 */
-	switch (mac->fc) {
-	case e1000_fc_none:
-		/* Flow control completely disabled by a software over-ride. */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
-		break;
-	case e1000_fc_rx_pause:
-		/* RX Flow control is enabled and TX Flow control is disabled
-		 * by a software over-ride. Since there really isn't a way to
-		 * advertise that we are capable of RX Pause ONLY, we will
-		 * advertise that we support both symmetric and asymmetric RX
-		 * PAUSE.  Later, we will disable the adapter's ability to send
-		 * PAUSE frames.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	case e1000_fc_tx_pause:
-		/* TX Flow control is enabled, and RX Flow control is disabled,
-		 * by a software over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
-		break;
-	case e1000_fc_full:
-		/* Flow control (both RX and TX) is enabled by a software
-		 * over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	default:
-		hw_dbg(hw, "Flow control param set incorrectly\n");
-		return -E1000_ERR_CONFIG;
-		break;
-	}
-
-	ew32(TXCW, txcw);
-	mac->txcw = txcw;
-
-	return 0;
-}
-
-/**
- *  e1000_poll_fiber_serdes_link_generic - Poll for link up
- *  @hw: pointer to the HW structure
- *
- *  Polls for link up by reading the status register, if link fails to come
- *  up with auto-negotiation, then the link is forced if a signal is detected.
- **/
-static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 i, status;
-	s32 ret_val;
-
-	/* If we have a signal (the cable is plugged in, or assumed true for
-	 * serdes media) then poll for a "Link-Up" indication in the Device
-	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
-	 * seconds (Auto-negotiation should complete in less than 500
-	 * milliseconds even if the other end is doing it in SW).
-	 */
-	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
-		msleep(10);
-		status = er32(STATUS);
-		if (status & E1000_STATUS_LU)
-			break;
-	}
-	if (i == FIBER_LINK_UP_LIMIT) {
-		hw_dbg(hw, "Never got a valid link from auto-neg!!!\n");
-		mac->autoneg_failed = 1;
-		/* AutoNeg failed to achieve a link, so we'll call
-		 * mac->check_for_link. This routine will force the
-		 * link up if we detect a signal. This will allow us to
-		 * communicate with non-autonegotiating link partners.
-		 */
-		ret_val = mac->ops.check_for_link(hw);
-		if (ret_val) {
-			hw_dbg(hw, "Error while checking for link\n");
-			return ret_val;
-		}
-		mac->autoneg_failed = 0;
-	} else {
-		mac->autoneg_failed = 0;
-		hw_dbg(hw, "Valid Link Found\n");
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber and serdes
- *  links.  Upon successful setup, poll for link.
- **/
-s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-
-	ctrl = er32(CTRL);
-
-	/* Take the link out of reset */
-	ctrl &= ~E1000_CTRL_LRST;
-
-	e1000e_config_collision_dist(hw);
-
-	ret_val = e1000_commit_fc_settings_generic(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Since auto-negotiation is enabled, take the link out of reset (the
-	 * link will be in reset, because we previously reset the chip). This
-	 * will restart auto-negotiation.  If auto-negotiation is successful
-	 * then the link-up status bit will be set and the flow control enable
-	 * bits (RFCE and TFCE) will be set according to their negotiated value.
-	 */
-	hw_dbg(hw, "Auto-negotiation enabled\n");
-
-	ew32(CTRL, ctrl);
-	e1e_flush();
-	msleep(1);
-
-	/* For these adapters, the SW defineable pin 1 is set when the optics
-	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
-	 * indication.
-	 */
-	if (hw->media_type == e1000_media_type_internal_serdes ||
-	    (er32(CTRL) & E1000_CTRL_SWDPIN1)) {
-		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
-	} else {
-		hw_dbg(hw, "No signal detected\n");
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_config_collision_dist - Configure collision distance
- *  @hw: pointer to the HW structure
- *
- *  Configures the collision distance to the default value and is used
- *  during link setup. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void e1000e_config_collision_dist(struct e1000_hw *hw)
-{
-	u32 tctl;
-
-	tctl = er32(TCTL);
-
-	tctl &= ~E1000_TCTL_COLD;
-	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
-
-	ew32(TCTL, tctl);
-	e1e_flush();
-}
-
-/**
- *  e1000e_set_fc_watermarks - Set flow control high/low watermarks
- *  @hw: pointer to the HW structure
- *
- *  Sets the flow control high/low threshold (watermark) registers.  If
- *  flow control XON frame transmission is enabled, then set XON frame
- *  tansmission as well.
- **/
-s32 e1000e_set_fc_watermarks(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 fcrtl = 0, fcrth = 0;
-
-	/* Set the flow control receive threshold registers.  Normally,
-	 * these registers will be set to a default threshold that may be
-	 * adjusted later by the driver's runtime code.  However, if the
-	 * ability to transmit pause frames is not enabled, then these
-	 * registers will be set to 0.
-	 */
-	if (mac->fc & e1000_fc_tx_pause) {
-		/* We need to set up the Receive Threshold high and low water
-		 * marks as well as (optionally) enabling the transmission of
-		 * XON frames.
-		 */
-		fcrtl = mac->fc_low_water;
-		fcrtl |= E1000_FCRTL_XONE;
-		fcrth = mac->fc_high_water;
-	}
-	ew32(FCRTL, fcrtl);
-	ew32(FCRTH, fcrth);
-
-	return 0;
-}
-
-/**
- *  e1000e_force_mac_fc - Force the MAC's flow control settings
- *  @hw: pointer to the HW structure
- *
- *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
- *  device control register to reflect the adapter settings.  TFCE and RFCE
- *  need to be explicitly set by software when a copper PHY is used because
- *  autonegotiation is managed by the PHY rather than the MAC.  Software must
- *  also configure these bits when link is forced on a fiber connection.
- **/
-s32 e1000e_force_mac_fc(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl;
-
-	ctrl = er32(CTRL);
-
-	/* Because we didn't get link via the internal auto-negotiation
-	 * mechanism (we either forced link or we got link via PHY
-	 * auto-neg), we have to manually enable/disable transmit an
-	 * receive flow control.
-	 *
-	 * The "Case" statement below enables/disable flow control
-	 * according to the "mac->fc" parameter.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause
-	 *	  frames but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *	  frames but we do not receive pause frames).
-	 *      3:  Both Rx and TX flow control (symmetric) is enabled.
-	 *  other:  No other values should be possible at this point.
-	 */
-	hw_dbg(hw, "mac->fc = %u\n", mac->fc);
-
-	switch (mac->fc) {
-	case e1000_fc_none:
-		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
-		break;
-	case e1000_fc_rx_pause:
-		ctrl &= (~E1000_CTRL_TFCE);
-		ctrl |= E1000_CTRL_RFCE;
-		break;
-	case e1000_fc_tx_pause:
-		ctrl &= (~E1000_CTRL_RFCE);
-		ctrl |= E1000_CTRL_TFCE;
-		break;
-	case e1000_fc_full:
-		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
-		break;
-	default:
-		hw_dbg(hw, "Flow control param set incorrectly\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	ew32(CTRL, ctrl);
-
-	return 0;
-}
-
-/**
- *  e1000e_config_fc_after_link_up - Configures flow control after link
- *  @hw: pointer to the HW structure
- *
- *  Checks the status of auto-negotiation after link up to ensure that the
- *  speed and duplex were not forced.  If the link needed to be forced, then
- *  flow control needs to be forced also.  If auto-negotiation is enabled
- *  and did not fail, then we configure flow control based on our link
- *  partner.
- **/
-s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = 0;
-	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
-	u16 speed, duplex;
-
-	/* Check for the case where we have fiber media and auto-neg failed
-	 * so we had to force link.  In this case, we need to force the
-	 * configuration of the MAC to match the "fc" parameter.
-	 */
-	if (mac->autoneg_failed) {
-		if (hw->media_type == e1000_media_type_fiber ||
-		    hw->media_type == e1000_media_type_internal_serdes)
-			ret_val = e1000e_force_mac_fc(hw);
-	} else {
-		if (hw->media_type == e1000_media_type_copper)
-			ret_val = e1000e_force_mac_fc(hw);
-	}
-
-	if (ret_val) {
-		hw_dbg(hw, "Error forcing flow control settings\n");
-		return ret_val;
-	}
-
-	/* Check for the case where we have copper media and auto-neg is
-	 * enabled.  In this case, we need to check and see if Auto-Neg
-	 * has completed, and if so, how the PHY and link partner has
-	 * flow control configured.
-	 */
-	if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) {
-		/* Read the MII Status Register and check to see if AutoNeg
-		 * has completed.  We read this twice because this reg has
-		 * some "sticky" (latched) bits.
-		 */
-		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			return ret_val;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			return ret_val;
-
-		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
-			hw_dbg(hw, "Copper PHY and Auto Neg "
-				 "has not completed.\n");
-			return ret_val;
-		}
-
-		/* The AutoNeg process has completed, so we now need to
-		 * read both the Auto Negotiation Advertisement
-		 * Register (Address 4) and the Auto_Negotiation Base
-		 * Page Ability Register (Address 5) to determine how
-		 * flow control was negotiated.
-		 */
-		ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);
-		if (ret_val)
-			return ret_val;
-		ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
-		if (ret_val)
-			return ret_val;
-
-		/* Two bits in the Auto Negotiation Advertisement Register
-		 * (Address 4) and two bits in the Auto Negotiation Base
-		 * Page Ability Register (Address 5) determine flow control
-		 * for both the PHY and the link partner.  The following
-		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
-		 * 1999, describes these PAUSE resolution bits and how flow
-		 * control is determined based upon these settings.
-		 * NOTE:  DC = Don't Care
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
-		 *   0   |    1    |   0   |   DC    | e1000_fc_none
-		 *   0   |    1    |   1   |    0    | e1000_fc_none
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 *   1   |    0    |   0   |   DC    | e1000_fc_none
-		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
-		 *   1   |    1    |   0   |    0    | e1000_fc_none
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 *
-		 */
-		/* Are both PAUSE bits set to 1?  If so, this implies
-		 * Symmetric Flow Control is enabled at both ends.  The
-		 * ASM_DIR bits are irrelevant per the spec.
-		 *
-		 * For Symmetric Flow Control:
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
-		 *
-		 */
-		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
-			/* Now we need to check if the user selected RX ONLY
-			 * of pause frames.  In this case, we had to advertise
-			 * FULL flow control because we could not advertise RX
-			 * ONLY. Hence, we must now check to see if we need to
-			 * turn OFF  the TRANSMISSION of PAUSE frames.
-			 */
-			if (mac->original_fc == e1000_fc_full) {
-				mac->fc = e1000_fc_full;
-				hw_dbg(hw, "Flow Control = FULL.\r\n");
-			} else {
-				mac->fc = e1000_fc_rx_pause;
-				hw_dbg(hw, "Flow Control = "
-					 "RX PAUSE frames only.\r\n");
-			}
-		}
-		/* For receiving PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 *
-		 */
-		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-			  (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-			  (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-			  (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			mac->fc = e1000_fc_tx_pause;
-			hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");
-		}
-		/* For transmitting PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 *
-		 */
-		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			mac->fc = e1000_fc_rx_pause;
-			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
-		}
-		/* Per the IEEE spec, at this point flow control should be
-		 * disabled.  However, we want to consider that we could
-		 * be connected to a legacy switch that doesn't advertise
-		 * desired flow control, but can be forced on the link
-		 * partner.  So if we advertised no flow control, that is
-		 * what we will resolve to.  If we advertised some kind of
-		 * receive capability (Rx Pause Only or Full Flow Control)
-		 * and the link partner advertised none, we will configure
-		 * ourselves to enable Rx Flow Control only.  We can do
-		 * this safely for two reasons:  If the link partner really
-		 * didn't want flow control enabled, and we enable Rx, no
-		 * harm done since we won't be receiving any PAUSE frames
-		 * anyway.  If the intent on the link partner was to have
-		 * flow control enabled, then by us enabling RX only, we
-		 * can at least receive pause frames and process them.
-		 * This is a good idea because in most cases, since we are
-		 * predominantly a server NIC, more times than not we will
-		 * be asked to delay transmission of packets than asking
-		 * our link partner to pause transmission of frames.
-		 */
-		else if ((mac->original_fc == e1000_fc_none) ||
-			 (mac->original_fc == e1000_fc_tx_pause)) {
-			mac->fc = e1000_fc_none;
-			hw_dbg(hw, "Flow Control = NONE.\r\n");
-		} else {
-			mac->fc = e1000_fc_rx_pause;
-			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
-		}
-
-		/* Now we need to do one last check...  If we auto-
-		 * negotiated to HALF DUPLEX, flow control should not be
-		 * enabled per IEEE 802.3 spec.
-		 */
-		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
-		if (ret_val) {
-			hw_dbg(hw, "Error getting link speed and duplex\n");
-			return ret_val;
-		}
-
-		if (duplex == HALF_DUPLEX)
-			mac->fc = e1000_fc_none;
-
-		/* Now we call a subroutine to actually force the MAC
-		 * controller to use the correct flow control settings.
-		 */
-		ret_val = e1000e_force_mac_fc(hw);
-		if (ret_val) {
-			hw_dbg(hw, "Error forcing flow control settings\n");
-			return ret_val;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Read the status register for the current speed/duplex and store the current
- *  speed and duplex for copper connections.
- **/
-s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex)
-{
-	u32 status;
-
-	status = er32(STATUS);
-	if (status & E1000_STATUS_SPEED_1000) {
-		*speed = SPEED_1000;
-		hw_dbg(hw, "1000 Mbs, ");
-	} else if (status & E1000_STATUS_SPEED_100) {
-		*speed = SPEED_100;
-		hw_dbg(hw, "100 Mbs, ");
-	} else {
-		*speed = SPEED_10;
-		hw_dbg(hw, "10 Mbs, ");
-	}
-
-	if (status & E1000_STATUS_FD) {
-		*duplex = FULL_DUPLEX;
-		hw_dbg(hw, "Full Duplex\n");
-	} else {
-		*duplex = HALF_DUPLEX;
-		hw_dbg(hw, "Half Duplex\n");
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Sets the speed and duplex to gigabit full duplex (the only possible option)
- *  for fiber/serdes links.
- **/
-s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex)
-{
-	*speed = SPEED_1000;
-	*duplex = FULL_DUPLEX;
-
-	return 0;
-}
-
-/**
- *  e1000e_get_hw_semaphore - Acquire hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Acquire the HW semaphore to access the PHY or NVM
- **/
-s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
-{
-	u32 swsm;
-	s32 timeout = hw->nvm.word_size + 1;
-	s32 i = 0;
-
-	/* Get the SW semaphore */
-	while (i < timeout) {
-		swsm = er32(SWSM);
-		if (!(swsm & E1000_SWSM_SMBI))
-			break;
-
-		udelay(50);
-		i++;
-	}
-
-	if (i == timeout) {
-		hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
-		return -E1000_ERR_NVM;
-	}
-
-	/* Get the FW semaphore. */
-	for (i = 0; i < timeout; i++) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
-
-		/* Semaphore acquired if bit latched */
-		if (er32(SWSM) & E1000_SWSM_SWESMBI)
-			break;
-
-		udelay(50);
-	}
-
-	if (i == timeout) {
-		/* Release semaphores */
-		e1000e_put_hw_semaphore(hw);
-		hw_dbg(hw, "Driver can't access the NVM\n");
-		return -E1000_ERR_NVM;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_put_hw_semaphore - Release hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Release hardware semaphore used to access the PHY or NVM
- **/
-void e1000e_put_hw_semaphore(struct e1000_hw *hw)
-{
-	u32 swsm;
-
-	swsm = er32(SWSM);
-	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
-	ew32(SWSM, swsm);
-}
-
-/**
- *  e1000e_get_auto_rd_done - Check for auto read completion
- *  @hw: pointer to the HW structure
- *
- *  Check EEPROM for Auto Read done bit.
- **/
-s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
-{
-	s32 i = 0;
-
-	while (i < AUTO_READ_DONE_TIMEOUT) {
-		if (er32(EECD) & E1000_EECD_AUTO_RD)
-			break;
-		msleep(1);
-		i++;
-	}
-
-	if (i == AUTO_READ_DONE_TIMEOUT) {
-		hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");
-		return -E1000_ERR_RESET;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_valid_led_default - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT;
-
-	return 0;
-}
-
-/**
- *  e1000e_id_led_init -
- *  @hw: pointer to the HW structure
- *
- **/
-s32 e1000e_id_led_init(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	const u32 ledctl_mask = 0x000000FF;
-	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
-	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
-	u16 data, i, temp;
-	const u16 led_mask = 0x0F;
-
-	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
-	if (ret_val)
-		return ret_val;
-
-	mac->ledctl_default = er32(LEDCTL);
-	mac->ledctl_mode1 = mac->ledctl_default;
-	mac->ledctl_mode2 = mac->ledctl_default;
-
-	for (i = 0; i < 4; i++) {
-		temp = (data >> (i << 2)) & led_mask;
-		switch (temp) {
-		case ID_LED_ON1_DEF2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_ON1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_OFF1_DEF2:
-		case ID_LED_OFF1_ON2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-		switch (temp) {
-		case ID_LED_DEF1_ON2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_OFF1_ON2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_DEF1_OFF2:
-		case ID_LED_ON1_OFF2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_cleanup_led_generic - Set LED config to default operation
- *  @hw: pointer to the HW structure
- *
- *  Remove the current LED configuration and set the LED configuration
- *  to the default value, saved from the EEPROM.
- **/
-s32 e1000e_cleanup_led_generic(struct e1000_hw *hw)
-{
-	ew32(LEDCTL, hw->mac.ledctl_default);
-	return 0;
-}
-
-/**
- *  e1000e_blink_led - Blink LED
- *  @hw: pointer to the HW structure
- *
- *  Blink the led's which are set to be on.
- **/
-s32 e1000e_blink_led(struct e1000_hw *hw)
-{
-	u32 ledctl_blink = 0;
-	u32 i;
-
-	if (hw->media_type == e1000_media_type_fiber) {
-		/* always blink LED0 for PCI-E fiber */
-		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
-		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
-	} else {
-		/* set the blink bit for each LED that's "on" (0x0E)
-		 * in ledctl_mode2 */
-		ledctl_blink = hw->mac.ledctl_mode2;
-		for (i = 0; i < 4; i++)
-			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
-			    E1000_LEDCTL_MODE_LED_ON)
-				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
-						 (i * 8));
-	}
-
-	ew32(LEDCTL, ledctl_blink);
-
-	return 0;
-}
-
-/**
- *  e1000e_led_on_generic - Turn LED on
- *  @hw: pointer to the HW structure
- *
- *  Turn LED on.
- **/
-s32 e1000e_led_on_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-
-	switch (hw->media_type) {
-	case e1000_media_type_fiber:
-		ctrl = er32(CTRL);
-		ctrl &= ~E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		ew32(CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		ew32(LEDCTL, hw->mac.ledctl_mode2);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_led_off_generic - Turn LED off
- *  @hw: pointer to the HW structure
- *
- *  Turn LED off.
- **/
-s32 e1000e_led_off_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-
-	switch (hw->media_type) {
-	case e1000_media_type_fiber:
-		ctrl = er32(CTRL);
-		ctrl |= E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		ew32(CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		ew32(LEDCTL, hw->mac.ledctl_mode1);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_set_pcie_no_snoop - Set PCI-express capabilities
- *  @hw: pointer to the HW structure
- *  @no_snoop: bitmap of snoop events
- *
- *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
- **/
-void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
-{
-	u32 gcr;
-
-	if (no_snoop) {
-		gcr = er32(GCR);
-		gcr &= ~(PCIE_NO_SNOOP_ALL);
-		gcr |= no_snoop;
-		ew32(GCR, gcr);
-	}
-}
-
-/**
- *  e1000e_disable_pcie_master - Disables PCI-express master access
- *  @hw: pointer to the HW structure
- *
- *  Returns 0 if successful, else returns -10
- *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
- *  the master requests to be disabled.
- *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests.
- **/
-s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 timeout = MASTER_DISABLE_TIMEOUT;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
-	ew32(CTRL, ctrl);
-
-	while (timeout) {
-		if (!(er32(STATUS) &
-		      E1000_STATUS_GIO_MASTER_ENABLE))
-			break;
-		udelay(100);
-		timeout--;
-	}
-
-	if (!timeout) {
-		hw_dbg(hw, "Master requests are pending.\n");
-		return -E1000_ERR_MASTER_REQUESTS_PENDING;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_reset_adaptive - Reset Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Reset the Adaptive Interframe Spacing throttle to default values.
- **/
-void e1000e_reset_adaptive(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	mac->current_ifs_val = 0;
-	mac->ifs_min_val = IFS_MIN;
-	mac->ifs_max_val = IFS_MAX;
-	mac->ifs_step_size = IFS_STEP;
-	mac->ifs_ratio = IFS_RATIO;
-
-	mac->in_ifs_mode = 0;
-	ew32(AIT, 0);
-}
-
-/**
- *  e1000e_update_adaptive - Update Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Update the Adaptive Interframe Spacing Throttle value based on the
- *  time between transmitted packets and time between collisions.
- **/
-void e1000e_update_adaptive(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
-		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
-			mac->in_ifs_mode = 1;
-			if (mac->current_ifs_val < mac->ifs_max_val) {
-				if (!mac->current_ifs_val)
-					mac->current_ifs_val = mac->ifs_min_val;
-				else
-					mac->current_ifs_val +=
-						mac->ifs_step_size;
-				ew32(AIT,
-						mac->current_ifs_val);
-			}
-		}
-	} else {
-		if (mac->in_ifs_mode &&
-		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
-			mac->current_ifs_val = 0;
-			mac->in_ifs_mode = 0;
-			ew32(AIT, 0);
-		}
-	}
-}
-
-/**
- *  e1000_raise_eec_clk - Raise EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Enable/Raise the EEPROM clock bit.
- **/
-static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd | E1000_EECD_SK;
-	ew32(EECD, *eecd);
-	e1e_flush();
-	udelay(hw->nvm.delay_usec);
-}
-
-/**
- *  e1000_lower_eec_clk - Lower EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Clear/Lower the EEPROM clock bit.
- **/
-static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd & ~E1000_EECD_SK;
-	ew32(EECD, *eecd);
-	e1e_flush();
-	udelay(hw->nvm.delay_usec);
-}
-
-/**
- *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
- *  @hw: pointer to the HW structure
- *  @data: data to send to the EEPROM
- *  @count: number of bits to shift out
- *
- *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
- *  "data" parameter will be shifted out to the EEPROM one bit at a time.
- *  In order to do this, "data" must be broken down into bits.
- **/
-static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u32 mask;
-
-	mask = 0x01 << (count - 1);
-	if (nvm->type == e1000_nvm_eeprom_spi)
-		eecd |= E1000_EECD_DO;
-
-	do {
-		eecd &= ~E1000_EECD_DI;
-
-		if (data & mask)
-			eecd |= E1000_EECD_DI;
-
-		ew32(EECD, eecd);
-		e1e_flush();
-
-		udelay(nvm->delay_usec);
-
-		e1000_raise_eec_clk(hw, &eecd);
-		e1000_lower_eec_clk(hw, &eecd);
-
-		mask >>= 1;
-	} while (mask);
-
-	eecd &= ~E1000_EECD_DI;
-	ew32(EECD, eecd);
-}
-
-/**
- *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
- *  @hw: pointer to the HW structure
- *  @count: number of bits to shift in
- *
- *  In order to read a register from the EEPROM, we need to shift 'count' bits
- *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
- *  the EEPROM (setting the SK bit), and then reading the value of the data out
- *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
- *  always be clear.
- **/
-static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
-{
-	u32 eecd;
-	u32 i;
-	u16 data;
-
-	eecd = er32(EECD);
-
-	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
-	data = 0;
-
-	for (i = 0; i < count; i++) {
-		data <<= 1;
-		e1000_raise_eec_clk(hw, &eecd);
-
-		eecd = er32(EECD);
-
-		eecd &= ~E1000_EECD_DI;
-		if (eecd & E1000_EECD_DO)
-			data |= 1;
-
-		e1000_lower_eec_clk(hw, &eecd);
-	}
-
-	return data;
-}
-
-/**
- *  e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion
- *  @hw: pointer to the HW structure
- *  @ee_reg: EEPROM flag for polling
- *
- *  Polls the EEPROM status bit for either read or write completion based
- *  upon the value of 'ee_reg'.
- **/
-s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
-{
-	u32 attempts = 100000;
-	u32 i, reg = 0;
-
-	for (i = 0; i < attempts; i++) {
-		if (ee_reg == E1000_NVM_POLL_READ)
-			reg = er32(EERD);
-		else
-			reg = er32(EEWR);
-
-		if (reg & E1000_NVM_RW_REG_DONE)
-			return 0;
-
-		udelay(5);
-	}
-
-	return -E1000_ERR_NVM;
-}
-
-/**
- *  e1000e_acquire_nvm - Generic request for access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
- *  Return successful if access grant bit set, else clear the request for
- *  EEPROM access and return -E1000_ERR_NVM (-1).
- **/
-s32 e1000e_acquire_nvm(struct e1000_hw *hw)
-{
-	u32 eecd = er32(EECD);
-	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
-
-	ew32(EECD, eecd | E1000_EECD_REQ);
-	eecd = er32(EECD);
-
-	while (timeout) {
-		if (eecd & E1000_EECD_GNT)
-			break;
-		udelay(5);
-		eecd = er32(EECD);
-		timeout--;
-	}
-
-	if (!timeout) {
-		eecd &= ~E1000_EECD_REQ;
-		ew32(EECD, eecd);
-		hw_dbg(hw, "Could not acquire NVM grant\n");
-		return -E1000_ERR_NVM;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_standby_nvm - Return EEPROM to standby state
- *  @hw: pointer to the HW structure
- *
- *  Return the EEPROM to a standby state.
- **/
-static void e1000_standby_nvm(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Toggle CS to flush commands */
-		eecd |= E1000_EECD_CS;
-		ew32(EECD, eecd);
-		e1e_flush();
-		udelay(nvm->delay_usec);
-		eecd &= ~E1000_EECD_CS;
-		ew32(EECD, eecd);
-		e1e_flush();
-		udelay(nvm->delay_usec);
-	}
-}
-
-/**
- *  e1000_stop_nvm - Terminate EEPROM command
- *  @hw: pointer to the HW structure
- *
- *  Terminates the current command by inverting the EEPROM's chip select pin.
- **/
-static void e1000_stop_nvm(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	eecd = er32(EECD);
-	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
-		/* Pull CS high */
-		eecd |= E1000_EECD_CS;
-		e1000_lower_eec_clk(hw, &eecd);
-	}
-}
-
-/**
- *  e1000e_release_nvm - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
- **/
-void e1000e_release_nvm(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	e1000_stop_nvm(hw);
-
-	eecd = er32(EECD);
-	eecd &= ~E1000_EECD_REQ;
-	ew32(EECD, eecd);
-}
-
-/**
- *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
- *  @hw: pointer to the HW structure
- *
- *  Setups the EEPROM for reading and writing.
- **/
-static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u16 timeout = 0;
-	u8 spi_stat_reg;
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Clear SK and CS */
-		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-		ew32(EECD, eecd);
-		udelay(1);
-		timeout = NVM_MAX_RETRY_SPI;
-
-		/* Read "Status Register" repeatedly until the LSB is cleared.
-		 * The EEPROM will signal that the command has been completed
-		 * by clearing bit 0 of the internal status register.  If it's
-		 * not cleared within 'timeout', then error out. */
-		while (timeout) {
-			e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
-						 hw->nvm.opcode_bits);
-			spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
-			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
-				break;
-
-			udelay(5);
-			e1000_standby_nvm(hw);
-			timeout--;
-		}
-
-		if (!timeout) {
-			hw_dbg(hw, "SPI NVM Status error\n");
-			return -E1000_ERR_NVM;
-		}
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_read_nvm_spi - Read EEPROM's using SPI
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM.
- **/
-s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i = 0;
-	s32 ret_val;
-	u16 word_in;
-	u8 read_opcode = NVM_READ_OPCODE_SPI;
-
-	/* A check for invalid values:  offset too large, too many words,
-	 * and not enough words. */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-		return -E1000_ERR_NVM;
-	}
-
-	ret_val = nvm->ops.acquire_nvm(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000_ready_nvm_eeprom(hw);
-	if (ret_val) {
-		nvm->ops.release_nvm(hw);
-		return ret_val;
-	}
-
-	e1000_standby_nvm(hw);
-
-	if ((nvm->address_bits == 8) && (offset >= 128))
-		read_opcode |= NVM_A8_OPCODE_SPI;
-
-	/* Send the READ command (opcode + addr) */
-	e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
-	e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
-
-	/* Read the data.  SPI NVMs increment the address with each byte
-	 * read and will roll over if reading beyond the end.  This allows
-	 * us to read the whole NVM from any offset */
-	for (i = 0; i < words; i++) {
-		word_in = e1000_shift_in_eec_bits(hw, 16);
-		data[i] = (word_in >> 8) | (word_in << 8);
-	}
-
-	nvm->ops.release_nvm(hw);
-	return 0;
-}
-
-/**
- *  e1000e_read_nvm_eerd - Reads EEPROM using EERD register
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM using the EERD register.
- **/
-s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i, eerd = 0;
-	s32 ret_val = 0;
-
-	/* A check for invalid values:  offset too large, too many words,
-	 * and not enough words. */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-		return -E1000_ERR_NVM;
-	}
-
-	for (i = 0; i < words; i++) {
-		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
-		       E1000_NVM_RW_REG_START;
-
-		ew32(EERD, eerd);
-		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
-		if (ret_val)
-			break;
-
-		data[i] = (er32(EERD) >>
-			   E1000_NVM_RW_REG_DATA);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_write_nvm_spi - Write to EEPROM using SPI
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  Writes data to EEPROM at offset using SPI interface.
- *
- *  If e1000e_update_nvm_checksum is not called after this function , the
- *  EEPROM will most likley contain an invalid checksum.
- **/
-s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
-	u16 widx = 0;
-
-	/* A check for invalid values:  offset too large, too many words,
-	 * and not enough words. */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
-		return -E1000_ERR_NVM;
-	}
-
-	ret_val = nvm->ops.acquire_nvm(hw);
-	if (ret_val)
-		return ret_val;
-
-	msleep(10);
-
-	while (widx < words) {
-		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
-
-		ret_val = e1000_ready_nvm_eeprom(hw);
-		if (ret_val) {
-			nvm->ops.release_nvm(hw);
-			return ret_val;
-		}
-
-		e1000_standby_nvm(hw);
-
-		/* Send the WRITE ENABLE command (8 bit opcode) */
-		e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
-					 nvm->opcode_bits);
-
-		e1000_standby_nvm(hw);
-
-		/* Some SPI eeproms use the 8th address bit embedded in the
-		 * opcode */
-		if ((nvm->address_bits == 8) && (offset >= 128))
-			write_opcode |= NVM_A8_OPCODE_SPI;
-
-		/* Send the Write command (8-bit opcode + addr) */
-		e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
-		e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
-					 nvm->address_bits);
-
-		/* Loop to allow for up to whole page write of eeprom */
-		while (widx < words) {
-			u16 word_out = data[widx];
-			word_out = (word_out >> 8) | (word_out << 8);
-			e1000_shift_out_eec_bits(hw, word_out, 16);
-			widx++;
-
-			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
-				e1000_standby_nvm(hw);
-				break;
-			}
-		}
-	}
-
-	msleep(10);
-	return 0;
-}
-
-/**
- *  e1000e_read_mac_addr - Read device MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the device MAC address from the EEPROM and stores the value.
- *  Since devices with two ports use the same EEPROM, we increment the
- *  last bit in the MAC address for the second port.
- **/
-s32 e1000e_read_mac_addr(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 offset, nvm_data, i;
-
-	for (i = 0; i < ETH_ALEN; i += 2) {
-		offset = i >> 1;
-		ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
-		if (ret_val) {
-			hw_dbg(hw, "NVM Read Error\n");
-			return ret_val;
-		}
-		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
-		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
-	}
-
-	/* Flip last bit of mac address if we're on second port */
-	if (hw->bus.func == E1000_FUNC_1)
-		hw->mac.perm_addr[5] ^= 1;
-
-	for (i = 0; i < ETH_ALEN; i++)
-		hw->mac.addr[i] = hw->mac.perm_addr[i];
-
-	return 0;
-}
-
-/**
- *  e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
- *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
- **/
-s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
-		ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			hw_dbg(hw, "NVM Read Error\n");
-			return ret_val;
-		}
-		checksum += nvm_data;
-	}
-
-	if (checksum != (u16) NVM_SUM) {
-		hw_dbg(hw, "NVM Checksum Invalid\n");
-		return -E1000_ERR_NVM;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_update_nvm_checksum_generic - Update EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
- *  up to the checksum.  Then calculates the EEPROM checksum and writes the
- *  value to the EEPROM.
- **/
-s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
-		ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			hw_dbg(hw, "NVM Read Error while updating checksum.\n");
-			return ret_val;
-		}
-		checksum += nvm_data;
-	}
-	checksum = (u16) NVM_SUM - checksum;
-	ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
-	if (ret_val)
-		hw_dbg(hw, "NVM Write Error while updating checksum.\n");
-
-	return ret_val;
-}
-
-/**
- *  e1000e_reload_nvm - Reloads EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
- *  extended control register.
- **/
-void e1000e_reload_nvm(struct e1000_hw *hw)
-{
-	u32 ctrl_ext;
-
-	udelay(10);
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-	ew32(CTRL_EXT, ctrl_ext);
-	e1e_flush();
-}
-
-/**
- *  e1000_calculate_checksum - Calculate checksum for buffer
- *  @buffer: pointer to EEPROM
- *  @length: size of EEPROM to calculate a checksum for
- *
- *  Calculates the checksum for some buffer on a specified length.  The
- *  checksum calculated is returned.
- **/
-static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
-{
-	u32 i;
-	u8  sum = 0;
-
-	if (!buffer)
-		return 0;
-
-	for (i = 0; i < length; i++)
-		sum += buffer[i];
-
-	return (u8) (0 - sum);
-}
-
-/**
- *  e1000_mng_enable_host_if - Checks host interface is enabled
- *  @hw: pointer to the HW structure
- *
- *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
- *
- *  This function checks whether the HOST IF is enabled for command operaton
- *  and also checks whether the previous command is completed.  It busy waits
- *  in case of previous command is not completed.
- **/
-static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
-{
-	u32 hicr;
-	u8 i;
-
-	/* Check that the host interface is enabled. */
-	hicr = er32(HICR);
-	if ((hicr & E1000_HICR_EN) == 0) {
-		hw_dbg(hw, "E1000_HOST_EN bit disabled.\n");
-		return -E1000_ERR_HOST_INTERFACE_COMMAND;
-	}
-	/* check the previous command is completed */
-	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
-		hicr = er32(HICR);
-		if (!(hicr & E1000_HICR_C))
-			break;
-		mdelay(1);
-	}
-
-	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
-		hw_dbg(hw, "Previous command timeout failed .\n");
-		return -E1000_ERR_HOST_INTERFACE_COMMAND;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_check_mng_mode - check managament mode
- *  @hw: pointer to the HW structure
- *
- *  Reads the firmware semaphore register and returns true (>0) if
- *  manageability is enabled, else false (0).
- **/
-bool e1000e_check_mng_mode(struct e1000_hw *hw)
-{
-	u32 fwsm = er32(FWSM);
-
-	return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
-}
-
-/**
- *  e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX
- *  @hw: pointer to the HW structure
- *
- *  Enables packet filtering on transmit packets if manageability is enabled
- *  and host interface is enabled.
- **/
-bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw)
-{
-	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
-	u32 *buffer = (u32 *)&hw->mng_cookie;
-	u32 offset;
-	s32 ret_val, hdr_csum, csum;
-	u8 i, len;
-
-	/* No manageability, no filtering */
-	if (!e1000e_check_mng_mode(hw)) {
-		hw->mac.tx_pkt_filtering = 0;
-		return 0;
-	}
-
-	/* If we can't read from the host interface for whatever
-	 * reason, disable filtering.
-	 */
-	ret_val = e1000_mng_enable_host_if(hw);
-	if (ret_val != 0) {
-		hw->mac.tx_pkt_filtering = 0;
-		return ret_val;
-	}
-
-	/* Read in the header.  Length and offset are in dwords. */
-	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
-	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
-	for (i = 0; i < len; i++)
-		*(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i);
-	hdr_csum = hdr->checksum;
-	hdr->checksum = 0;
-	csum = e1000_calculate_checksum((u8 *)hdr,
-					E1000_MNG_DHCP_COOKIE_LENGTH);
-	/* If either the checksums or signature don't match, then
-	 * the cookie area isn't considered valid, in which case we
-	 * take the safe route of assuming Tx filtering is enabled.
-	 */
-	if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
-		hw->mac.tx_pkt_filtering = 1;
-		return 1;
-	}
-
-	/* Cookie area is valid, make the final check for filtering. */
-	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
-		hw->mac.tx_pkt_filtering = 0;
-		return 0;
-	}
-
-	hw->mac.tx_pkt_filtering = 1;
-	return 1;
-}
-
-/**
- *  e1000_mng_write_cmd_header - Writes manageability command header
- *  @hw: pointer to the HW structure
- *  @hdr: pointer to the host interface command header
- *
- *  Writes the command header after does the checksum calculation.
- **/
-static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
-				  struct e1000_host_mng_command_header *hdr)
-{
-	u16 i, length = sizeof(struct e1000_host_mng_command_header);
-
-	/* Write the whole command header structure with new checksum. */
-
-	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
-
-	length >>= 2;
-	/* Write the relevant command block into the ram area. */
-	for (i = 0; i < length; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i,
-					    *((u32 *) hdr + i));
-		e1e_flush();
-	}
-
-	return 0;
-}
-
-/**
- *  e1000_mng_host_if_write - Writes to the manageability host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface buffer
- *  @length: size of the buffer
- *  @offset: location in the buffer to write to
- *  @sum: sum of the data (not checksum)
- *
- *  This function writes the buffer content at the offset given on the host if.
- *  It also does alignment considerations to do the writes in most efficient
- *  way.  Also fills up the sum of the buffer in *buffer parameter.
- **/
-static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer,
-				   u16 length, u16 offset, u8 *sum)
-{
-	u8 *tmp;
-	u8 *bufptr = buffer;
-	u32 data = 0;
-	u16 remaining, i, j, prev_bytes;
-
-	/* sum = only sum of the data and it is not checksum */
-
-	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
-		return -E1000_ERR_PARAM;
-
-	tmp = (u8 *)&data;
-	prev_bytes = offset & 0x3;
-	offset >>= 2;
-
-	if (prev_bytes) {
-		data = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset);
-		for (j = prev_bytes; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset, data);
-		length -= j - prev_bytes;
-		offset++;
-	}
-
-	remaining = length & 0x3;
-	length -= remaining;
-
-	/* Calculate length in DWORDs */
-	length >>= 2;
-
-	/* The device driver writes the relevant command block into the
-	 * ram area. */
-	for (i = 0; i < length; i++) {
-		for (j = 0; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-
-		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
-	}
-	if (remaining) {
-		for (j = 0; j < sizeof(u32); j++) {
-			if (j < remaining)
-				*(tmp + j) = *bufptr++;
-			else
-				*(tmp + j) = 0;
-
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface
- *  @length: size of the buffer
- *
- *  Writes the DHCP information to the host interface.
- **/
-s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
-{
-	struct e1000_host_mng_command_header hdr;
-	s32 ret_val;
-	u32 hicr;
-
-	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
-	hdr.command_length = length;
-	hdr.reserved1 = 0;
-	hdr.reserved2 = 0;
-	hdr.checksum = 0;
-
-	/* Enable the host interface */
-	ret_val = e1000_mng_enable_host_if(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Populate the host interface with the contents of "buffer". */
-	ret_val = e1000_mng_host_if_write(hw, buffer, length,
-					  sizeof(hdr), &(hdr.checksum));
-	if (ret_val)
-		return ret_val;
-
-	/* Write the manageability command header */
-	ret_val = e1000_mng_write_cmd_header(hw, &hdr);
-	if (ret_val)
-		return ret_val;
-
-	/* Tell the ARC a new command is pending. */
-	hicr = er32(HICR);
-	ew32(HICR, hicr | E1000_HICR_C);
-
-	return 0;
-}
-
-/**
- *  e1000e_enable_mng_pass_thru - Enable processing of ARP's
- *  @hw: pointer to the HW structure
- *
- *  Verifies the hardware needs to allow ARPs to be processed by the host.
- **/
-bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
-{
-	u32 manc;
-	u32 fwsm, factps;
-	bool ret_val = 0;
-
-	manc = er32(MANC);
-
-	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
-	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
-		return ret_val;
-
-	if (hw->mac.arc_subsystem_valid) {
-		fwsm = er32(FWSM);
-		factps = er32(FACTPS);
-
-		if (!(factps & E1000_FACTPS_MNGCG) &&
-		    ((fwsm & E1000_FWSM_MODE_MASK) ==
-		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
-			ret_val = 1;
-			return ret_val;
-		}
-	} else {
-		if ((manc & E1000_MANC_SMBUS_EN) &&
-		    !(manc & E1000_MANC_ASF_EN)) {
-			ret_val = 1;
-			return ret_val;
-		}
-	}
-
-	return ret_val;
-}
-
-s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num)
-{
-	s32 ret_val;
-	u16 nvm_data;
-
-	ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-	*part_num = (u32)(nvm_data << 16);
-
-	ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
-	if (ret_val) {
-		hw_dbg(hw, "NVM Read Error\n");
-		return ret_val;
-	}
-	*part_num |= nvm_data;
-
-	return 0;
-}
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/Makefile linux-2.6.24.7-rt20-atom/drivers/net/e1000e/Makefile
--- linux-2.6.24.7-rt20/drivers/net/e1000e/Makefile	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/Makefile	2008-10-05 22:33:29.000000000 +0200
@@ -32,6 +32,8 @@
 
 obj-$(CONFIG_E1000E) += e1000e.o
 
-e1000e-objs := 82571.o ich8lan.o es2lan.o \
-	       lib.o phy.o param.o ethtool.o netdev.o
+e1000e-objs := e1000_80003es2lan.o e1000_82571.o e1000_ich8lan.o e1000_mac.o \
+	       e1000_manage.o e1000_nvm.o e1000_phy.o kcompat.o param.o \
+	       ethtool.o netdev.o
+
 
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/netdev.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/netdev.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/netdev.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/netdev.c	2008-06-23 18:27:33.000000000 +0200
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -36,39 +36,282 @@
 #include <linux/netdevice.h>
 #include <linux/tcp.h>
 #include <linux/ipv6.h>
+#ifdef NETIF_F_TSO
 #include <net/checksum.h>
+#ifdef NETIF_F_TSO6
 #include <net/ip6_checksum.h>
+#endif
+#endif
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
-#include <linux/cpu.h>
-#include <linux/smp.h>
 
 #include "e1000.h"
 
-#define DRV_VERSION "0.2.0"
+#ifdef CONFIG_E1000E_NAPI
+#define DRV_NAPI "-NAPI"
+#else
+#define DRV_NAPI
+#endif
+
+#define DRV_DEBUG
+
+#define DRV_VERSION "0.4.1.7" DRV_NAPI DRV_DEBUG
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
+static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	static int global_quad_port_a; /* global port a indication */
+	struct pci_dev *pdev = adapter->pdev;
+	u16 eeprom_data = 0;
+	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
+
+	/* tag quad port adapters first, it's used below */
+	switch (pdev->device) {
+	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+	case E1000_DEV_ID_82571PT_QUAD_COPPER:
+		adapter->flags |= FLAG_IS_QUAD_PORT;
+		/* mark the first port */
+		if (global_quad_port_a == 0)
+			adapter->flags |= FLAG_IS_QUAD_PORT_A;
+		/* Reset for multiple quad port adapters */
+		global_quad_port_a++;
+		if (global_quad_port_a == 4)
+			global_quad_port_a = 0;
+		break;
+	default:
+		break;
+	}
+
+	switch (adapter->hw.mac.type) {
+	case e1000_82571:
+		/* these dual ports don't have WoL on port B at all */
+		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
+		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
+		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
+		    (is_port_b))
+			adapter->flags &= ~FLAG_HAS_WOL;
+		/* quad ports only support WoL on port A */
+		if (adapter->flags & FLAG_IS_QUAD_PORT &&
+		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
+			adapter->flags &= ~FLAG_HAS_WOL;
+		/* Does not support WoL on any port */
+		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)
+			adapter->flags &= ~FLAG_HAS_WOL;
+		break;
+
+	case e1000_82573:
+		if (pdev->device == E1000_DEV_ID_82573L) {
+			adapter->hw.nvm.ops.read(&adapter->hw, NVM_INIT_3GIO_3,
+			                         1, &eeprom_data);
+			if (!(eeprom_data & NVM_WORD1A_ASPM_MASK))
+				adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct e1000_info e1000_82571_info = {
+	.mac			= e1000_82571,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_RESET_OVERWRITES_LAA /* errata */
+				  | FLAG_TARC_SPEED_MODE_BIT /* errata */
+				  | FLAG_APME_CHECK_PORT_B,
+	.pba			= 38,
+	.init_ops		= e1000_init_function_pointers_82571,
+	.get_variants		= e1000_get_variants_82571,
+};
+
+static struct e1000_info e1000_82572_info = {
+	.mac			= e1000_82572,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */
+	.pba			= 38,
+	.init_ops		= e1000_init_function_pointers_82571,
+	.get_variants		= e1000_get_variants_82571,
+};
+
+static struct e1000_info e1000_82573_info = {
+	.mac			= e1000_82573,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ASPM
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_SWSM_ON_LOAD,
+	.pba			= 20,
+	.init_ops		= e1000_init_function_pointers_82571,
+	.get_variants		= e1000_get_variants_82571,
+};
+
+static struct e1000_info e1000_82574_info = {
+	.mac			= e1000_82574,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+#ifdef CONFIG_E1000E_MSIX
+				  | FLAG_HAS_MSIX
+#endif
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ASPM
+				  | FLAG_HAS_CTRLEXT_ON_LOAD,
+	.pba			= 20,
+	.init_ops		= e1000_init_function_pointers_82571,
+	.get_variants		= e1000_get_variants_82571,
+};
+
+static struct e1000_info e1000_es2_info = {
+	.mac			= e1000_80003es2lan,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_RX_NEEDS_RESTART /* errata */
+				  | FLAG_TARC_SET_BIT_ZERO /* errata */
+				  | FLAG_APME_CHECK_PORT_B
+				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+				  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
+	.pba			= 38,
+	.init_ops		= e1000_init_function_pointers_80003es2lan,
+	.get_variants		= NULL,
+};
+
+static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
+{
+	if (adapter->hw.phy.type == e1000_phy_ife)
+		adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+
+	if ((adapter->hw.mac.type == e1000_ich8lan) &&
+	    (adapter->hw.phy.type == e1000_phy_igp_3))
+		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+
+	return 0;
+}
+
+static struct e1000_info e1000_ich8_info = {
+	.mac			= e1000_ich8lan,
+	.flags			= FLAG_HAS_WOL
+				  | FLAG_IS_ICH
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 8,
+	.init_ops		= e1000_init_function_pointers_ich8lan,
+	.get_variants		= e1000_get_variants_ich8lan,
+};
+
+static struct e1000_info e1000_ich9_info = {
+	.mac			= e1000_ich9lan,
+	.flags			= FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 10,
+	.init_ops		= e1000_init_function_pointers_ich8lan,
+	.get_variants		= e1000_get_variants_ich8lan,
+};
+
+static struct e1000_info e1000_ich10_info = {
+	.mac			= e1000_ich10lan,
+	.flags			= FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_IS_ICH
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 10,
+	.init_ops		= e1000_init_function_pointers_ich8lan,
+	.get_variants		= e1000_get_variants_ich8lan,
+};
+
 static const struct e1000_info *e1000_info_tbl[] = {
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
 	[board_82573]		= &e1000_82573_info,
+	[board_82574]		= &e1000_82574_info,
 	[board_80003es2lan]	= &e1000_es2_info,
 	[board_ich8lan]		= &e1000_ich8_info,
 	[board_ich9lan]		= &e1000_ich9_info,
+	[board_ich10lan]	= &e1000_ich10_info,
 };
 
-#ifdef DEBUG
-/**
- * e1000_get_hw_dev_name - return device name string
- * used by hardware layer to print debugging information
- **/
-char *e1000e_get_hw_dev_name(struct e1000_hw *hw)
+
+void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value)
 {
-	return hw->adapter->netdev->name;
+	struct e1000_adapter *adapter = hw->back;
+
+	pci_read_config_word(adapter->pdev, reg, value);
+}
+
+s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+	struct e1000_adapter *adapter = hw->back;
+	u16 cap_offset;
+
+	cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+	if (!cap_offset)
+		return -E1000_ERR_CONFIG;
+
+	pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+	return E1000_SUCCESS;
+}
+
+s32 e1000_alloc_zeroed_dev_spec_struct(struct e1000_hw *hw, u32 size)
+{
+	hw->dev_spec = kzalloc(size, GFP_KERNEL);
+
+	if (!hw->dev_spec)
+		return -ENOMEM;
+
+	return E1000_SUCCESS;
+}
+
+void e1000_free_dev_spec_struct(struct e1000_hw *hw)
+{
+	if (!hw->dev_spec)
+		return;
+
+	kfree(hw->dev_spec);
 }
-#endif
 
 /**
  * e1000_desc_unused - calculate if we have unused descriptors
@@ -82,7 +325,7 @@
 }
 
 /**
- * e1000_receive_skb - helper function to handle rx indications
+ * e1000_receive_skb - helper function to handle Rx indications
  * @adapter: board private structure
  * @status: descriptor status field as written by hardware
  * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
@@ -95,12 +338,20 @@
 {
 	skb->protocol = eth_type_trans(skb, netdev);
 
+#ifdef CONFIG_E1000E_NAPI
 	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
 		vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
 					 le16_to_cpu(vlan) &
 					 E1000_RXD_SPC_VLAN_MASK);
 	else
 		netif_receive_skb(skb);
+#else
+	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+		vlan_hwaccel_rx(skb, adapter->vlgrp,
+				le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK);
+	else
+		netif_rx(skb);
+#endif
 
 	netdev->last_rx = jiffies;
 }
@@ -138,8 +389,9 @@
 		/* TCP checksum is good */
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else {
-		/* IP fragment with UDP payload */
-		/* Hardware complements the payload checksum, so we undo it
+		/*
+		 * IP fragment with UDP payload
+		 * Hardware complements the payload checksum, so we undo it
 		 * and then put the value in host order for further stack use.
 		 */
 		csum = ntohl(csum ^ 0xFFFF);
@@ -182,7 +434,8 @@
 			break;
 		}
 
-		/* Make buffer alignment 2 beyond a 16 byte boundary
+		/*
+		 * Make buffer alignment 2 beyond a 16 byte boundary
 		 * this will result in a 16 byte aligned IP header after
 		 * the 14 byte MAC header is removed
 		 */
@@ -213,10 +466,12 @@
 		if (i-- == 0)
 			i = (rx_ring->count - 1);
 
-		/* Force memory writes to complete before letting h/w
+		/*
+		 * Force memory writes to complete before letting h/w
 		 * know there are new descriptors to fetch.  (Only
 		 * applicable for weak-ordered memory model archs,
-		 * such as IA-64). */
+		 * such as IA-64).
+		 */
 		wmb();
 		writel(i, adapter->hw.hw_addr + rx_ring->tail);
 	}
@@ -285,7 +540,8 @@
 			break;
 		}
 
-		/* Make buffer alignment 2 beyond a 16 byte boundary
+		/*
+		 * Make buffer alignment 2 beyond a 16 byte boundary
 		 * this will result in a 16 byte aligned IP header after
 		 * the 14 byte MAC header is removed
 		 */
@@ -319,12 +575,15 @@
 		if (!(i--))
 			i = (rx_ring->count - 1);
 
-		/* Force memory writes to complete before letting h/w
+		/*
+		 * Force memory writes to complete before letting h/w
 		 * know there are new descriptors to fetch.  (Only
 		 * applicable for weak-ordered memory model archs,
-		 * such as IA-64). */
+		 * such as IA-64).
+		 */
 		wmb();
-		/* Hardware increments by 16 bytes, but packet split
+		/*
+		 * Hardware increments by 16 bytes, but packet split
 		 * descriptors are 32 bytes...so we increment tail
 		 * twice as much.
 		 */
@@ -332,6 +591,91 @@
 	}
 }
 
+#ifdef CONFIG_E1000E_NAPI
+/**
+ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers
+ * @adapter: address of board private structure
+ * @rx_ring: pointer to receive ring structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+
+static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+                                         int cleaned_count)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_rx_desc *rx_desc;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_buffer *buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+	unsigned int bufsz = 256 -
+	                     16 /* for skb_reserve */ -
+	                     NET_IP_ALIGN;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (cleaned_count--) {
+		skb = buffer_info->skb;
+		if (skb) {
+			skb_trim(skb, 0);
+			goto check_page;
+		}
+
+		skb = netdev_alloc_skb(netdev, bufsz);
+		if (unlikely(!skb)) {
+			/* Better luck next round */
+			adapter->alloc_rx_buff_failed++;
+			break;
+		}
+
+		/* Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		buffer_info->skb = skb;
+check_page:
+		/* allocate a new page if necessary */
+		if (!buffer_info->page) {
+			buffer_info->page = alloc_page(GFP_ATOMIC);
+			if (unlikely(!buffer_info->page)) {
+				adapter->alloc_rx_buff_failed++;
+				break;
+			}
+		}
+
+		if (!buffer_info->dma)
+			buffer_info->dma = pci_map_page(pdev,
+			                                buffer_info->page, 0,
+			                                PAGE_SIZE,
+			                                PCI_DMA_FROMDEVICE);
+
+		rx_desc = E1000_RX_DESC(*rx_ring, i);
+		rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+		if (unlikely(++i == rx_ring->count))
+			i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+	}
+
+	if (likely(rx_ring->next_to_use != i)) {
+		rx_ring->next_to_use = i;
+		if (unlikely(i-- == 0))
+			i = (rx_ring->count - 1);
+
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64). */
+		wmb();
+		writel(i, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+#endif /* CONFIG_E1000E_NAPI */
+
 /**
  * e1000_clean_rx_irq - Send received data up the network stack; legacy
  * @adapter: board private structure
@@ -339,8 +683,12 @@
  * the return value indicates whether actual cleaning was done, there
  * is no guarantee that everything was cleaned
  **/
+#ifdef CONFIG_E1000E_NAPI
 static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 			       int *work_done, int work_to_do)
+#else
+static bool e1000_clean_rx_irq(struct e1000_adapter *adapter)
+#endif
 {
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
@@ -361,9 +709,11 @@
 		struct sk_buff *skb;
 		u8 status;
 
+#ifdef CONFIG_E1000E_NAPI
 		if (*work_done >= work_to_do)
 			break;
 		(*work_done)++;
+#endif
 
 		status = rx_desc->status;
 		skb = buffer_info->skb;
@@ -393,8 +743,7 @@
 		 * packet, also make sure the frame isn't just CRC only */
 		if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) {
 			/* All receives must fit into a single buffer */
-			ndev_dbg(netdev, "%s: Receive packet consumed "
-				 "multiple buffers\n", netdev->name);
+			e_dbg("Receive packet consumed multiple buffers\n");
 			/* recycle */
 			buffer_info->skb = skb;
 			goto next_desc;
@@ -409,17 +758,22 @@
 		total_rx_bytes += length;
 		total_rx_packets++;
 
-		/* code added for copybreak, this should improve
+		/*
+		 * code added for copybreak, this should improve
 		 * performance for small packets with large amounts
-		 * of reassembly being done in the stack */
+		 * of reassembly being done in the stack
+		 */
 		if (length < copybreak) {
 			struct sk_buff *new_skb =
 			    netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
 			if (new_skb) {
 				skb_reserve(new_skb, NET_IP_ALIGN);
-				memcpy(new_skb->data - NET_IP_ALIGN,
-				       skb->data - NET_IP_ALIGN,
-				       length + NET_IP_ALIGN);
+				skb_copy_to_linear_data_offset(new_skb,
+				                               -NET_IP_ALIGN,
+				                               (skb->data -
+				                                NET_IP_ALIGN),
+				                               (length +
+				                                NET_IP_ALIGN));
 				/* save the skb in buffer_info as good */
 				buffer_info->skb = skb;
 				skb = new_skb;
@@ -458,6 +812,8 @@
 
 	adapter->total_rx_packets += total_rx_packets;
 	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
 	return cleaned;
 }
 
@@ -481,119 +837,181 @@
 	unsigned int i = tx_ring->next_to_clean;
 	unsigned int eop = tx_ring->buffer_info[i].next_to_watch;
 	struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop);
-	struct net_device *netdev = adapter->netdev;
 
 	/* detected Tx unit hang */
-	ndev_err(netdev,
-		 "Detected Tx Unit Hang:\n"
-		 "  TDH                  <%x>\n"
-		 "  TDT                  <%x>\n"
-		 "  next_to_use          <%x>\n"
-		 "  next_to_clean        <%x>\n"
-		 "buffer_info[next_to_clean]:\n"
-		 "  time_stamp           <%lx>\n"
-		 "  next_to_watch        <%x>\n"
-		 "  jiffies              <%lx>\n"
-		 "  next_to_watch.status <%x>\n",
-		 readl(adapter->hw.hw_addr + tx_ring->head),
-		 readl(adapter->hw.hw_addr + tx_ring->tail),
-		 tx_ring->next_to_use,
-		 tx_ring->next_to_clean,
-		 tx_ring->buffer_info[eop].time_stamp,
-		 eop,
-		 jiffies,
-		 eop_desc->upper.fields.status);
+	e_err("Detected Tx Unit Hang:\n"
+	      "  TDH                  <%x>\n"
+	      "  TDT                  <%x>\n"
+	      "  next_to_use          <%x>\n"
+	      "  next_to_clean        <%x>\n"
+	      "buffer_info[next_to_clean]:\n"
+	      "  time_stamp           <%lx>\n"
+	      "  next_to_watch        <%x>\n"
+	      "  jiffies              <%lx>\n"
+	      "  next_to_watch.status <%x>\n",
+	      readl(adapter->hw.hw_addr + tx_ring->head),
+	      readl(adapter->hw.hw_addr + tx_ring->tail),
+	      tx_ring->next_to_use,
+	      tx_ring->next_to_clean,
+	      tx_ring->buffer_info[eop].time_stamp,
+	      eop,
+	      jiffies,
+	      eop_desc->upper.fields.status);
 }
 
 /**
- * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @e1000_alloc_ring - allocate memory for a ring structure
+ **/
+static int e1000_alloc_ring_dma(struct e1000_adapter *adapter,
+				struct e1000_ring *ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
+					GFP_KERNEL);
+	if (!ring->desc)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * e1000e_setup_tx_resources - allocate Tx resources (Descriptors)
  * @adapter: board private structure
  *
- * the return value indicates whether actual cleaning was done, there
- * is no guarantee that everything was cleaned
+ * Return 0 on success, negative on failure
  **/
-static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
+int e1000_setup_tx_resources(struct e1000_adapter *adapter)
 {
-	struct net_device *netdev = adapter->netdev;
-	struct e1000_hw *hw = &adapter->hw;
 	struct e1000_ring *tx_ring = adapter->tx_ring;
-	struct e1000_tx_desc *tx_desc, *eop_desc;
-	struct e1000_buffer *buffer_info;
-	unsigned int i, eop;
-	unsigned int count = 0;
-	bool cleaned = 0;
-	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+	int err = -ENOMEM, size;
 
-	i = tx_ring->next_to_clean;
-	eop = tx_ring->buffer_info[i].next_to_watch;
-	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+	size = sizeof(struct e1000_buffer) * tx_ring->count;
+	tx_ring->buffer_info = vmalloc(size);
+	if (!tx_ring->buffer_info)
+		goto err;
+	memset(tx_ring->buffer_info, 0, size);
 
-	while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
-		for (cleaned = 0; !cleaned; ) {
-			tx_desc = E1000_TX_DESC(*tx_ring, i);
-			buffer_info = &tx_ring->buffer_info[i];
-			cleaned = (i == eop);
+	/* round up to nearest 4K */
+	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
 
-			if (cleaned) {
-				struct sk_buff *skb = buffer_info->skb;
-				unsigned int segs, bytecount;
-				segs = skb_shinfo(skb)->gso_segs ?: 1;
-				/* multiply data chunks by size of headers */
-				bytecount = ((segs - 1) * skb_headlen(skb)) +
-					    skb->len;
-				total_tx_packets += segs;
-				total_tx_bytes += bytecount;
-			}
+	err = e1000_alloc_ring_dma(adapter, tx_ring);
+	if (err)
+		goto err;
 
-			e1000_put_txbuf(adapter, buffer_info);
-			tx_desc->upper.data = 0;
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	spin_lock_init(&adapter->tx_queue_lock);
 
-			i++;
-			if (i == tx_ring->count)
-				i = 0;
-		}
+	return 0;
+err:
+	vfree(tx_ring->buffer_info);
+	e_err("Unable to allocate memory for the transmit descriptor ring\n");
+	return err;
+}
 
-		eop = tx_ring->buffer_info[i].next_to_watch;
-		eop_desc = E1000_TX_DESC(*tx_ring, eop);
-#define E1000_TX_WEIGHT 64
-		/* weight of a sort for tx, to avoid endless transmit cleanup */
-		if (count++ == E1000_TX_WEIGHT)
-			break;
+/**
+ * e1000e_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int e1000_setup_rx_resources(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_buffer *buffer_info;
+	int i, size, desc_len, err = -ENOMEM;
+
+	size = sizeof(struct e1000_buffer) * rx_ring->count;
+	rx_ring->buffer_info = vmalloc(size);
+	if (!rx_ring->buffer_info)
+		goto err;
+	memset(rx_ring->buffer_info, 0, size);
+
+	for (i = 0; i < rx_ring->count; i++) {
+		buffer_info = &rx_ring->buffer_info[i];
+		buffer_info->ps_pages = kcalloc(PS_PAGE_BUFFERS,
+						sizeof(struct e1000_ps_page),
+						GFP_KERNEL);
+		if (!buffer_info->ps_pages)
+			goto err_pages;
 	}
 
-	tx_ring->next_to_clean = i;
+	desc_len = sizeof(union e1000_rx_desc_packet_split);
 
-#define TX_WAKE_THRESHOLD 32
-	if (cleaned && netif_carrier_ok(netdev) &&
-		     e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) {
-		/* Make sure that anybody stopping the queue after this
-		 * sees the new next_to_clean.
-		 */
-		smp_mb();
+	/* Round up to nearest 4K */
+	rx_ring->size = rx_ring->count * desc_len;
+	rx_ring->size = ALIGN(rx_ring->size, 4096);
 
-		if (netif_queue_stopped(netdev) &&
-		    !(test_bit(__E1000_DOWN, &adapter->state))) {
-			netif_wake_queue(netdev);
-			++adapter->restart_queue;
-		}
+	err = e1000_alloc_ring_dma(adapter, rx_ring);
+	if (err)
+		goto err_pages;
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+	rx_ring->rx_skb_top = NULL;
+
+	return 0;
+
+err_pages:
+	for (i = 0; i < rx_ring->count; i++) {
+		buffer_info = &rx_ring->buffer_info[i];
+		kfree(buffer_info->ps_pages);
 	}
+err:
+	vfree(rx_ring->buffer_info);
+	e_err("Unable to allocate memory for the transmit descriptor ring\n");
+	return err;
+}
 
-	if (adapter->detect_tx_hung) {
-		/* Detect a transmit hang in hardware, this serializes the
-		 * check with the clearing of time_stamp and movement of i */
-		adapter->detect_tx_hung = 0;
-		if (tx_ring->buffer_info[eop].dma &&
-		    time_after(jiffies, tx_ring->buffer_info[eop].time_stamp
-			       + (adapter->tx_timeout_factor * HZ))
-		    && !(er32(STATUS) &
-			 E1000_STATUS_TXOFF)) {
-			e1000_print_tx_hang(adapter);
-			netif_stop_queue(netdev);
-		}
+/**
+ * e1000_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ **/
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_buffer *buffer_info;
+	unsigned long size;
+	unsigned int i;
+
+	for (i = 0; i < tx_ring->count; i++) {
+		buffer_info = &tx_ring->buffer_info[i];
+		e1000_put_txbuf(adapter, buffer_info);
 	}
-	adapter->total_tx_bytes += total_tx_bytes;
-	adapter->total_tx_packets += total_tx_packets;
-	return cleaned;
+
+	size = sizeof(struct e1000_buffer) * tx_ring->count;
+	memset(tx_ring->buffer_info, 0, size);
+
+	memset(tx_ring->desc, 0, tx_ring->size);
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+
+	writel(0, adapter->hw.hw_addr + tx_ring->head);
+	writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * e1000_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+void e1000_free_tx_resources(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+
+	e1000_clean_tx_ring(adapter);
+
+	vfree(tx_ring->buffer_info);
+	tx_ring->buffer_info = NULL;
+
+	dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+			  tx_ring->dma);
+	tx_ring->desc = NULL;
 }
 
 /**
@@ -603,8 +1021,12 @@
  * the return value indicates whether actual cleaning was done, there
  * is no guarantee that everything was cleaned
  **/
+#ifdef CONFIG_E1000E_NAPI
 static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
 				  int *work_done, int work_to_do)
+#else
+static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
+#endif
 {
 	union e1000_rx_desc_packet_split *rx_desc, *next_rxd;
 	struct net_device *netdev = adapter->netdev;
@@ -625,9 +1047,11 @@
 	buffer_info = &rx_ring->buffer_info[i];
 
 	while (staterr & E1000_RXD_STAT_DD) {
+#ifdef CONFIG_E1000E_NAPI
 		if (*work_done >= work_to_do)
 			break;
 		(*work_done)++;
+#endif
 		skb = buffer_info->skb;
 
 		/* in the packet split case this is header only */
@@ -649,8 +1073,8 @@
 		buffer_info->dma = 0;
 
 		if (!(staterr & E1000_RXD_STAT_EOP)) {
-			ndev_dbg(netdev, "%s: Packet Split buffers didn't pick "
-				 "up the full packet\n", netdev->name);
+			e_dbg("Packet Split buffers didn't pick up the full"
+			      " packet\n");
 			dev_kfree_skb_irq(skb);
 			goto next_desc;
 		}
@@ -663,8 +1087,8 @@
 		length = le16_to_cpu(rx_desc->wb.middle.length0);
 
 		if (!length) {
-			ndev_dbg(netdev, "%s: Last part of the packet spanning"
-				 " multiple descriptors\n", netdev->name);
+			e_dbg("Last part of the packet spanning multiple"
+			      " descriptors\n");
 			dev_kfree_skb_irq(skb);
 			goto next_desc;
 		}
@@ -672,22 +1096,30 @@
 		/* Good Receive */
 		skb_put(skb, length);
 
+#ifdef CONFIG_E1000E_NAPI
 		{
-		/* this looks ugly, but it seems compiler issues make it
-		   more efficient than reusing j */
+		/*
+		 * this looks ugly, but it seems compiler issues make it
+		 * more efficient than reusing j
+		 */
 		int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]);
 
-		/* page alloc/put takes too long and effects small packet
-		 * throughput, so unsplit small packets and save the alloc/put*/
+		/*
+		 * page alloc/put takes too long and effects small packet
+		 * throughput, so unsplit small packets and save the alloc/put
+		 * only valid in softirq (napi) context to call kmap_*
+		 */
 		if (l1 && (l1 <= copybreak) &&
 		    ((length + l1) <= adapter->rx_ps_bsize0)) {
 			u8 *vaddr;
 
 			ps_page = &buffer_info->ps_pages[0];
 
-			/* there is no documentation about how to call
+			/*
+			 * there is no documentation about how to call
 			 * kmap_atomic, so we can't hold the mapping
-			 * very long */
+			 * very long
+			 */
 			pci_dma_sync_single_for_cpu(pdev, ps_page->dma,
 				PAGE_SIZE, PCI_DMA_FROMDEVICE);
 			vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ);
@@ -700,6 +1132,7 @@
 			goto copydone;
 		} /* if */
 		}
+#endif
 
 		for (j = 0; j < PS_PAGE_BUFFERS; j++) {
 			length = le16_to_cpu(rx_desc->wb.upper.length[j]);
@@ -717,7 +1150,9 @@
 			skb->truesize += length;
 		}
 
+#ifdef CONFIG_E1000E_NAPI
 copydone:
+#endif
 		total_rx_bytes += skb->len;
 		total_rx_packets++;
 
@@ -755,8 +1190,196 @@
 
 	adapter->total_rx_packets += total_rx_packets;
 	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
+	return cleaned;
+}
+
+#ifdef CONFIG_E1000E_NAPI
+/* NOTE: these new jumbo frame routines rely on NAPI because of the
+ * pskb_may_pull call, which eventually must call kmap_atomic which you cannot
+ * call from hard irq context */
+
+/**
+ * e1000_consume_page - helper function
+ **/
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+                               u16 length)
+{
+	bi->page = NULL;
+	skb->len += length;
+	skb->data_len += length;
+	skb->truesize += length;
+}
+
+/**
+ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+                                     int *work_done, int work_to_do)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_rx_desc *rx_desc, *next_rxd;
+	struct e1000_buffer *buffer_info, *next_buffer;
+	u32 length;
+	unsigned int i;
+	int cleaned_count = 0;
+	bool cleaned = FALSE;
+	unsigned int total_rx_bytes=0, total_rx_packets=0;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC(*rx_ring, i);
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (rx_desc->status & E1000_RXD_STAT_DD) {
+		struct sk_buff *skb;
+		u8 status;
+
+		if (*work_done >= work_to_do)
+			break;
+		(*work_done)++;
+
+		status = rx_desc->status;
+		skb = buffer_info->skb;
+		buffer_info->skb = NULL;
+
+		++i;
+		if (i == rx_ring->count)
+			i = 0;
+		next_rxd = E1000_RX_DESC(*rx_ring, i);
+		prefetch(next_rxd);
+
+		next_buffer = &rx_ring->buffer_info[i];
+
+		cleaned = TRUE;
+		cleaned_count++;
+		pci_unmap_page(pdev, buffer_info->dma, PAGE_SIZE,
+		               PCI_DMA_FROMDEVICE);
+		buffer_info->dma = 0;
+
+		length = le16_to_cpu(rx_desc->length);
+
+		/* errors is only valid for DD + EOP descriptors */
+		if (unlikely((status & E1000_RXD_STAT_EOP) &&
+		    (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
+				/* recycle both page and skb */
+				buffer_info->skb = skb;
+				/* an error means any chain goes out the window
+				 * too */
+				if (rx_ring->rx_skb_top)
+					dev_kfree_skb(rx_ring->rx_skb_top);
+				rx_ring->rx_skb_top = NULL;
+				goto next_desc;
+		}
+
+#define rxtop rx_ring->rx_skb_top
+		if (!(status & E1000_RXD_STAT_EOP)) {
+			/* this descriptor is only the beginning (or middle) */
+			if (!rxtop) {
+				/* this is the beginning of a chain */
+				rxtop = skb;
+				skb_fill_page_desc(rxtop, 0, buffer_info->page,
+				                   0, length);
+			} else {
+				/* this is the middle of a chain */
+				skb_fill_page_desc(rxtop,
+				    skb_shinfo(rxtop)->nr_frags,
+				    buffer_info->page, 0, length);
+				/* re-use the skb, only consumed the page */
+				buffer_info->skb = skb;
+			}
+			e1000_consume_page(buffer_info, rxtop, length);
+			goto next_desc;
+		} else {
+			if (rxtop) {
+				/* end of the chain */
+				skb_fill_page_desc(rxtop,
+				    skb_shinfo(rxtop)->nr_frags,
+				    buffer_info->page, 0, length);
+				/* re-use the current skb, we only consumed the
+				 * page */
+				buffer_info->skb = skb;
+				skb = rxtop;
+				rxtop = NULL;
+				e1000_consume_page(buffer_info, skb, length);
+			} else {
+				/* no chain, got EOP, this buf is the packet
+				 * copybreak to save the put_page/alloc_page */
+				if (length <= copybreak &&
+				    skb_tailroom(skb) >= length) {
+					u8 *vaddr;
+					vaddr = kmap_atomic(buffer_info->page,
+					                   KM_SKB_DATA_SOFTIRQ);
+					memcpy(skb_tail_pointer(skb), vaddr,
+					       length);
+					kunmap_atomic(vaddr,
+					              KM_SKB_DATA_SOFTIRQ);
+					/* re-use the page, so don't erase
+					 * buffer_info->page */
+					skb_put(skb, length);
+				} else {
+					skb_fill_page_desc(skb, 0,
+					                   buffer_info->page, 0,
+				                           length);
+					e1000_consume_page(buffer_info, skb,
+					                   length);
+				}
+			}
+		}
+
+		/* Receive Checksum Offload XXX recompute due to CRC strip? */
+		e1000_rx_checksum(adapter,
+		                  (u32)(status) |
+		                  ((u32)(rx_desc->errors) << 24),
+		                  le16_to_cpu(rx_desc->csum), skb);
+
+		/* probably a little skewed due to removing CRC */
+		total_rx_bytes += skb->len;
+		total_rx_packets++;
+
+		/* eth type trans needs skb->data to point to something */
+		if (!pskb_may_pull(skb, ETH_HLEN)) {
+			e_err("pskb_may_pull failed.\n");
+			dev_kfree_skb(skb);
+			goto next_desc;
+		}
+
+		e1000_receive_skb(adapter, netdev, skb, status,
+		                  rx_desc->special);
+
+next_desc:
+		rx_desc->status = 0;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
+			adapter->alloc_rx_buf(adapter, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		buffer_info = next_buffer;
+	}
+	rx_ring->next_to_clean = i;
+
+	cleaned_count = e1000_desc_unused(rx_ring);
+	if (cleaned_count)
+		adapter->alloc_rx_buf(adapter, cleaned_count);
+
+	adapter->total_rx_packets += total_rx_packets;
+	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
 	return cleaned;
 }
+#endif /* CONFIG_E1000E_NAPI */
 
 /**
  * e1000_clean_rx_ring - Free Rx Buffers per Queue
@@ -778,6 +1401,12 @@
 				pci_unmap_single(pdev, buffer_info->dma,
 						 adapter->rx_buffer_len,
 						 PCI_DMA_FROMDEVICE);
+#ifdef CONFIG_E1000E_NAPI
+			else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq)
+				pci_unmap_page(pdev, buffer_info->dma,
+				               PAGE_SIZE,
+				               PCI_DMA_FROMDEVICE);
+#endif
 			else if (adapter->clean_rx == e1000_clean_rx_irq_ps)
 				pci_unmap_single(pdev, buffer_info->dma,
 						 adapter->rx_ps_bsize0,
@@ -785,6 +1414,11 @@
 			buffer_info->dma = 0;
 		}
 
+		if (buffer_info->page) {
+			put_page(buffer_info->page);
+			buffer_info->page = NULL;
+		}
+
 		if (buffer_info->skb) {
 			dev_kfree_skb(buffer_info->skb);
 			buffer_info->skb = NULL;
@@ -802,11 +1436,13 @@
 		}
 	}
 
+#ifdef CONFIG_E1000E_NAPI
 	/* there also may be some cached data from a chained receive */
 	if (rx_ring->rx_skb_top) {
 		dev_kfree_skb(rx_ring->rx_skb_top);
 		rx_ring->rx_skb_top = NULL;
 	}
+#endif
 
 	/* Zero out the descriptor ring */
 	memset(rx_ring->desc, 0, rx_ring->size);
@@ -819,606 +1455,999 @@
 }
 
 /**
- * e1000_intr_msi - Interrupt Handler
- * @irq: interrupt number
- * @data: pointer to a network interface device structure
+ * e1000_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
  **/
-static irqreturn_t e1000_intr_msi(int irq, void *data)
-{
-	struct net_device *netdev = data;
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-	struct e1000_hw *hw = &adapter->hw;
-	u32 icr = er32(ICR);
 
-	/* read ICR disables interrupts using IAM, so keep up with our
-	 * enable/disable accounting */
-	atomic_inc(&adapter->irq_sem);
+void e1000_free_rx_resources(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	int i;
 
-	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
-		hw->mac.get_link_status = 1;
-		/* ICH8 workaround-- Call gig speed drop workaround on cable
-		 * disconnect (LSC) before accessing any PHY registers */
-		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
-		    (!(er32(STATUS) & E1000_STATUS_LU)))
-			e1000e_gig_downshift_workaround_ich8lan(hw);
+	e1000_clean_rx_ring(adapter);
 
-		/* 80003ES2LAN workaround-- For packet buffer work-around on
-		 * link down event; disable receives here in the ISR and reset
-		 * adapter in watchdog */
-		if (netif_carrier_ok(netdev) &&
-		    adapter->flags & FLAG_RX_NEEDS_RESTART) {
-			/* disable receives */
-			u32 rctl = er32(RCTL);
-			ew32(RCTL, rctl & ~E1000_RCTL_EN);
-		}
-		/* guard against interrupt when we're going down */
-		if (!test_bit(__E1000_DOWN, &adapter->state))
-			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	for (i = 0; i < rx_ring->count; i++) {
+		kfree(rx_ring->buffer_info[i].ps_pages);
 	}
 
-	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
-		adapter->total_tx_bytes = 0;
-		adapter->total_tx_packets = 0;
-		adapter->total_rx_bytes = 0;
-		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev, &adapter->napi);
-	} else {
-		atomic_dec(&adapter->irq_sem);
-	}
+	vfree(rx_ring->buffer_info);
+	rx_ring->buffer_info = NULL;
 
-	return IRQ_HANDLED;
+	dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+			  rx_ring->dma);
+	rx_ring->desc = NULL;
 }
 
 /**
- * e1000_intr - Interrupt Handler
- * @irq: interrupt number
- * @data: pointer to a network interface device structure
+ * e1000_update_itr - update the dynamic ITR value based on statistics
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ *
+ *      Stores a new ITR value based on packets and byte
+ *      counts during the last interrupt.  The advantage of per interrupt
+ *      computation is faster updates and more accurate ITR for the current
+ *      traffic pattern.  Constants in this function were computed
+ *      based on theoretical maximum wire speed and thresholds were set based
+ *      on testing data as well as attempting to minimize response time
+ *      while increasing bulk throughput.  This functionality is controlled
+ *      by the InterruptThrottleRate module parameter.
  **/
-static irqreturn_t e1000_intr(int irq, void *data)
-{
-	struct net_device *netdev = data;
-	struct e1000_adapter *adapter = netdev_priv(netdev);
+static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
+				     u16 itr_setting, int packets,
+				     int bytes)
+{
+	unsigned int retval = itr_setting;
+
+	if (packets == 0)
+		goto update_itr_done;
+
+	switch (itr_setting) {
+	case lowest_latency:
+		/* handle TSO and jumbo frames */
+		if (bytes/packets > 8000)
+			retval = bulk_latency;
+		else if ((packets < 5) && (bytes > 512)) {
+			retval = low_latency;
+		}
+		break;
+	case low_latency:  /* 50 usec aka 20000 ints/s */
+		if (bytes > 10000) {
+			/* this if handles the TSO accounting */
+			if (bytes/packets > 8000) {
+				retval = bulk_latency;
+			} else if ((packets < 10) || ((bytes/packets) > 1200)) {
+				retval = bulk_latency;
+			} else if ((packets > 35)) {
+				retval = lowest_latency;
+			}
+		} else if (bytes/packets > 2000) {
+			retval = bulk_latency;
+		} else if (packets <= 2 && bytes < 512) {
+			retval = lowest_latency;
+		}
+		break;
+	case bulk_latency: /* 250 usec aka 4000 ints/s */
+		if (bytes > 25000) {
+			if (packets > 35) {
+				retval = low_latency;
+			}
+		} else if (bytes < 6000) {
+			retval = low_latency;
+		}
+		break;
+	}
+
+update_itr_done:
+	return retval;
+}
+
+static void e1000_set_itr(struct e1000_adapter *adapter)
+{
 	struct e1000_hw *hw = &adapter->hw;
+	u16 current_itr;
+	u32 new_itr = adapter->itr;
 
-	u32 rctl, icr = er32(ICR);
-	if (!icr)
-		return IRQ_NONE;  /* Not our interrupt */
+	/* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+	if (adapter->link_speed != SPEED_1000) {
+		current_itr = 0;
+		new_itr = 4000;
+		goto set_itr_now;
+	}
 
-	/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
-	 * not set, then the adapter didn't send an interrupt */
-	if (!(icr & E1000_ICR_INT_ASSERTED))
-		return IRQ_NONE;
+	adapter->tx_itr = e1000_update_itr(adapter,
+				    adapter->tx_itr,
+				    adapter->total_tx_packets,
+				    adapter->total_tx_bytes);
+	/* conservative mode (itr 3) eliminates the lowest_latency setting */
+	if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
+		adapter->tx_itr = low_latency;
+
+	adapter->rx_itr = e1000_update_itr(adapter,
+				    adapter->rx_itr,
+				    adapter->total_rx_packets,
+				    adapter->total_rx_bytes);
+	/* conservative mode (itr 3) eliminates the lowest_latency setting */
+	if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+		adapter->rx_itr = low_latency;
 
-	/* Interrupt Auto-Mask...upon reading ICR,
-	 * interrupts are masked.  No need for the
-	 * IMC write, but it does mean we should
-	 * account for it ASAP. */
-	atomic_inc(&adapter->irq_sem);
+	current_itr = max(adapter->rx_itr, adapter->tx_itr);
+
+	switch (current_itr) {
+	/* counts and packets in update_itr are dependent on these numbers */
+	case lowest_latency:
+		new_itr = 70000;
+		break;
+	case low_latency:
+		new_itr = 20000; /* aka hwitr = ~200 */
+		break;
+	case bulk_latency:
+		new_itr = 4000;
+		break;
+	default:
+		break;
+	}
+
+set_itr_now:
+	if (new_itr != adapter->itr) {
+		/*
+		 * this attempts to bias the interrupt rate towards Bulk
+		 * by adding intermediate steps when interrupt rate is
+		 * increasing
+		 */
+		new_itr = new_itr > adapter->itr ?
+			     min(adapter->itr + (new_itr >> 2), new_itr) :
+			     new_itr;
+		adapter->itr = new_itr;
+#ifdef CONFIG_E1000E_MSIX
+		adapter->rx_ring->itr_val = new_itr;
+		if (adapter->msix_entries)
+			adapter->rx_ring->set_itr = 1;
+		else
+#endif
+			ew32(ITR, 1000000000 / (new_itr * 256));
+	}
+}
+
+/**
+ * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ *
+ * the return value indicates if there is more work to do (later)
+ **/
+static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc, *eop_desc;
+	struct e1000_buffer *buffer_info;
+	unsigned int i, eop;
+	bool cleaned = 0, retval = 1;
+	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+
+	i = tx_ring->next_to_clean;
+	eop = tx_ring->buffer_info[i].next_to_watch;
+	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+
+	while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+		for (cleaned = 0; !cleaned; ) {
+			tx_desc = E1000_TX_DESC(*tx_ring, i);
+			buffer_info = &tx_ring->buffer_info[i];
+			cleaned = (i == eop);
+
+			if (cleaned) {
+				struct sk_buff *skb = buffer_info->skb;
+#ifdef NETIF_F_TSO
+				unsigned int segs, bytecount;
+				segs = skb_shinfo(skb)->gso_segs ?: 1;
+				/* multiply data chunks by size of headers */
+				bytecount = ((segs - 1) * skb_headlen(skb)) +
+					    skb->len;
+				total_tx_packets += segs;
+				total_tx_bytes += bytecount;
+#else
+				total_tx_packets++;
+				total_tx_bytes += skb->len;
+#endif
+			}
+
+			e1000_put_txbuf(adapter, buffer_info);
+			tx_desc->upper.data = 0;
+
+			i++;
+			if (i == tx_ring->count)
+				i = 0;
+#ifdef CONFIG_E1000E_NAPI
+			if (total_tx_packets >= tx_ring->count) {
+				retval = 0;
+				goto done_cleaning;
+			}
+#endif
+		}
+
+		eop = tx_ring->buffer_info[i].next_to_watch;
+		eop_desc = E1000_TX_DESC(*tx_ring, eop);
+	}
+
+#ifdef CONFIG_E1000E_NAPI
+done_cleaning:
+#endif
+	tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+	if (cleaned && netif_carrier_ok(netdev) &&
+	    e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) {
+		/*
+		 * Make sure that anybody stopping the queue after this
+		 * sees the new next_to_clean.
+		 */
+		smp_mb();
+
+		if (netif_queue_stopped(netdev) &&
+		    !(test_bit(__E1000_DOWN, &adapter->state))) {
+			netif_wake_queue(netdev);
+			++adapter->restart_queue;
+		}
+	}
+
+	if (adapter->detect_tx_hung) {
+		/*
+		 * Detect a transmit hang in hardware, this serializes the
+		 * check with the clearing of time_stamp and movement of i
+		 */
+		adapter->detect_tx_hung = 0;
+		if (tx_ring->buffer_info[eop].dma &&
+		    time_after(jiffies, tx_ring->buffer_info[eop].time_stamp
+			       + (adapter->tx_timeout_factor * HZ))
+		    && !(er32(STATUS) & E1000_STATUS_TXOFF)) {
+			e1000_print_tx_hang(adapter);
+			netif_stop_queue(netdev);
+		}
+	}
+	adapter->total_tx_bytes += total_tx_bytes;
+	adapter->total_tx_packets += total_tx_packets;
+	adapter->net_stats.tx_bytes += total_tx_bytes;
+	adapter->net_stats.tx_packets += total_tx_packets;
+	return retval;
+}
+
+/**
+ * e1000_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr_msi(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+#ifndef CONFIG_E1000E_NAPI
+	int i;
+#endif
+	/* read ICR disables interrupts using IAM */
+	u32 icr = er32(ICR);
 
 	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
 		hw->mac.get_link_status = 1;
-		/* ICH8 workaround-- Call gig speed drop workaround on cable
-		 * disconnect (LSC) before accessing any PHY registers */
+		/*
+		 * ICH8 workaround-- Call gig speed drop workaround on cable
+		 * disconnect (LSC) before accessing any PHY registers
+		 */
 		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
 		    (!(er32(STATUS) & E1000_STATUS_LU)))
-			e1000e_gig_downshift_workaround_ich8lan(hw);
+			e1000_gig_downshift_workaround_ich8lan(hw);
 
-		/* 80003ES2LAN workaround--
-		 * For packet buffer work-around on link down event;
-		 * disable receives here in the ISR and
-		 * reset adapter in watchdog
+		/*
+		 * 80003ES2LAN workaround-- For packet buffer work-around on
+		 * link down event; disable receives here in the ISR and reset
+		 * adapter in watchdog
 		 */
 		if (netif_carrier_ok(netdev) &&
-		    (adapter->flags & FLAG_RX_NEEDS_RESTART)) {
+		    adapter->flags & FLAG_RX_NEEDS_RESTART) {
 			/* disable receives */
-			rctl = er32(RCTL);
+			u32 rctl = er32(RCTL);
 			ew32(RCTL, rctl & ~E1000_RCTL_EN);
+			adapter->flags |= FLAG_RX_RESTART_NOW;
 		}
 		/* guard against interrupt when we're going down */
 		if (!test_bit(__E1000_DOWN, &adapter->state))
 			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
 
+#ifdef CONFIG_E1000E_NAPI
 	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
 		__netif_rx_schedule(netdev, &adapter->napi);
-	} else {
-		atomic_dec(&adapter->irq_sem);
 	}
-
-	return IRQ_HANDLED;
-}
-
-static int e1000_request_irq(struct e1000_adapter *adapter)
-{
-	struct net_device *netdev = adapter->netdev;
-	void (*handler) = &e1000_intr;
-	int irq_flags = IRQF_SHARED;
-	int err;
-
-	err = pci_enable_msi(adapter->pdev);
-	if (err) {
-		ndev_warn(netdev,
-		 "Unable to allocate MSI interrupt Error: %d\n", err);
-	} else {
-		adapter->flags |= FLAG_MSI_ENABLED;
-		handler = &e1000_intr_msi;
-		irq_flags = 0;
-	}
-
-	err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
-			  netdev);
-	if (err) {
-		if (adapter->flags & FLAG_MSI_ENABLED)
-			pci_disable_msi(adapter->pdev);
-		ndev_err(netdev,
-		       "Unable to allocate interrupt Error: %d\n", err);
+#else
+	adapter->total_tx_bytes = 0;
+	adapter->total_rx_bytes = 0;
+	adapter->total_tx_packets = 0;
+	adapter->total_rx_packets = 0;
+
+	for (i = 0; i < E1000_MAX_INTR; i++) {
+		int rx_cleaned = adapter->clean_rx(adapter);
+		int tx_cleaned_complete = e1000_clean_tx_irq(adapter);
+		if (!rx_cleaned && tx_cleaned_complete)
+			break;
 	}
 
-	return err;
-}
-
-static void e1000_free_irq(struct e1000_adapter *adapter)
-{
-	struct net_device *netdev = adapter->netdev;
+	if (likely(adapter->itr_setting & 3))
+		e1000_set_itr(adapter);
+#endif /* CONFIG_E1000E_NAPI */
 
-	free_irq(adapter->pdev->irq, netdev);
-	if (adapter->flags & FLAG_MSI_ENABLED) {
-		pci_disable_msi(adapter->pdev);
-		adapter->flags &= ~FLAG_MSI_ENABLED;
-	}
+	return IRQ_HANDLED;
 }
 
 /**
- * e1000_irq_disable - Mask off interrupt generation on the NIC
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
  **/
-static void e1000_irq_disable(struct e1000_adapter *adapter)
+static irqreturn_t e1000_intr(int irq, void *data)
 {
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
+#ifndef CONFIG_E1000E_NAPI
+	int i;
+	int rx_cleaned, tx_cleaned_complete;
+#endif
+	u32 rctl, icr = er32(ICR);
 
-	atomic_inc(&adapter->irq_sem);
-	ew32(IMC, ~0);
-	e1e_flush();
-	synchronize_irq(adapter->pdev->irq);
-}
+	if (!icr)
+		return IRQ_NONE;  /* Not our interrupt */
 
-/**
- * e1000_irq_enable - Enable default interrupt generation settings
- **/
-static void e1000_irq_enable(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
+#ifdef CONFIG_E1000E_NAPI
+	/*
+	 * IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+	 * not set, then the adapter didn't send an interrupt
+	 */
+	if (!(icr & E1000_ICR_INT_ASSERTED))
+		return IRQ_NONE;
 
-	if (atomic_dec_and_test(&adapter->irq_sem)) {
-		ew32(IMS, IMS_ENABLE_MASK);
-		e1e_flush();
-	}
-}
+#endif /* CONFIG_E1000E_NAPI */
+	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		hw->mac.get_link_status = 1;
+		/*
+		 * ICH8 workaround-- Call gig speed drop workaround on cable
+		 * disconnect (LSC) before accessing any PHY registers
+		 */
+		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+		    (!(er32(STATUS) & E1000_STATUS_LU)))
+			e1000_gig_downshift_workaround_ich8lan(hw);
 
-/**
- * e1000_get_hw_control - get control of the h/w from f/w
- * @adapter: address of board private structure
- *
- * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that
- * the driver is loaded. For AMT version (only with 82573)
- * of the f/w this means that the network i/f is open.
- **/
-static void e1000_get_hw_control(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl_ext;
-	u32 swsm;
+		/*
+		 * 80003ES2LAN workaround--
+		 * For packet buffer work-around on link down event;
+		 * disable receives here in the ISR and
+		 * reset adapter in watchdog
+		 */
+		if (netif_carrier_ok(netdev) &&
+		    (adapter->flags & FLAG_RX_NEEDS_RESTART)) {
+			/* disable receives */
+			rctl = er32(RCTL);
+			ew32(RCTL, rctl & ~E1000_RCTL_EN);
+			adapter->flags |= FLAG_RX_RESTART_NOW;
+		}
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
 
-	/* Let firmware know the driver has taken over */
-	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
-	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
-		ctrl_ext = er32(CTRL_EXT);
-		ew32(CTRL_EXT,
-				ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+#ifdef CONFIG_E1000E_NAPI
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		adapter->total_tx_bytes = 0;
+		adapter->total_tx_packets = 0;
+		adapter->total_rx_bytes = 0;
+		adapter->total_rx_packets = 0;
+		__netif_rx_schedule(netdev, &adapter->napi);
+	}
+#else
+	adapter->total_tx_bytes = 0;
+	adapter->total_rx_bytes = 0;
+	adapter->total_tx_packets = 0;
+	adapter->total_rx_packets = 0;
+
+	for (i = 0; i < E1000_MAX_INTR; i++) {
+		rx_cleaned = adapter->clean_rx(adapter);
+		tx_cleaned_complete = e1000_clean_tx_irq(adapter);
+		if (!rx_cleaned && tx_cleaned_complete)
+			break;
 	}
+
+	if (likely(adapter->itr_setting & 3))
+		e1000_set_itr(adapter);
+#endif /* CONFIG_E1000E_NAPI */
+
+	return IRQ_HANDLED;
 }
 
-/**
- * e1000_release_hw_control - release control of the h/w to f/w
- * @adapter: address of board private structure
- *
- * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that the
- * driver is no longer loaded. For AMT version (only with 82573) i
- * of the f/w this means that the network i/f is closed.
- *
- **/
-static void e1000_release_hw_control(struct e1000_adapter *adapter)
+#ifdef CONFIG_E1000E_MSIX
+static irqreturn_t e1000_msix_other(int irq, void *data)
 {
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl_ext;
-	u32 swsm;
+	u32 icr = er32(ICR);
 
-	/* Let firmware taken over control of h/w */
-	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD);
-	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
-		ctrl_ext = er32(CTRL_EXT);
-		ew32(CTRL_EXT,
-				ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+	if (!(icr & E1000_ICR_INT_ASSERTED))
+	{
+		ew32(IMS, E1000_IMS_OTHER);
+		return IRQ_NONE;
 	}
-}
-
-static void e1000_release_manageability(struct e1000_adapter *adapter)
-{
-	if (adapter->flags & FLAG_MNG_PT_ENABLED) {
-		struct e1000_hw *hw = &adapter->hw;
 
-		u32 manc = er32(MANC);
+	if (icr & adapter->eiac_mask)
+		ew32(ICS, (icr & adapter->eiac_mask));
 
-		/* re-enable hardware interception of ARP */
-		manc |= E1000_MANC_ARP_EN;
-		manc &= ~E1000_MANC_EN_MNG2HOST;
-
-		/* don't explicitly have to mess with MANC2H since
-		 * MANC has an enable disable that gates MANC2H */
-		ew32(MANC, manc);
+	if (icr & E1000_ICR_OTHER) {
+		if (!(icr & E1000_ICR_LSC))
+			goto no_link_interrupt;
+		hw->mac.get_link_status = 1;
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
 	}
-}
-
-/**
- * @e1000_alloc_ring - allocate memory for a ring structure
- **/
-static int e1000_alloc_ring_dma(struct e1000_adapter *adapter,
-				struct e1000_ring *ring)
-{
-	struct pci_dev *pdev = adapter->pdev;
 
-	ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
-					GFP_KERNEL);
-	if (!ring->desc)
-		return -ENOMEM;
+no_link_interrupt:
+	ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
 
-	return 0;
+	return IRQ_HANDLED;
 }
 
-/**
- * e1000e_setup_tx_resources - allocate Tx resources (Descriptors)
- * @adapter: board private structure
- *
- * Return 0 on success, negative on failure
- **/
-int e1000e_setup_tx_resources(struct e1000_adapter *adapter)
+
+#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER
+static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
 {
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 	struct e1000_ring *tx_ring = adapter->tx_ring;
-	int err = -ENOMEM, size;
 
-	size = sizeof(struct e1000_buffer) * tx_ring->count;
-	tx_ring->buffer_info = vmalloc(size);
-	if (!tx_ring->buffer_info)
-		goto err;
-	memset(tx_ring->buffer_info, 0, size);
 
-	/* round up to nearest 4K */
-	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
-	tx_ring->size = ALIGN(tx_ring->size, 4096);
+	adapter->total_tx_bytes = 0;
+	adapter->total_tx_packets = 0;
 
-	err = e1000_alloc_ring_dma(adapter, tx_ring);
-	if (err)
-		goto err;
+	if (!e1000_clean_tx_irq(adapter))
+		/* Ring was not completely cleaned, so fire another interrupt */
+		ew32(ICS, tx_ring->ims_val);
 
-	tx_ring->next_to_use = 0;
-	tx_ring->next_to_clean = 0;
-	spin_lock_init(&adapter->tx_queue_lock);
-
-	return 0;
-err:
-	vfree(tx_ring->buffer_info);
-	ndev_err(adapter->netdev,
-	"Unable to allocate memory for the transmit descriptor ring\n");
-	return err;
+	return IRQ_HANDLED;
 }
 
-/**
- * e1000e_setup_rx_resources - allocate Rx resources (Descriptors)
- * @adapter: board private structure
- *
- * Returns 0 on success, negative on failure
- **/
-int e1000e_setup_rx_resources(struct e1000_adapter *adapter)
+#endif  /* CONFIG_E1000E_SEPARATE_TX_HANDLER */
+static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
 {
-	struct e1000_ring *rx_ring = adapter->rx_ring;
-	struct e1000_buffer *buffer_info;
-	int i, size, desc_len, err = -ENOMEM;
-
-	size = sizeof(struct e1000_buffer) * rx_ring->count;
-	rx_ring->buffer_info = vmalloc(size);
-	if (!rx_ring->buffer_info)
-		goto err;
-	memset(rx_ring->buffer_info, 0, size);
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+#ifndef CONFIG_E1000E_NAPI
+	int i;
+	struct e1000_hw *hw = &adapter->hw;
+#endif
 
-	for (i = 0; i < rx_ring->count; i++) {
-		buffer_info = &rx_ring->buffer_info[i];
-		buffer_info->ps_pages = kcalloc(PS_PAGE_BUFFERS,
-						sizeof(struct e1000_ps_page),
-						GFP_KERNEL);
-		if (!buffer_info->ps_pages)
-			goto err_pages;
+	/* Write the ITR value calculated at the end of the
+	 * previous interrupt.
+	 */
+	if (adapter->rx_ring->set_itr) {
+		writel(1000000000 / (adapter->rx_ring->itr_val * 256),
+		       adapter->hw.hw_addr + adapter->rx_ring->itr_register);
+		adapter->rx_ring->set_itr = 0;
 	}
+	
+#ifdef CONFIG_E1000E_NAPI
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		adapter->total_rx_bytes = 0;
+		adapter->total_rx_packets = 0;
+#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER
+		adapter->total_tx_bytes = 0;
+		adapter->total_tx_packets = 0;
+#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */
+		__netif_rx_schedule(netdev, &adapter->napi);
+	}
+#else
+	adapter->total_rx_bytes = 0;
+	adapter->total_rx_packets = 0;
+#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER
+	adapter->total_tx_bytes = 0;
+	adapter->total_tx_packets = 0;
+#endif
 
-	desc_len = sizeof(union e1000_rx_desc_packet_split);
-
-	/* Round up to nearest 4K */
-	rx_ring->size = rx_ring->count * desc_len;
-	rx_ring->size = ALIGN(rx_ring->size, 4096);
-
-	err = e1000_alloc_ring_dma(adapter, rx_ring);
-	if (err)
-		goto err_pages;
-
-	rx_ring->next_to_clean = 0;
-	rx_ring->next_to_use = 0;
-	rx_ring->rx_skb_top = NULL;
-
-	return 0;
-
-err_pages:
-	for (i = 0; i < rx_ring->count; i++) {
-		buffer_info = &rx_ring->buffer_info[i];
-		kfree(buffer_info->ps_pages);
+	for (i = 0; i < E1000_MAX_INTR; i++) {
+		int rx_cleaned = adapter->clean_rx(adapter);
+#ifndef CONFIG_E1000E_SEPARATE_TX_HANDLER
+		int tx_cleaned_complete = e1000_clean_tx_irq(adapter);
+		if (!rx_cleaned && tx_cleaned_complete)
+#else
+		if (!rx_cleaned)
+#endif
+			goto out;
 	}
-err:
-	vfree(rx_ring->buffer_info);
-	ndev_err(adapter->netdev,
-	"Unable to allocate memory for the transmit descriptor ring\n");
-	return err;
+	/* If we got here, the ring was not completely cleaned,
+	 * so fire another interrupt.
+	 */
+	ew32(ICS, adapter->rx_ring->ims_val);
+
+out:
+#endif /* CONFIG_E1000E_NAPI */
+	return IRQ_HANDLED;
 }
 
 /**
- * e1000_clean_tx_ring - Free Tx Buffers
- * @adapter: board private structure
+ * e1000_configure_msix - Configure MSI-X hardware
+ *
+ * e1000_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
  **/
-static void e1000_clean_tx_ring(struct e1000_adapter *adapter)
+static void e1000_configure_msix(struct e1000_adapter *adapter)
 {
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
 	struct e1000_ring *tx_ring = adapter->tx_ring;
-	struct e1000_buffer *buffer_info;
-	unsigned long size;
-	unsigned int i;
+	int vector = 0;
+	u32 ctrl_ext, ivar = 0;
 
-	for (i = 0; i < tx_ring->count; i++) {
-		buffer_info = &tx_ring->buffer_info[i];
-		e1000_put_txbuf(adapter, buffer_info);
+	adapter->eiac_mask = 0;
+
+	/* Workaround issue with spurious interrupts on 82574 in MSI-X mode */
+	if (hw->mac.type == e1000_82574) {
+		u32 rfctl = er32(RFCTL);
+		rfctl |= E1000_RFCTL_ACK_DIS;
+		ew32(RFCTL, rfctl);
 	}
 
-	size = sizeof(struct e1000_buffer) * tx_ring->count;
-	memset(tx_ring->buffer_info, 0, size);
+#define E1000_IVAR_INT_ALLOC_VALID	0x8
+	/* Configure Rx vector */
+	rx_ring->ims_val = E1000_IMS_RXQ0;
+	adapter->eiac_mask |= rx_ring->ims_val;
+	if (rx_ring->itr_val)
+		writel(1000000000 / (rx_ring->itr_val * 256),
+		       hw->hw_addr + rx_ring->itr_register);
+	else
+		writel(1, hw->hw_addr + rx_ring->itr_register);
+	ivar = E1000_IVAR_INT_ALLOC_VALID | vector;
 
-	memset(tx_ring->desc, 0, tx_ring->size);
+	/* Configure Tx vector */
+	tx_ring->ims_val = E1000_IMS_TXQ0;
+#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER
+	vector++;
+	if (tx_ring->itr_val)
+		writel(1000000000 / (tx_ring->itr_val * 256),
+		       hw->hw_addr + tx_ring->itr_register);
+	else
+		writel(1, hw->hw_addr + tx_ring->itr_register);
+#else
+	rx_ring->ims_val |= tx_ring->ims_val;
+#endif
+	adapter->eiac_mask |= tx_ring->ims_val;
+	ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8);
 
-	tx_ring->next_to_use = 0;
-	tx_ring->next_to_clean = 0;
+	/* set vector for Other Causes, e.g. link changes */
+	vector++;
+	ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16);
+	if (rx_ring->itr_val)
+		writel(1000000000 / (rx_ring->itr_val * 256),
+		       hw->hw_addr + E1000_EITR_82574(vector));
+	else
+		writel(1, hw->hw_addr + E1000_EITR_82574(vector));
 
-	writel(0, adapter->hw.hw_addr + tx_ring->head);
-	writel(0, adapter->hw.hw_addr + tx_ring->tail);
+	/* Cause Tx interrupts on every write back */
+	ivar |= (1 << 31);
+
+	ew32(IVAR, ivar);
+
+	/* enable MSI-X PBA support */
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
+
+	/* Auto-Mask Other interrupts upon ICR read */
+	ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
+	ctrl_ext |= E1000_CTRL_EXT_EIAME;
+	ew32(CTRL_EXT, ctrl_ext);
+	e1e_flush();
+}
+
+void e1000_reset_interrupt_capability(struct e1000_adapter *adapter)
+{
+	if (adapter->msix_entries) {
+		pci_disable_msix(adapter->pdev);
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+	} else if (adapter->flags & FLAG_MSI_ENABLED) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~FLAG_MSI_ENABLED;
+	}
+
+	return;
 }
 
 /**
- * e1000e_free_tx_resources - Free Tx Resources per Queue
- * @adapter: board private structure
+ * e1000_set_interrupt_capability - set MSI or MSI-X if supported
  *
- * Free all transmit software resources
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
  **/
-void e1000e_free_tx_resources(struct e1000_adapter *adapter)
+void e1000_set_interrupt_capability(struct e1000_adapter *adapter)
 {
-	struct pci_dev *pdev = adapter->pdev;
-	struct e1000_ring *tx_ring = adapter->tx_ring;
+	int err;
+	int numvecs, i;
 
-	e1000_clean_tx_ring(adapter);
 
-	vfree(tx_ring->buffer_info);
-	tx_ring->buffer_info = NULL;
+	switch (adapter->int_mode) {
+	case E1000E_INT_MODE_MSIX:
+		if (adapter->flags & FLAG_HAS_MSIX) {
+#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER
+			numvecs = 3; /* RxQ0, TxQ0 and other */
+#else
+			numvecs = 2; /* RxQ0/TxQ0 and other */
+#endif
+			adapter->msix_entries = kcalloc(numvecs,
+						      sizeof(struct msix_entry),
+						      GFP_KERNEL);
+			if (adapter->msix_entries) {
+				for (i=0; i < numvecs; i++)
+					adapter->msix_entries[i].entry = i;
+
+				err = pci_enable_msix(adapter->pdev,
+						      adapter->msix_entries,
+				                      numvecs);
+				if (err == 0)
+					return;
+			}
+			/* MSI-X failed, so fall through and try MSI */
+			e_err("Failed to initialize MSI-X interrupts.  "
+			      "Falling back to MSI interrupts.\n");
+			e1000_reset_interrupt_capability(adapter);
+		}
+		adapter->int_mode = E1000E_INT_MODE_MSI;
+		/* Fall through */
+	case E1000E_INT_MODE_MSI:
+		if (!pci_enable_msi(adapter->pdev)) {
+			adapter->flags |= FLAG_MSI_ENABLED;
+		} else {
+			adapter->int_mode = E1000E_INT_MODE_LEGACY;
+			e_err("Failed to initialize MSI interrupts.  Falling "
+			      "back to legacy interrupts.\n");
+		}
+		/* Fall through */
+	case E1000E_INT_MODE_LEGACY:
+		/* Don't do anything; this is the system default */
+		break;
+	}
 
-	dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
-			  tx_ring->dma);
-	tx_ring->desc = NULL;
+	return;
 }
 
 /**
- * e1000e_free_rx_resources - Free Rx Resources
- * @adapter: board private structure
+ * e1000_request_msix - Initialize MSI-X interrupts
  *
- * Free all receive software resources
+ * e1000_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
  **/
-
-void e1000e_free_rx_resources(struct e1000_adapter *adapter)
+static int e1000_request_msix(struct e1000_adapter *adapter)
 {
-	struct pci_dev *pdev = adapter->pdev;
-	struct e1000_ring *rx_ring = adapter->rx_ring;
-	int i;
+	struct net_device *netdev = adapter->netdev;
+	int err = 0, vector = 0;
 
-	e1000_clean_rx_ring(adapter);
+	if (strlen(netdev->name) < (IFNAMSIZ - 5))
+#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER
+		sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);
+#else
+		sprintf(adapter->rx_ring->name, "%s-Q0", netdev->name);
+#endif
+	else
+		memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_intr_msix_rx, 0, adapter->rx_ring->name,
+	                  netdev);
+	if (err)
+		goto out;
+	adapter->rx_ring->itr_register = E1000_EITR_82574(vector);
+	adapter->rx_ring->itr_val = adapter->itr;
+	vector++;
+
+#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER
+	if (strlen(netdev->name) < (IFNAMSIZ - 5))
+		sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name);
+	else
+		memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &e1000_intr_msix_tx, 0, adapter->tx_ring->name,
+	                  netdev);
+	if (err)
+		goto out;
+	adapter->tx_ring->itr_register = E1000_EITR_82574(vector);
+	adapter->tx_ring->itr_val = adapter->itr;
+	vector++;
+
+#endif /* CONFIG_E1000E_SEPARATE_TX_HANDLER */
+	err = request_irq(adapter->msix_entries[vector].vector,
+	                  &e1000_msix_other, 0, netdev->name, netdev);
+	if (err)
+		goto out;
 
-	for (i = 0; i < rx_ring->count; i++) {
-		kfree(rx_ring->buffer_info[i].ps_pages);
-	}
+	e1000_configure_msix(adapter);
+	return 0;
+out:
+	return err;
+}
 
-	vfree(rx_ring->buffer_info);
-	rx_ring->buffer_info = NULL;
+#endif /* CONFIG_E1000E_MSIX */
+/**
+ * e1000_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ **/
+static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
+{
+	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->tx_ring)
+		goto err;
 
-	dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
-			  rx_ring->dma);
-	rx_ring->desc = NULL;
+	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->rx_ring)
+		goto err;
+
+	return 0;
+err:
+	e_err("Unable to allocate memory for queues\n");
+	kfree(adapter->rx_ring);
+	kfree(adapter->tx_ring);
+	return -ENOMEM;
 }
 
 /**
- * e1000_update_itr - update the dynamic ITR value based on statistics
- *      Stores a new ITR value based on packets and byte
- *      counts during the last interrupt.  The advantage of per interrupt
- *      computation is faster updates and more accurate ITR for the current
- *      traffic pattern.  Constants in this function were computed
- *      based on theoretical maximum wire speed and thresholds were set based
- *      on testing data as well as attempting to minimize response time
- *      while increasing bulk throughput.
- *      this functionality is controlled by the InterruptThrottleRate module
- *      parameter (see e1000_param.c)
- * @adapter: pointer to adapter
- * @itr_setting: current adapter->itr
- * @packets: the number of packets during this measurement interval
- * @bytes: the number of bytes during this measurement interval
+ * e1000_request_irq - initialize interrupts
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
  **/
-static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
-				     u16 itr_setting, int packets,
-				     int bytes)
+static int e1000_request_irq(struct e1000_adapter *adapter)
 {
-	unsigned int retval = itr_setting;
+	struct net_device *netdev = adapter->netdev;
+	int err;
+#ifdef CONFIG_E1000E_MSIX
 
-	if (packets == 0)
-		goto update_itr_done;
+	if (adapter->msix_entries) {
+		err = e1000_request_msix(adapter);
+		if (!err)
+			return err;
+		/* fall back to MSI */
+		e1000_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_MSI;
+		e1000_set_interrupt_capability(adapter);
+	}
+	if (adapter->flags & FLAG_MSI_ENABLED) {
+		err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0,
+		                  netdev->name, netdev);
+		if (!err)
+			return err;
 
-	switch (itr_setting) {
-	case lowest_latency:
-		/* handle TSO and jumbo frames */
-		if (bytes/packets > 8000)
-			retval = bulk_latency;
-		else if ((packets < 5) && (bytes > 512)) {
-			retval = low_latency;
-		}
-		break;
-	case low_latency:  /* 50 usec aka 20000 ints/s */
-		if (bytes > 10000) {
-			/* this if handles the TSO accounting */
-			if (bytes/packets > 8000) {
-				retval = bulk_latency;
-			} else if ((packets < 10) || ((bytes/packets) > 1200)) {
-				retval = bulk_latency;
-			} else if ((packets > 35)) {
-				retval = lowest_latency;
-			}
-		} else if (bytes/packets > 2000) {
-			retval = bulk_latency;
-		} else if (packets <= 2 && bytes < 512) {
-			retval = lowest_latency;
+		/* fall back to legacy interrupt */
+		e1000_reset_interrupt_capability(adapter);
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
+	}
+
+	err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED,
+	                  netdev->name, netdev);
+	if (err)
+		e_err("Unable to allocate interrupt, Error: %d\n", err);
+#else
+	int irq_flags = IRQF_SHARED;
+
+	if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
+		err = pci_enable_msi(adapter->pdev);
+		if (!err) {
+			adapter->flags |= FLAG_MSI_ENABLED;
+			irq_flags = 0;
 		}
-		break;
-	case bulk_latency: /* 250 usec aka 4000 ints/s */
-		if (bytes > 25000) {
-			if (packets > 35) {
-				retval = low_latency;
-			}
-		} else if (bytes < 6000) {
-			retval = low_latency;
+	}
+
+	err = request_irq(adapter->pdev->irq,
+			  ((adapter->flags & FLAG_MSI_ENABLED) ?
+				&e1000_intr_msi : &e1000_intr),
+			  irq_flags, netdev->name, netdev);
+	if (err) {
+		if (adapter->flags & FLAG_MSI_ENABLED) {
+			pci_disable_msi(adapter->pdev);
+			adapter->flags &= ~FLAG_MSI_ENABLED;
 		}
-		break;
+		e_err("Unable to allocate interrupt, Error: %d\n", err);
 	}
+#endif /* CONFIG_E1000E_MSIX */
 
-update_itr_done:
-	return retval;
+	return err;
 }
 
-static void e1000_set_itr(struct e1000_adapter *adapter)
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+#ifdef CONFIG_E1000E_MSIX
+	if (adapter->msix_entries) {
+		int vector = 0;
+
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		vector++;
+
+#ifdef CONFIG_E1000E_SEPARATE_TX_HANDLER
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		vector++;
+
+#endif
+		/* Other Causes interrupt vector */
+		free_irq(adapter->msix_entries[vector].vector, netdev);
+		return;
+	}
+
+#endif /* CONFIG_E1000E_MSIX */
+	free_irq(adapter->pdev->irq, netdev);
+#ifndef CONFIG_E1000E_MSIX
+	if (adapter->flags & FLAG_MSI_ENABLED) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~FLAG_MSI_ENABLED;
+	}
+#endif
+}
+
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ **/
+static void e1000_irq_disable(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	u16 current_itr;
-	u32 new_itr = adapter->itr;
 
-	/* for non-gigabit speeds, just fix the interrupt rate at 4000 */
-	if (adapter->link_speed != SPEED_1000) {
-		current_itr = 0;
-		new_itr = 4000;
-		goto set_itr_now;
+	ew32(IMC, ~0);
+#ifdef CONFIG_E1000E_MSIX
+	if (adapter->msix_entries) {
+		ew32(EIAC_82574, 0);
 	}
+#endif /* CONFIG_E1000E_MSIX */
+	e1e_flush();
+	synchronize_irq(adapter->pdev->irq);
+}
 
-	adapter->tx_itr = e1000_update_itr(adapter,
-				    adapter->tx_itr,
-				    adapter->total_tx_packets,
-				    adapter->total_tx_bytes);
-	/* conservative mode (itr 3) eliminates the lowest_latency setting */
-	if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
-		adapter->tx_itr = low_latency;
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ **/
+static void e1000_irq_enable(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+#ifdef CONFIG_E1000E_MSIX
 
-	adapter->rx_itr = e1000_update_itr(adapter,
-				    adapter->rx_itr,
-				    adapter->total_rx_packets,
-				    adapter->total_rx_bytes);
-	/* conservative mode (itr 3) eliminates the lowest_latency setting */
-	if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
-		adapter->rx_itr = low_latency;
+	if (adapter->msix_entries) {
+		ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
+		ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+	} else {
+		ew32(IMS, IMS_ENABLE_MASK);
+	}
+#else
+	ew32(IMS, IMS_ENABLE_MASK);
+#endif /* CONFIG_E1000E_MSIX */
+}
 
-	current_itr = max(adapter->rx_itr, adapter->tx_itr);
+/**
+ * e1000_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded. For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is open.
+ **/
+static void e1000_get_hw_control(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+	u32 swsm;
 
-	switch (current_itr) {
-	/* counts and packets in update_itr are dependent on these numbers */
-	case lowest_latency:
-		new_itr = 70000;
-		break;
-	case low_latency:
-		new_itr = 20000; /* aka hwitr = ~200 */
-		break;
-	case bulk_latency:
-		new_itr = 4000;
-		break;
-	default:
-		break;
+	/* Let firmware know the driver has taken over */
+	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
+	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+		ctrl_ext = er32(CTRL_EXT);
+		ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
 	}
+}
 
-set_itr_now:
-	if (new_itr != adapter->itr) {
-		/* this attempts to bias the interrupt rate towards Bulk
-		 * by adding intermediate steps when interrupt rate is
-		 * increasing */
-		new_itr = new_itr > adapter->itr ?
-			     min(adapter->itr + (new_itr >> 2), new_itr) :
-			     new_itr;
-		adapter->itr = new_itr;
-		ew32(ITR, 1000000000 / (new_itr * 256));
+/**
+ * e1000_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_release_hw_control resets {CTRL_EXT|SWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded. For AMT version (only with 82573) i
+ * of the f/w this means that the network i/f is closed.
+ *
+ **/
+static void e1000_release_hw_control(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+	u32 swsm;
+
+	/* Let firmware taken over control of h/w */
+	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD);
+	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+		ctrl_ext = er32(CTRL_EXT);
+		ew32(CTRL_EXT, ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
 	}
 }
 
+#ifdef CONFIG_E1000E_NAPI
 /**
- * e1000_clean - NAPI Rx polling callback
- * @adapter: board private structure
+ * e1000_poll - NAPI Rx polling callback
+ * @napi: struct associated with this polling callback
+ * @budget: amount of packets driver is allowed to process this poll
  **/
-static int e1000_clean(struct napi_struct *napi, int budget)
+static int e1000_poll(struct napi_struct *napi, int budget)
 {
-	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
-	struct net_device *poll_dev = adapter->netdev;
-	int tx_cleaned = 0, work_done = 0;
+	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter,
+						     napi);
+	struct net_device *netdev = adapter->netdev;
+	int tx_clean_complete = 1, work_done = 0;
+#ifdef CONFIG_E1000E_MSIX
+	struct e1000_hw *hw = &adapter->hw;
 
-	/* Must NOT use netdev_priv macro here. */
-	adapter = poll_dev->priv;
+	if (adapter->msix_entries &&
+	    !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val))
+		goto clean_rx;
 
-	/* e1000_clean is called per-cpu.  This lock protects
+#endif
+	/*
+	 * e1000_poll is called per-cpu.  This lock protects
 	 * tx_ring from being cleaned by multiple cpus
 	 * simultaneously.  A failure obtaining the lock means
-	 * tx_ring is currently being cleaned anyway. */
+	 * tx_ring is currently being cleaned anyway.
+	 */
 	if (spin_trylock(&adapter->tx_queue_lock)) {
-		tx_cleaned = e1000_clean_tx_irq(adapter);
+		tx_clean_complete &= e1000_clean_tx_irq(adapter);
 		spin_unlock(&adapter->tx_queue_lock);
 	}
 
+#ifdef CONFIG_E1000E_MSIX
+clean_rx:
+#endif
 	adapter->clean_rx(adapter, &work_done, budget);
 
-	if (tx_cleaned)
-		work_done = budget;
-
-	/* If budget not fully consumed, exit the polling mode */
-	if (work_done < budget) {
+	/* If Tx completed and all Rx work done, exit the polling mode */
+	if ((tx_clean_complete && (work_done == 0)) || !netif_running(netdev)) {
+		netif_rx_complete(netdev, napi);
 		if (adapter->itr_setting & 3)
 			e1000_set_itr(adapter);
-		netif_rx_complete(poll_dev, napi);
-		e1000_irq_enable(adapter);
+		if (!test_bit(__E1000_DOWN, &adapter->state)) {
+#ifdef CONFIG_E1000E_MSIX
+			if (adapter->msix_entries)
+				ew32(IMS, adapter->rx_ring->ims_val);
+			else
+#endif
+				e1000_irq_enable(adapter);
+		}
+		return 0;
 	}
 
+	if (!tx_clean_complete)
+		work_done = budget;
+
 	return work_done;
 }
 
+#endif /* CONFIG_E1000E_NAPI */
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 	u32 vfta, index;
+	struct net_device *v_netdev;
 
 	/* don't update vlan cookie if already programmed */
 	if ((adapter->hw.mng_cookie.status &
@@ -1429,7 +2458,15 @@
 	index = (vid >> 5) & 0x7F;
 	vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
 	vfta |= (1 << (vid & 0x1F));
-	e1000e_write_vfta(hw, index, vfta);
+	if (hw->mac.ops.write_vfta)
+		hw->mac.ops.write_vfta(hw, index, vfta);
+	/*
+	 * Copy feature flags from netdev to the vlan netdev for this vid.
+	 * This allows things like TSO to bubble down to our vlan device.
+	 */
+	v_netdev = vlan_group_get_device(adapter->vlgrp, vid);
+	v_netdev->features |= adapter->netdev->features;
+	vlan_group_set_device(adapter->vlgrp, vid, v_netdev);
 }
 
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
@@ -1438,9 +2475,11 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 vfta, index;
 
-	e1000_irq_disable(adapter);
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		e1000_irq_disable(adapter);
 	vlan_group_set_device(adapter->vlgrp, vid, NULL);
-	e1000_irq_enable(adapter);
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		e1000_irq_enable(adapter);
 
 	if ((adapter->hw.mng_cookie.status &
 	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
@@ -1454,7 +2493,8 @@
 	index = (vid >> 5) & 0x7F;
 	vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
 	vfta &= ~(1 << (vid & 0x1F));
-	e1000e_write_vfta(hw, index, vfta);
+	if (hw->mac.ops.write_vfta)
+		hw->mac.ops.write_vfta(hw, index, vfta);
 }
 
 static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
@@ -1491,7 +2531,8 @@
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ctrl, rctl;
 
-	e1000_irq_disable(adapter);
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		e1000_irq_disable(adapter);
 	adapter->vlgrp = grp;
 
 	if (grp) {
@@ -1528,7 +2569,8 @@
 		}
 	}
 
-	e1000_irq_enable(adapter);
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		e1000_irq_enable(adapter);
 }
 
 static void e1000_restore_vlan(struct e1000_adapter *adapter)
@@ -1557,12 +2599,11 @@
 
 	manc = er32(MANC);
 
-	/* disable hardware interception of ARP */
-	manc &= ~(E1000_MANC_ARP_EN);
-
-	/* enable receiving management packets to the host. this will probably
+	/*
+	 * enable receiving management packets to the host. this will probably
 	 * generate destination unreachable messages from the host OS, but
-	 * the packets will be handled on SMBUS */
+	 * the packets will be handled on SMBUS
+	 */
 	manc |= E1000_MANC_EN_MNG2HOST;
 	manc2h = er32(MANC2H);
 #define E1000_MNG2HOST_PORT_623 (1 << 5)
@@ -1590,13 +2631,13 @@
 	/* Setup the HW Tx Head and Tail descriptor pointers */
 	tdba = tx_ring->dma;
 	tdlen = tx_ring->count * sizeof(struct e1000_tx_desc);
-	ew32(TDBAL, (tdba & DMA_32BIT_MASK));
-	ew32(TDBAH, (tdba >> 32));
-	ew32(TDLEN, tdlen);
-	ew32(TDH, 0);
-	ew32(TDT, 0);
-	tx_ring->head = E1000_TDH;
-	tx_ring->tail = E1000_TDT;
+	ew32(TDBAL(0), (tdba & DMA_32BIT_MASK));
+	ew32(TDBAH(0), (tdba >> 32));
+	ew32(TDLEN(0), tdlen);
+	ew32(TDH(0), 0);
+	ew32(TDT(0), 0);
+	tx_ring->head = E1000_TDH(0);
+	tx_ring->tail = E1000_TDT(0);
 
 	/* Set the default values for the Tx Inter Packet Gap timer */
 	tipg = DEFAULT_82543_TIPG_IPGT_COPPER;          /*  8  */
@@ -1612,7 +2653,7 @@
 
 	/* Set the Tx Interrupt Delay register */
 	ew32(TIDV, adapter->tx_int_delay);
-	/* tx irq moderation */
+	/* Tx irq moderation */
 	ew32(TADV, adapter->tx_abs_int_delay);
 
 	/* Program the Transmit Control Register */
@@ -1622,25 +2663,27 @@
 		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
 
 	if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
-		tarc = er32(TARC0);
-		/* set the speed mode bit, we'll clear it if we're not at
-		 * gigabit link later */
+		tarc = er32(TARC(0));
+		/*
+		 * set the speed mode bit, we'll clear it if we're not at
+		 * gigabit link later
+		 */
 #define SPEED_MODE_BIT (1 << 21)
 		tarc |= SPEED_MODE_BIT;
-		ew32(TARC0, tarc);
+		ew32(TARC(0), tarc);
 	}
 
 	/* errata: program both queues to unweighted RR */
 	if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
-		tarc = er32(TARC0);
+		tarc = er32(TARC(0));
 		tarc |= 1;
-		ew32(TARC0, tarc);
-		tarc = er32(TARC1);
+		ew32(TARC(0), tarc);
+		tarc = er32(TARC(1));
 		tarc |= 1;
-		ew32(TARC1, tarc);
+		ew32(TARC(1), tarc);
 	}
 
-	e1000e_config_collision_dist(hw);
+	hw->mac.ops.config_collision_dist(hw);
 
 	/* Setup Transmit Descriptor Settings for eop descriptor */
 	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
@@ -1736,17 +2779,21 @@
 	 * a lot of memory, since we allocate 3 pages at all times
 	 * per packet.
 	 */
-	adapter->rx_ps_pages = 0;
 	pages = PAGE_USE_COUNT(adapter->netdev->mtu);
-	if ((pages <= 3) && (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
+	if (!(adapter->flags & FLAG_IS_ICH) && (pages <= 3) &&
+	    (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
 		adapter->rx_ps_pages = pages;
+	else
+		adapter->rx_ps_pages = 0;
 
 	if (adapter->rx_ps_pages) {
 		/* Configure extra packet-split registers */
 		rfctl = er32(RFCTL);
 		rfctl |= E1000_RFCTL_EXTEN;
-		/* disable packet split support for IPv6 extension headers,
-		 * because some malformed IPv6 headers can hang the RX */
+		/*
+		 * disable packet split support for IPv6 extension headers,
+		 * because some malformed IPv6 headers can hang the Rx
+		 */
 		rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
 			  E1000_RFCTL_NEW_IPV6_EXT_DIS);
 
@@ -1775,6 +2822,8 @@
 	}
 
 	ew32(RCTL, rctl);
+	/* just started the receive unit, no need to restart */
+	adapter->flags &= ~FLAG_RX_RESTART_NOW;
 }
 
 /**
@@ -1796,9 +2845,14 @@
 			sizeof(union e1000_rx_desc_packet_split);
 		adapter->clean_rx = e1000_clean_rx_irq_ps;
 		adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
+#ifdef CONFIG_E1000E_NAPI
+	} else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) {
+		rdlen = rx_ring->count * sizeof(struct e1000_rx_desc);
+		adapter->clean_rx = e1000_clean_jumbo_rx_irq;
+		adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
+#endif
 	} else {
-		rdlen = rx_ring->count *
-			sizeof(struct e1000_rx_desc);
+		rdlen = rx_ring->count * sizeof(struct e1000_rx_desc);
 		adapter->clean_rx = e1000_clean_rx_irq;
 		adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
 	}
@@ -1815,36 +2869,41 @@
 	/* irq moderation */
 	ew32(RADV, adapter->rx_abs_int_delay);
 	if (adapter->itr_setting != 0)
-		ew32(ITR,
-			1000000000 / (adapter->itr * 256));
+		ew32(ITR, 1000000000 / (adapter->itr * 256));
 
 	ctrl_ext = er32(CTRL_EXT);
 	/* Reset delay timers after every interrupt */
 	ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+#ifdef CONFIG_E1000E_NAPI
 	/* Auto-Mask interrupts upon ICR access */
 	ctrl_ext |= E1000_CTRL_EXT_IAME;
 	ew32(IAM, 0xffffffff);
+#endif
 	ew32(CTRL_EXT, ctrl_ext);
 	e1e_flush();
 
-	/* Setup the HW Rx Head and Tail Descriptor Pointers and
-	 * the Base and Length of the Rx Descriptor Ring */
+	/*
+	 * Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring
+	 */
 	rdba = rx_ring->dma;
-	ew32(RDBAL, (rdba & DMA_32BIT_MASK));
-	ew32(RDBAH, (rdba >> 32));
-	ew32(RDLEN, rdlen);
-	ew32(RDH, 0);
-	ew32(RDT, 0);
-	rx_ring->head = E1000_RDH;
-	rx_ring->tail = E1000_RDT;
+	ew32(RDBAL(0), (rdba & DMA_32BIT_MASK));
+	ew32(RDBAH(0), (rdba >> 32));
+	ew32(RDLEN(0), rdlen);
+	ew32(RDH(0), 0);
+	ew32(RDT(0), 0);
+	rx_ring->head = E1000_RDH(0);
+	rx_ring->tail = E1000_RDT(0);
 
 	/* Enable Receive Checksum Offload for TCP and UDP */
 	rxcsum = er32(RXCSUM);
 	if (adapter->flags & FLAG_RX_CSUM_ENABLED) {
 		rxcsum |= E1000_RXCSUM_TUOFL;
 
-		/* IPv4 payload checksum for UDP fragments must be
-		 * used in conjunction with packet-split. */
+		/*
+		 * IPv4 payload checksum for UDP fragments must be
+		 * used in conjunction with packet-split.
+		 */
 		if (adapter->rx_ps_pages)
 			rxcsum |= E1000_RXCSUM_IPPCSE;
 	} else {
@@ -1853,41 +2912,33 @@
 	}
 	ew32(RXCSUM, rxcsum);
 
-	/* Enable early receives on supported devices, only takes effect when
+	/*
+	 * Enable early receives on supported devices, only takes effect when
 	 * packet size is equal or larger than the specified value (in 8 byte
-	 * units), e.g. using jumbo frames when setting to E1000_ERT_2048 */
+	 * units), e.g. using jumbo frames when setting to E1000_ERT_2048
+	 */
 	if ((adapter->flags & FLAG_HAS_ERT) &&
-	    (adapter->netdev->mtu > ETH_DATA_LEN))
-		ew32(ERT, E1000_ERT_2048);
+	    (adapter->netdev->mtu > ETH_DATA_LEN)) {
+		u32 rxdctl = er32(RXDCTL(0));
+		ew32(RXDCTL(0), rxdctl | 0x3);
+		ew32(ERT, E1000_ERT_2048 | (1 << 13));
+		/*
+		 * With jumbo frames and early-receive enabled, excessive
+		 * C4->C2 latencies result in dropped transactions.
+		 */
+		pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
+					  e1000e_driver_name, 55);
+	} else {
+		pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
+					  e1000e_driver_name,
+					  PM_QOS_DEFAULT_VALUE);
+	}
 
 	/* Enable Receives */
 	ew32(RCTL, rctl);
 }
 
 /**
- *  e1000_mc_addr_list_update - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *  @rar_used_count: the first RAR register free to program
- *  @rar_count: total number of supported Receive Address Registers
- *
- *  Updates the Receive Address Registers and Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- *  The parameter rar_count will usually be hw->mac.rar_entry_count
- *  unless there are workarounds that change this.  Currently no func pointer
- *  exists and all implementations are handled in the generic version of this
- *  function.
- **/
-static void e1000_mc_addr_list_update(struct e1000_hw *hw, u8 *mc_addr_list,
-			       u32 mc_addr_count, u32 rar_used_count,
-			       u32 rar_count)
-{
-	hw->mac.ops.mc_addr_list_update(hw, mc_addr_list, mc_addr_count,
-				        rar_used_count, rar_count);
-}
-
-/**
  * e1000_set_multi - Multicast and Promiscuous mode set
  * @netdev: network interface device structure
  *
@@ -1937,21 +2988,21 @@
 			mc_ptr = mc_ptr->next;
 		}
 
-		e1000_mc_addr_list_update(hw, mta_list, i, 1,
-					  mac->rar_entry_count);
+		hw->mac.ops.update_mc_addr_list(hw, mta_list, i, 1,
+		                                mac->rar_entry_count);
 		kfree(mta_list);
 	} else {
 		/*
 		 * if we're called from probe, we might not have
 		 * anything to do here, so clear out the list
 		 */
-		e1000_mc_addr_list_update(hw, NULL, 0, 1,
-					  mac->rar_entry_count);
+		hw->mac.ops.update_mc_addr_list(hw, NULL, 0, 1,
+		                                mac->rar_entry_count);
 	}
 }
 
 /**
- * e1000_configure - configure the hardware for RX and TX
+ * e1000_configure - configure the hardware for Rx and Tx
  * @adapter: private board structure
  **/
 static void e1000_configure(struct e1000_adapter *adapter)
@@ -1964,67 +3015,7 @@
 	e1000_configure_tx(adapter);
 	e1000_setup_rctl(adapter);
 	e1000_configure_rx(adapter);
-	adapter->alloc_rx_buf(adapter,
-			      e1000_desc_unused(adapter->rx_ring));
-}
-
-/**
- * e1000e_power_up_phy - restore link in case the phy was powered down
- * @adapter: address of board private structure
- *
- * The phy may be powered down to save power and turn off link when the
- * driver is unloaded and wake on lan is not enabled (among others)
- * *** this routine MUST be followed by a call to e1000e_reset ***
- **/
-void e1000e_power_up_phy(struct e1000_adapter *adapter)
-{
-	u16 mii_reg = 0;
-
-	/* Just clear the power down bit to wake the phy back up */
-	if (adapter->hw.media_type == e1000_media_type_copper) {
-		/* according to the manual, the phy will retain its
-		 * settings across a power-down/up cycle */
-		e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg);
-		mii_reg &= ~MII_CR_POWER_DOWN;
-		e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg);
-	}
-
-	adapter->hw.mac.ops.setup_link(&adapter->hw);
-}
-
-/**
- * e1000_power_down_phy - Power down the PHY
- *
- * Power down the PHY so no link is implied when interface is down
- * The PHY cannot be powered down is management or WoL is active
- */
-static void e1000_power_down_phy(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u16 mii_reg;
-
-	/* WoL is enabled */
-	if (!adapter->wol)
-		return;
-
-	/* non-copper PHY? */
-	if (adapter->hw.media_type != e1000_media_type_copper)
-		return;
-
-	/* reset is blocked because of a SoL/IDER session */
-	if (e1000e_check_mng_mode(hw) ||
-	    e1000_check_reset_block(hw))
-		return;
-
-	/* managebility (AMT) is enabled */
-	if (er32(MANC) & E1000_MANC_SMBUS_EN)
-		return;
-
-	/* power down the PHY */
-	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
-	mii_reg |= MII_CR_POWER_DOWN;
-	e1e_wphy(hw, PHY_CONTROL, mii_reg);
-	mdelay(1);
+	adapter->alloc_rx_buf(adapter, e1000_desc_unused(adapter->rx_ring));
 }
 
 /**
@@ -2033,51 +3024,61 @@
  * This function boots the hardware and enables some settings that
  * require a configuration cycle of the hardware - those cannot be
  * set/changed during runtime. After reset the device needs to be
- * properly configured for rx, tx etc.
+ * properly configured for Rx, Tx etc.
  */
-void e1000e_reset(struct e1000_adapter *adapter)
+void e1000_reset(struct e1000_adapter *adapter)
 {
 	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct e1000_fc_info *fc = &adapter->hw.fc;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 tx_space, min_tx_space, min_rx_space;
-	u32 pba;
+	u32 pba = adapter->pba;
 	u16 hwm;
 
-	ew32(PBA, adapter->pba);
+	/* reset Packet Buffer Allocation to default */
+	ew32(PBA, pba);
 
-	if (mac->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) {
-		/* To maintain wire speed transmits, the Tx FIFO should be
+	if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) {
+		/*
+		 * To maintain wire speed transmits, the Tx FIFO should be
 		 * large enough to accommodate two full transmit packets,
 		 * rounded up to the next 1KB and expressed in KB.  Likewise,
 		 * the Rx FIFO should be large enough to accommodate at least
 		 * one full receive packet and is similarly rounded up and
-		 * expressed in KB. */
+		 * expressed in KB.
+		 */
 		pba = er32(PBA);
 		/* upper 16 bits has Tx packet buffer allocation size in KB */
 		tx_space = pba >> 16;
 		/* lower 16 bits has Rx packet buffer allocation size in KB */
 		pba &= 0xffff;
-		/* the tx fifo also stores 16 bytes of information about the tx
-		 * but don't include ethernet FCS because hardware appends it */
-		min_tx_space = (mac->max_frame_size +
+		/*
+		 * the Tx fifo also stores 16 bytes of information about the tx
+		 * but don't include ethernet FCS because hardware appends it
+		 */
+		min_tx_space = (adapter->max_frame_size +
 				sizeof(struct e1000_tx_desc) -
 				ETH_FCS_LEN) * 2;
 		min_tx_space = ALIGN(min_tx_space, 1024);
 		min_tx_space >>= 10;
 		/* software strips receive CRC, so leave room for it */
-		min_rx_space = mac->max_frame_size;
+		min_rx_space = adapter->max_frame_size;
 		min_rx_space = ALIGN(min_rx_space, 1024);
 		min_rx_space >>= 10;
 
-		/* If current Tx allocation is less than the min Tx FIFO size,
+		/*
+		 * If current Tx allocation is less than the min Tx FIFO size,
 		 * and the min Tx FIFO size is less than the current Rx FIFO
-		 * allocation, take space away from current Rx allocation */
+		 * allocation, take space away from current Rx allocation
+		 */
 		if ((tx_space < min_tx_space) &&
 		    ((min_tx_space - tx_space) < pba)) {
 			pba -= min_tx_space - tx_space;
 
-			/* if short on rx space, rx wins and must trump tx
-			 * adjustment or use Early Receive if available */
+			/*
+			 * if short on Rx space, Rx wins and must trump tx
+			 * adjustment or use Early Receive if available
+			 */
 			if ((pba < min_rx_space) &&
 			    (!(adapter->flags & FLAG_HAS_ERT)))
 				/* ERT enabled in e1000_configure_rx */
@@ -2088,59 +3089,75 @@
 	}
 
 
-	/* flow control settings */
-	/* The high water mark must be low enough to fit one full frame
+	/*
+	 * flow control settings
+	 *
+	 * The high water mark must be low enough to fit one full frame
 	 * (or the size used for early receive) above it in the Rx FIFO.
 	 * Set it to the lower of:
 	 * - 90% of the Rx FIFO size, and
 	 * - the full Rx FIFO size minus the early receive size (for parts
 	 *   with ERT support assuming ERT set to E1000_ERT_2048), or
-	 * - the full Rx FIFO size minus one full frame */
+	 * - the full Rx FIFO size minus one full frame
+	 */
 	if (adapter->flags & FLAG_HAS_ERT)
-		hwm = min(((adapter->pba << 10) * 9 / 10),
-			  ((adapter->pba << 10) - (E1000_ERT_2048 << 3)));
+		hwm = min(((pba << 10) * 9 / 10),
+			  ((pba << 10) - (E1000_ERT_2048 << 3)));
 	else
-		hwm = min(((adapter->pba << 10) * 9 / 10),
-			  ((adapter->pba << 10) - mac->max_frame_size));
+		hwm = min(((pba << 10) * 9 / 10),
+			  ((pba << 10) - adapter->max_frame_size));
 
-	mac->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
-	mac->fc_low_water = mac->fc_high_water - 8;
+	fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */
+	fc->low_water = fc->high_water - 8;
 
 	if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
-		mac->fc_pause_time = 0xFFFF;
+		fc->pause_time = 0xFFFF;
 	else
-		mac->fc_pause_time = E1000_FC_PAUSE_TIME;
-	mac->fc = mac->original_fc;
+		fc->pause_time = E1000_FC_PAUSE_TIME;
+	fc->send_xon = 1;
+	fc->type = fc->original_type;
 
 	/* Allow time for pending master requests to run */
 	mac->ops.reset_hw(hw);
+
+	/*
+	 * For parts with AMT enabled, let the firmware know
+	 * that the network interface is in control
+	 */
+	if (adapter->flags & FLAG_HAS_AMT)
+		e1000_get_hw_control(adapter);
+
 	ew32(WUC, 0);
 
 	if (mac->ops.init_hw(hw))
-		ndev_err(adapter->netdev, "Hardware Error\n");
+		e_err("Hardware Error\n");
 
 	e1000_update_mng_vlan(adapter);
 
 	/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
 	ew32(VET, ETH_P_8021Q);
 
-	e1000e_reset_adaptive(hw);
-	e1000_get_phy_info(hw);
+	e1000_reset_adaptive_generic(hw);
+	
+	if (!hw->phy.ops.get_info)
+		return;
+
+	hw->phy.ops.get_info(hw);
 
 	if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) {
 		u16 phy_data = 0;
-		/* speed up time to link by disabling smart power down, ignore
+		/*
+		 * speed up time to link by disabling smart power down, ignore
 		 * the return value of this function because there is nothing
-		 * different we would do if it failed */
-		e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+		 * different we would do if it failed
+		 */
+		hw->phy.ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
 		phy_data &= ~IGP02E1000_PM_SPD;
-		e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+		hw->phy.ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
 	}
-
-	e1000_release_manageability(adapter);
 }
 
-int e1000e_up(struct e1000_adapter *adapter)
+int e1000_up(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 
@@ -2149,7 +3166,13 @@
 
 	clear_bit(__E1000_DOWN, &adapter->state);
 
+#ifdef CONFIG_E1000E_NAPI
 	napi_enable(&adapter->napi);
+#endif
+#ifdef CONFIG_E1000E_MSIX
+	if (adapter->msix_entries)
+		e1000_configure_msix(adapter);
+#endif /* CONFIG_E1000E_MSIX */
 	e1000_irq_enable(adapter);
 
 	/* fire a link change interrupt to start the watchdog */
@@ -2157,14 +3180,16 @@
 	return 0;
 }
 
-void e1000e_down(struct e1000_adapter *adapter)
+void e1000_down(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 tctl, rctl;
 
-	/* signal that we're down so the interrupt handler does not
-	 * reschedule our watchdog timer */
+	/*
+	 * signal that we're down so the interrupt handler does not
+	 * reschedule our watchdog timer
+	 */
 	set_bit(__E1000_DOWN, &adapter->state);
 
 	/* disable receives in the hardware */
@@ -2182,8 +3207,10 @@
 	e1e_flush();
 	msleep(10);
 
+#ifdef CONFIG_E1000E_NAPI
 	napi_disable(&adapter->napi);
-	atomic_set(&adapter->irq_sem, 0);
+#endif
+
 	e1000_irq_disable(adapter);
 
 	del_timer_sync(&adapter->watchdog_timer);
@@ -2194,7 +3221,7 @@
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 
-	e1000e_reset(adapter);
+	e1000_reset(adapter);
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
 
@@ -2204,13 +3231,13 @@
 	 */
 }
 
-void e1000e_reinit_locked(struct e1000_adapter *adapter)
+void e1000_reinit_locked(struct e1000_adapter *adapter)
 {
 	might_sleep();
 	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
 		msleep(1);
-	e1000e_down(adapter);
-	e1000e_up(adapter);
+	e1000_down(adapter);
+	e1000_up(adapter);
 	clear_bit(__E1000_RESETTING, &adapter->state);
 }
 
@@ -2224,38 +3251,184 @@
  **/
 static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
 {
-	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
+	s32 rc;
 
 	adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN;
 	adapter->rx_ps_bsize0 = 128;
-	hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
-	hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
-	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
-	if (!adapter->tx_ring)
-		goto err;
+	/* Set various function pointers */
+	adapter->ei->init_ops(&adapter->hw);
 
-	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
-	if (!adapter->rx_ring)
-		goto err;
+	rc = adapter->hw.mac.ops.init_params(&adapter->hw);
+	if (rc)
+		return rc;
+
+	rc = adapter->hw.nvm.ops.init_params(&adapter->hw);
+	if (rc)
+		return rc;
+
+	rc = adapter->hw.phy.ops.init_params(&adapter->hw);
+	if (rc)
+		return rc;
+
+#ifdef CONFIG_E1000E_MSIX
+	e1000_set_interrupt_capability(adapter);
+
+#endif /* CONFIG_E1000E_MSIX */
+	if (e1000_alloc_queues(adapter))
+		return -ENOMEM;
 
 	spin_lock_init(&adapter->tx_queue_lock);
 
 	/* Explicitly disable IRQ since the NIC can be in any state. */
-	atomic_set(&adapter->irq_sem, 0);
 	e1000_irq_disable(adapter);
 
 	spin_lock_init(&adapter->stats_lock);
 
 	set_bit(__E1000_DOWN, &adapter->state);
 	return 0;
+}
 
-err:
-	ndev_err(netdev, "Unable to allocate memory for queues\n");
-	kfree(adapter->rx_ring);
-	kfree(adapter->tx_ring);
-	return -ENOMEM;
+/**
+ * e1000_intr_msi_test - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr_msi_test(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 icr = er32(ICR);
+
+	e_dbg("icr is %08X\n", icr);
+	if (icr & E1000_ICR_RXSEQ) {
+		adapter->flags &= ~FLAG_MSI_TEST_FAILED;
+		wmb();
+	}
+	
+	return IRQ_HANDLED;
+}
+
+/**
+ * e1000_test_msi_interrupt - Returns 0 for successful test
+ * @adapter: board private struct
+ *
+ * code flow taken from tg3.c
+ **/
+static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	int err;
+
+	/* poll_enable hasn't been called yet, so don't need disable */
+	/* clear any pending events */
+	er32(ICR);
+
+	/* free the real vector and request a test handler */
+	e1000_free_irq(adapter);
+#ifdef CONFIG_E1000E_MSIX
+	e1000_reset_interrupt_capability(adapter);
+#endif
+
+	/* Assume that the test fails, if it succeeds then the test
+	 * MSI irq handler will unset this flag */
+	adapter->flags |= FLAG_MSI_TEST_FAILED;
+
+	err = pci_enable_msi(adapter->pdev);
+	if (err)
+		goto msi_test_failed;
+
+	err = request_irq(adapter->pdev->irq, &e1000_intr_msi_test, 0,
+			  netdev->name, netdev);
+	if (err) {
+		pci_disable_msi(adapter->pdev);
+		goto msi_test_failed;
+	}
+
+	wmb();
+
+	e1000_irq_enable(adapter);
+
+	/* fire an unusual interrupt on the test handler */
+	ew32(ICS, E1000_ICS_RXSEQ);
+	e1e_flush();
+	msleep(50);
+
+	e1000_irq_disable(adapter);
+
+	rmb();
+
+	if (adapter->flags & FLAG_MSI_TEST_FAILED) {
+#ifdef CONFIG_E1000E_MSIX
+		adapter->int_mode = E1000E_INT_MODE_LEGACY;
+#endif
+		err = -EIO;
+		e_info("MSI interrupt test failed!\n");
+	}
+
+	free_irq(adapter->pdev->irq, netdev);
+	pci_disable_msi(adapter->pdev);
+
+	if (err == -EIO)
+		goto msi_test_failed;
+
+	/* okay so the test worked, restore settings */
+	e_dbg("MSI interrupt test succeeded!\n");
+msi_test_failed:
+#ifdef CONFIG_E1000E_MSIX
+	e1000_set_interrupt_capability(adapter);
+#else
+	/* restore the original vector, even if it failed */
+#endif
+	e1000_request_irq(adapter);
+	return err;
+}
+
+/**
+ * e1000_test_msi - Returns 0 if MSI test succeeds or INTx mode is restored
+ * @adapter: board private struct
+ *
+ * code flow taken from tg3.c, called with e1000 interrupts disabled.
+ **/
+static int e1000_test_msi(struct e1000_adapter *adapter)
+{
+	int err;
+	u16 pci_cmd;
+
+	if (!(adapter->flags & FLAG_MSI_ENABLED))
+		return 0;
+
+	/* disable SERR in case the MSI write causes a master abort */
+	pci_read_config_word(adapter->pdev, PCI_COMMAND, &pci_cmd);
+	pci_write_config_word(adapter->pdev, PCI_COMMAND,
+			      pci_cmd & ~PCI_COMMAND_SERR);
+
+	err = e1000_test_msi_interrupt(adapter);
+
+	/* restore previous setting of command word */
+	pci_write_config_word(adapter->pdev, PCI_COMMAND, pci_cmd);
+
+	/* success ! */
+	if (!err)
+		return 0;
+
+	/* EIO means MSI test failed */
+	if (err != -EIO)
+		return err;
+
+	/* back to INTx mode */
+	e_warn("MSI interrupt test failed, using legacy interrupt.\n");
+
+	e1000_free_irq(adapter);
+
+	err = e1000_request_irq(adapter);
+
+	return err;
 }
 
 /**
@@ -2281,42 +3454,63 @@
 		return -EBUSY;
 
 	/* allocate transmit descriptors */
-	err = e1000e_setup_tx_resources(adapter);
+	err = e1000_setup_tx_resources(adapter);
 	if (err)
 		goto err_setup_tx;
 
 	/* allocate receive descriptors */
-	err = e1000e_setup_rx_resources(adapter);
+	err = e1000_setup_rx_resources(adapter);
 	if (err)
 		goto err_setup_rx;
 
-	e1000e_power_up_phy(adapter);
+	e1000_power_up_phy(hw);
 
 	adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
 	if ((adapter->hw.mng_cookie.status &
 	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
 		e1000_update_mng_vlan(adapter);
 
-	/* If AMT is enabled, let the firmware know that the network
-	 * interface is now open */
-	if ((adapter->flags & FLAG_HAS_AMT) &&
-	    e1000e_check_mng_mode(&adapter->hw))
+	/*
+	 * If AMT is enabled, let the firmware know that the network
+	 * interface is now open
+	 */
+	if (adapter->flags & FLAG_HAS_AMT)
 		e1000_get_hw_control(adapter);
 
-	/* before we allocate an interrupt, we must be ready to handle it.
+	/*
+	 * before we allocate an interrupt, we must be ready to handle it.
 	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
 	 * as soon as we call pci_request_irq, so we have to setup our
-	 * clean_rx handler before we do so.  */
+	 * clean_rx handler before we do so.
+	 */
 	e1000_configure(adapter);
 
 	err = e1000_request_irq(adapter);
 	if (err)
 		goto err_req_irq;
 
-	/* From here on the code is the same as e1000e_up() */
+	/*
+	 * Work around PCIe errata with MSI interrupts causing some chipsets to
+	 * ignore e1000e MSI messages, which means we need to test our MSI
+	 * interrupt now
+	 */
+#ifdef CONFIG_E1000E_MSIX
+	if (adapter->int_mode != E1000E_INT_MODE_LEGACY)
+#endif
+	{
+		err = e1000_test_msi(adapter);
+		if (err) {
+			e_err("Interrupt allocation failed\n");
+			goto err_req_irq;
+		}
+	}
+
+	/* From here on the code is the same as e1000_up() */
 	clear_bit(__E1000_DOWN, &adapter->state);
 
+#ifdef CONFIG_E1000E_NAPI
 	napi_enable(&adapter->napi);
+#endif
 
 	e1000_irq_enable(adapter);
 
@@ -2327,12 +3521,13 @@
 
 err_req_irq:
 	e1000_release_hw_control(adapter);
-	e1000_power_down_phy(adapter);
-	e1000e_free_rx_resources(adapter);
+	if (!adapter->wol && hw->phy.ops.power_down)
+		hw->phy.ops.power_down(hw);
+	e1000_free_rx_resources(adapter);
 err_setup_rx:
-	e1000e_free_tx_resources(adapter);
+	e1000_free_tx_resources(adapter);
 err_setup_tx:
-	e1000e_reset(adapter);
+	e1000_reset(adapter);
 
 	return err;
 }
@@ -2351,27 +3546,32 @@
 static int e1000_close(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 
 	WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
-	e1000e_down(adapter);
-	e1000_power_down_phy(adapter);
+	e1000_down(adapter);
+	if (!adapter->wol && hw->phy.ops.power_down)
+		hw->phy.ops.power_down(hw);
 	e1000_free_irq(adapter);
 
-	e1000e_free_tx_resources(adapter);
-	e1000e_free_rx_resources(adapter);
+	e1000_free_tx_resources(adapter);
+	e1000_free_rx_resources(adapter);
 
-	/* kill manageability vlan ID if supported, but not if a vlan with
-	 * the same ID is registered on the host OS (let 8021q kill it) */
+	/*
+	 * kill manageability vlan ID if supported, but not if a vlan with
+	 * the same ID is registered on the host OS (let 8021q kill it)
+	 */
 	if ((adapter->hw.mng_cookie.status &
 			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
 	     !(adapter->vlgrp &&
 	       vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
 		e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
 
-	/* If AMT is enabled, let the firmware know that the network
-	 * interface is now closed */
-	if ((adapter->flags & FLAG_HAS_AMT) &&
-	    e1000e_check_mng_mode(&adapter->hw))
+	/*
+	 * If AMT is enabled, let the firmware know that the network
+	 * interface is now closed
+	 */
+	if (adapter->flags & FLAG_HAS_AMT)
 		e1000_release_hw_control(adapter);
 
 	return 0;
@@ -2394,42 +3594,48 @@
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 	memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
 
-	e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+	adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
 
 	if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) {
 		/* activate the work around */
-		e1000e_set_laa_state_82571(&adapter->hw, 1);
+		e1000_set_laa_state_82571(&adapter->hw, 1);
 
-		/* Hold a copy of the LAA in RAR[14] This is done so that
+		/*
+		 * Hold a copy of the LAA in RAR[14] This is done so that
 		 * between the time RAR[0] gets clobbered  and the time it
 		 * gets fixed (in e1000_watchdog), the actual LAA is in one
 		 * of the RARs and no incoming packets directed to this port
 		 * are dropped. Eventually the LAA will be in RAR[0] and
-		 * RAR[14] */
-		e1000e_rar_set(&adapter->hw,
-			      adapter->hw.mac.addr,
-			      adapter->hw.mac.rar_entry_count - 1);
+		 * RAR[14]
+		 */
+		adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr,
+		                           adapter->hw.mac.rar_entry_count - 1);
 	}
 
 	return 0;
 }
 
-/* Need to wait a few seconds after link up to get diagnostic information from
- * the phy */
+/**
+ * Need to wait a few seconds after link up to get diagnostic information from
+ * the phy
+ **/
 static void e1000_update_phy_info(unsigned long data)
 {
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-	e1000_get_phy_info(&adapter->hw);
+	if (adapter->hw.phy.ops.get_info)
+		adapter->hw.phy.ops.get_info(&adapter->hw);
 }
 
 /**
- * e1000e_update_stats - Update the board statistics counters
+ * e1000_update_stats - Update the board statistics counters
  * @adapter: board private structure
  **/
-void e1000e_update_stats(struct e1000_adapter *adapter)
+void e1000_update_stats(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
+#ifdef HAVE_PCI_ERS
 	struct pci_dev *pdev = adapter->pdev;
+#endif
 	unsigned long irq_flags;
 	u16 phy_tmp;
 
@@ -2441,34 +3647,26 @@
 	 */
 	if (adapter->link_speed == 0)
 		return;
+#ifdef HAVE_PCI_ERS
 	if (pci_channel_offline(pdev))
 		return;
+#endif
 
 	spin_lock_irqsave(&adapter->stats_lock, irq_flags);
 
-	/* these counters are modified from e1000_adjust_tbi_stats,
+	/*
+	 * these counters are modified from e1000_adjust_tbi_stats,
 	 * called from the interrupt context, so they must only
 	 * be written while holding adapter->stats_lock
 	 */
 
 	adapter->stats.crcerrs += er32(CRCERRS);
 	adapter->stats.gprc += er32(GPRC);
-	adapter->stats.gorcl += er32(GORCL);
-	adapter->stats.gorch += er32(GORCH);
+	adapter->stats.gorc += er32(GORCL);
+	er32(GORCH); /* Clear gorc */
 	adapter->stats.bprc += er32(BPRC);
 	adapter->stats.mprc += er32(MPRC);
-	adapter->stats.roc += er32(ROC);
-
-	if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
-		adapter->stats.prc64 += er32(PRC64);
-		adapter->stats.prc127 += er32(PRC127);
-		adapter->stats.prc255 += er32(PRC255);
-		adapter->stats.prc511 += er32(PRC511);
-		adapter->stats.prc1023 += er32(PRC1023);
-		adapter->stats.prc1522 += er32(PRC1522);
-		adapter->stats.symerrs += er32(SYMERRS);
-		adapter->stats.sec += er32(SEC);
-	}
+	adapter->stats.roc += er32(ROC);
 
 	adapter->stats.mpc += er32(MPC);
 	adapter->stats.scc += er32(SCC);
@@ -2476,33 +3674,15 @@
 	adapter->stats.mcc += er32(MCC);
 	adapter->stats.latecol += er32(LATECOL);
 	adapter->stats.dc += er32(DC);
-	adapter->stats.rlec += er32(RLEC);
 	adapter->stats.xonrxc += er32(XONRXC);
 	adapter->stats.xontxc += er32(XONTXC);
 	adapter->stats.xoffrxc += er32(XOFFRXC);
 	adapter->stats.xofftxc += er32(XOFFTXC);
-	adapter->stats.fcruc += er32(FCRUC);
 	adapter->stats.gptc += er32(GPTC);
-	adapter->stats.gotcl += er32(GOTCL);
-	adapter->stats.gotch += er32(GOTCH);
+	adapter->stats.gotc += er32(GOTCL);
+	er32(GOTCH); /* Clear gotc */
 	adapter->stats.rnbc += er32(RNBC);
 	adapter->stats.ruc += er32(RUC);
-	adapter->stats.rfc += er32(RFC);
-	adapter->stats.rjc += er32(RJC);
-	adapter->stats.torl += er32(TORL);
-	adapter->stats.torh += er32(TORH);
-	adapter->stats.totl += er32(TOTL);
-	adapter->stats.toth += er32(TOTH);
-	adapter->stats.tpr += er32(TPR);
-
-	if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
-		adapter->stats.ptc64 += er32(PTC64);
-		adapter->stats.ptc127 += er32(PTC127);
-		adapter->stats.ptc255 += er32(PTC255);
-		adapter->stats.ptc511 += er32(PTC511);
-		adapter->stats.ptc1023 += er32(PTC1023);
-		adapter->stats.ptc1522 += er32(PTC1522);
-	}
 
 	adapter->stats.mptc += er32(MPTC);
 	adapter->stats.bptc += er32(BPTC);
@@ -2516,36 +3696,22 @@
 
 	adapter->stats.algnerrc += er32(ALGNERRC);
 	adapter->stats.rxerrc += er32(RXERRC);
-	adapter->stats.tncrs += er32(TNCRS);
+	if (hw->mac.type != e1000_82574)
+		adapter->stats.tncrs += er32(TNCRS);
 	adapter->stats.cexterr += er32(CEXTERR);
 	adapter->stats.tsctc += er32(TSCTC);
 	adapter->stats.tsctfc += er32(TSCTFC);
 
-	adapter->stats.iac += er32(IAC);
-
-	if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) {
-		adapter->stats.icrxoc += er32(ICRXOC);
-		adapter->stats.icrxptc += er32(ICRXPTC);
-		adapter->stats.icrxatc += er32(ICRXATC);
-		adapter->stats.ictxptc += er32(ICTXPTC);
-		adapter->stats.ictxatc += er32(ICTXATC);
-		adapter->stats.ictxqec += er32(ICTXQEC);
-		adapter->stats.ictxqmtc += er32(ICTXQMTC);
-		adapter->stats.icrxdmtc += er32(ICRXDMTC);
-	}
-
 	/* Fill out the OS statistics structure */
-	adapter->net_stats.rx_packets = adapter->stats.gprc;
-	adapter->net_stats.tx_packets = adapter->stats.gptc;
-	adapter->net_stats.rx_bytes = adapter->stats.gorcl;
-	adapter->net_stats.tx_bytes = adapter->stats.gotcl;
 	adapter->net_stats.multicast = adapter->stats.mprc;
 	adapter->net_stats.collisions = adapter->stats.colc;
 
 	/* Rx Errors */
 
-	/* RLEC on some newer hardware can be incorrect so build
-	* our own version based on RUC and ROC */
+	/*
+	 * RLEC on some newer hardware can be incorrect so build
+	 * our own version based on RUC and ROC
+	 */
 	adapter->net_stats.rx_errors = adapter->stats.rxerrc +
 		adapter->stats.crcerrs + adapter->stats.algnerrc +
 		adapter->stats.ruc + adapter->stats.roc +
@@ -2566,9 +3732,9 @@
 	/* Tx Dropped needs to be maintained elsewhere */
 
 	/* Phy Stats */
-	if (hw->media_type == e1000_media_type_copper) {
+	if (hw->phy.media_type == e1000_media_type_copper) {
 		if ((adapter->link_speed == SPEED_1000) &&
-		   (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) {
+		   (!hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
 			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
 			adapter->phy_stats.idle_errors += phy_tmp;
 		}
@@ -2582,21 +3748,128 @@
 	spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
 }
 
+#ifdef SIOCGMIIPHY
+/**
+ * e1000_phy_read_status - Update the PHY register status snapshot
+ * @adapter: board private structure
+ **/
+static void e1000_phy_read_status(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_phy_regs *phy = &adapter->phy_regs;
+	int ret_val;
+	unsigned long irq_flags;
+
+
+	spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+
+	if ((er32(STATUS) & E1000_STATUS_LU) &&
+	    (adapter->hw.phy.media_type == e1000_media_type_copper)) {
+		ret_val  = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy->bmcr);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_STATUS, &phy->bmsr);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
+		                                &phy->advertise);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, &phy->lpa);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_AUTONEG_EXP,
+		                                &phy->expansion);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_1000T_CTRL,
+		                                &phy->ctrl1000);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_1000T_STATUS,
+		                                &phy->stat1000);
+		ret_val |= hw->phy.ops.read_reg(hw, PHY_EXT_STATUS,
+		                                &phy->estatus);
+		if (ret_val)
+			e_warn("Error reading PHY register\n");
+	} else {
+		/*
+		 * Do not read PHY registers if link is not up
+		 * Set values to typical power-on defaults
+		 */
+		phy->bmcr = (BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_FULLDPLX);
+		phy->bmsr = (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL |
+		             BMSR_10HALF | BMSR_ESTATEN | BMSR_ANEGCAPABLE |
+		             BMSR_ERCAP);
+		phy->advertise = (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP |
+		                  ADVERTISE_ALL | ADVERTISE_CSMA);
+		phy->lpa = 0;
+		phy->expansion = EXPANSION_ENABLENPAGE;
+		phy->ctrl1000 = ADVERTISE_1000FULL;
+		phy->stat1000 = 0;
+		phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
+	}
+
+	spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+}
+
+#endif /* SIOCGMIIPHY */
 static void e1000_print_link_info(struct e1000_adapter *adapter)
 {
-	struct net_device *netdev = adapter->netdev;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ctrl = er32(CTRL);
 
-	ndev_info(netdev,
-		"Link is Up %d Mbps %s, Flow Control: %s\n",
-		adapter->link_speed,
-		(adapter->link_duplex == FULL_DUPLEX) ?
+	e_info("Link is Up %d Mbps %s, Flow Control: %s\n",
+	       adapter->link_speed,
+	       (adapter->link_duplex == FULL_DUPLEX) ?
 				"Full Duplex" : "Half Duplex",
-		((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
+	       ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
 				"RX/TX" :
-		((ctrl & E1000_CTRL_RFCE) ? "RX" :
-		((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+	       ((ctrl & E1000_CTRL_RFCE) ? "RX" :
+	       ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+}
+
+static bool e1000_has_link(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	bool link_active = 0;
+	s32 ret_val = 0;
+
+	/*
+	 * get_link_status is set on LSC (link status) interrupt or
+	 * Rx sequence error interrupt.  get_link_status will stay
+	 * false until the check_for_link establishes link
+	 * for copper adapters ONLY
+	 */
+	switch (hw->phy.media_type) {
+	case e1000_media_type_copper:
+		if (hw->mac.get_link_status) {
+			ret_val = hw->mac.ops.check_for_link(hw);
+			link_active = !hw->mac.get_link_status;
+		} else {
+			link_active = 1;
+		}
+		break;
+	case e1000_media_type_fiber:
+		ret_val = hw->mac.ops.check_for_link(hw);
+		link_active = !!(er32(STATUS) & E1000_STATUS_LU);
+		break;
+	case e1000_media_type_internal_serdes:
+		ret_val = hw->mac.ops.check_for_link(hw);
+		link_active = adapter->hw.mac.serdes_has_link;
+		break;
+	default:
+	case e1000_media_type_unknown:
+		break;
+	}
+
+	if ((ret_val == E1000_ERR_PHY) && (hw->phy.type == e1000_phy_igp_3) &&
+	    (er32(CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
+		/* See e1000_kmrn_lock_loss_workaround_ich8lan() */
+		e_info("Gigabit has been disabled, downgrading speed\n");
+	}
+
+	return link_active;
+}
+
+static void e1000e_enable_receives(struct e1000_adapter *adapter)
+{
+	/* make sure the receive unit is started */
+	if ((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
+	    (adapter->flags & FLAG_RX_RESTART_NOW)) {
+		struct e1000_hw *hw = &adapter->hw;
+		u32 rctl = er32(RCTL);
+		ew32(RCTL, rctl | E1000_RCTL_EN);
+		adapter->flags &= ~FLAG_RX_RESTART_NOW;
+	}
 }
 
 /**
@@ -2617,55 +3890,69 @@
 {
 	struct e1000_adapter *adapter = container_of(work,
 					struct e1000_adapter, watchdog_task);
-
 	struct net_device *netdev = adapter->netdev;
 	struct e1000_mac_info *mac = &adapter->hw.mac;
 	struct e1000_ring *tx_ring = adapter->tx_ring;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 link, tctl;
-	s32 ret_val;
 	int tx_pending = 0;
+	unsigned long timer_val;
 
-	if ((netif_carrier_ok(netdev)) &&
-	    (er32(STATUS) & E1000_STATUS_LU))
+	link = e1000_has_link(adapter);
+	if ((netif_carrier_ok(netdev)) && link) {
+		e1000e_enable_receives(adapter);
 		goto link_up;
-
-	ret_val = mac->ops.check_for_link(hw);
-	if ((ret_val == E1000_ERR_PHY) &&
-	    (adapter->hw.phy.type == e1000_phy_igp_3) &&
-	    (er32(CTRL) &
-	     E1000_PHY_CTRL_GBE_DISABLE)) {
-		/* See e1000_kmrn_lock_loss_workaround_ich8lan() */
-		ndev_info(netdev,
-			"Gigabit has been disabled, downgrading speed\n");
 	}
 
-	if ((e1000e_enable_tx_pkt_filtering(hw)) &&
+	if ((e1000_enable_tx_pkt_filtering_generic(hw)) &&
 	    (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id))
 		e1000_update_mng_vlan(adapter);
 
-	if ((adapter->hw.media_type == e1000_media_type_internal_serdes) &&
-	   !(er32(TXCW) & E1000_TXCW_ANE))
-		link = adapter->hw.mac.serdes_has_link;
-	else
-		link = er32(STATUS) & E1000_STATUS_LU;
-
 	if (link) {
 		if (!netif_carrier_ok(netdev)) {
 			bool txb2b = 1;
+#ifdef SIOCGMIIPHY
+			/* update snapshot of PHY registers on LSC */
+			e1000_phy_read_status(adapter);
+#endif
 			mac->ops.get_link_up_info(&adapter->hw,
 						   &adapter->link_speed,
 						   &adapter->link_duplex);
 			e1000_print_link_info(adapter);
-			/* tweak tx_queue_len according to speed/duplex
-			 * and adjust the timeout factor */
+
+			/*
+			 * On supported PHYs, check for duplex mismatch only
+			 * if link has autonegotiated at 10/100 half
+			 */
+			if ((hw->phy.type == e1000_phy_igp_3 ||
+			     hw->phy.type == e1000_phy_bm) &&
+			    (hw->mac.autoneg == TRUE) &&
+			    (adapter->link_speed == SPEED_10 ||
+			     adapter->link_speed == SPEED_100) &&
+			    (adapter->link_duplex == HALF_DUPLEX)) {
+				u16 autoneg_exp;
+
+				hw->phy.ops.read_reg(hw, PHY_AUTONEG_EXP,
+				                     &autoneg_exp);
+
+				if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
+					e_info("Autonegotiated half duplex but"
+					       " link partner cannot autoneg. "
+					       " Try forcing full duplex if "
+					       "link gets many collisions.");
+			}
+
+			/*
+			 * tweak tx_queue_len according to speed/duplex
+			 * and adjust the timeout factor
+			 */
 			netdev->tx_queue_len = adapter->tx_queue_len;
 			adapter->tx_timeout_factor = 1;
 			switch (adapter->link_speed) {
 			case SPEED_10:
 				txb2b = 0;
 				netdev->tx_queue_len = 10;
-				adapter->tx_timeout_factor = 14;
+				adapter->tx_timeout_factor = 16;
 				break;
 			case SPEED_100:
 				txb2b = 0;
@@ -2674,67 +3961,64 @@
 				break;
 			}
 
-			/* workaround: re-program speed mode bit after
-			 * link-up event */
+			/*
+			 * workaround: re-program speed mode bit after
+			 * link-up event
+			 */
 			if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) &&
 			    !txb2b) {
 				u32 tarc0;
-				tarc0 = er32(TARC0);
+				tarc0 = er32(TARC(0));
 				tarc0 &= ~SPEED_MODE_BIT;
-				ew32(TARC0, tarc0);
+				ew32(TARC(0), tarc0);
 			}
 
-			/* disable TSO for pcie and 10/100 speeds, to avoid
-			 * some hardware issues */
+#ifdef NETIF_F_TSO
+			/*
+			 * disable TSO for pcie and 10/100 speeds, to avoid
+			 * some hardware issues
+			 */
 			if (!(adapter->flags & FLAG_TSO_FORCE)) {
 				switch (adapter->link_speed) {
 				case SPEED_10:
 				case SPEED_100:
-					ndev_info(netdev,
-					"10/100 speed: disabling TSO\n");
+					e_info("10/100 speed: disabling TSO\n");
 					netdev->features &= ~NETIF_F_TSO;
+#ifdef NETIF_F_TSO6
 					netdev->features &= ~NETIF_F_TSO6;
+#endif
 					break;
 				case SPEED_1000:
 					netdev->features |= NETIF_F_TSO;
+#ifdef NETIF_F_TSO6
 					netdev->features |= NETIF_F_TSO6;
+#endif
 					break;
 				default:
 					/* oops */
 					break;
 				}
 			}
+#endif
 
-			/* enable transmits in the hardware, need to do this
-			 * after setting TARC0 */
+			/*
+			 * enable transmits in the hardware, need to do this
+			 * after setting TARC(0)
+			 */
 			tctl = er32(TCTL);
 			tctl |= E1000_TCTL_EN;
 			ew32(TCTL, tctl);
 
 			netif_carrier_on(netdev);
 			netif_wake_queue(netdev);
-
-			if (!test_bit(__E1000_DOWN, &adapter->state))
-				mod_timer(&adapter->phy_info_timer,
-					  round_jiffies(jiffies + 2 * HZ));
-		} else {
-			/* make sure the receive unit is started */
-			if (adapter->flags & FLAG_RX_NEEDS_RESTART) {
-				u32 rctl = er32(RCTL);
-				ew32(RCTL, rctl |
-						E1000_RCTL_EN);
-			}
 		}
 	} else {
 		if (netif_carrier_ok(netdev)) {
 			adapter->link_speed = 0;
 			adapter->link_duplex = 0;
-			ndev_info(netdev, "Link is Down\n");
+			e_info("Link is Down\n");
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
-			if (!test_bit(__E1000_DOWN, &adapter->state))
-				mod_timer(&adapter->phy_info_timer,
-					  round_jiffies(jiffies + 2 * HZ));
 
 			if (adapter->flags & FLAG_RX_NEEDS_RESTART)
 				schedule_work(&adapter->reset_task);
@@ -2742,48 +4026,60 @@
 	}
 
 link_up:
-	e1000e_update_stats(adapter);
+	e1000_update_stats(adapter);
 
 	mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
 	adapter->tpt_old = adapter->stats.tpt;
 	mac->collision_delta = adapter->stats.colc - adapter->colc_old;
 	adapter->colc_old = adapter->stats.colc;
 
-	adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
-	adapter->gorcl_old = adapter->stats.gorcl;
-	adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
-	adapter->gotcl_old = adapter->stats.gotcl;
+	adapter->gorc = adapter->stats.gorc - adapter->gorc_old;
+	adapter->gorc_old = adapter->stats.gorc;
+	adapter->gotc = adapter->stats.gotc - adapter->gotc_old;
+	adapter->gotc_old = adapter->stats.gotc;
 
-	e1000e_update_adaptive(&adapter->hw);
+	e1000_update_adaptive_generic(&adapter->hw);
 
 	if (!netif_carrier_ok(netdev)) {
 		tx_pending = (e1000_desc_unused(tx_ring) + 1 <
 			       tx_ring->count);
 		if (tx_pending) {
-			/* We've lost link, so the controller stops DMA,
+			/*
+			 * We've lost link, so the controller stops DMA,
 			 * but we've got queued Tx work that's never going
 			 * to get done, so reset controller to flush Tx.
-			 * (Do the reset outside of interrupt context). */
+			 * (Do the reset outside of interrupt context).
+			 */
 			adapter->tx_timeout_count++;
 			schedule_work(&adapter->reset_task);
 		}
 	}
 
-	/* Cause software interrupt to ensure rx ring is cleaned */
-	ew32(ICS, E1000_ICS_RXDMT0);
+	/* Cause software interrupt to ensure Rx ring is cleaned */
+#ifdef CONFIG_E1000E_MSIX
+	if (adapter->msix_entries)
+		ew32(ICS, adapter->rx_ring->ims_val);
+	else
+#endif
+		ew32(ICS, E1000_ICS_RXDMT0);
 
 	/* Force detection of hung controller every watchdog period */
 	adapter->detect_tx_hung = 1;
 
-	/* With 82571 controllers, LAA may be overwritten due to controller
-	 * reset from the other port. Set the appropriate LAA in RAR[0] */
-	if (e1000e_get_laa_state_82571(hw))
-		e1000e_rar_set(hw, adapter->hw.mac.addr, 0);
+	/*
+	 * With 82571 controllers, LAA may be overwritten due to controller
+	 * reset from the other port. Set the appropriate LAA in RAR[0]
+	 */
+	if (e1000_get_laa_state_82571(hw))
+		hw->mac.ops.rar_set(hw, adapter->hw.mac.addr, 0);
 
 	/* Reset the timer */
-	if (!test_bit(__E1000_DOWN, &adapter->state))
-		mod_timer(&adapter->watchdog_timer,
-			  round_jiffies(jiffies + 2 * HZ));
+	if (!test_bit(__E1000_DOWN, &adapter->state)) {
+		timer_val = jiffies + usecs_to_jiffies(adapter->stats_freq_us);
+		if (adapter->stats_freq_us > 1000000)
+			timer_val = round_jiffies(timer_val);
+		mod_timer(&adapter->watchdog_timer, timer_val);
+	}
 }
 
 #define E1000_TX_FLAGS_CSUM		0x00000001
@@ -2796,6 +4092,7 @@
 static int e1000_tso(struct e1000_adapter *adapter,
 		     struct sk_buff *skb)
 {
+#ifdef NETIF_F_TSO
 	struct e1000_ring *tx_ring = adapter->tx_ring;
 	struct e1000_context_desc *context_desc;
 	struct e1000_buffer *buffer_info;
@@ -2805,68 +4102,72 @@
 	u8 ipcss, ipcso, tucss, tucso, hdr_len;
 	int err;
 
-	if (skb_is_gso(skb)) {
-		if (skb_header_cloned(skb)) {
-			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-			if (err)
-				return err;
-		}
-
-		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
-		mss = skb_shinfo(skb)->gso_size;
-		if (skb->protocol == htons(ETH_P_IP)) {
-			struct iphdr *iph = ip_hdr(skb);
-			iph->tot_len = 0;
-			iph->check = 0;
-			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
-								 iph->daddr, 0,
-								 IPPROTO_TCP,
-								 0);
-			cmd_length = E1000_TXD_CMD_IP;
-			ipcse = skb_transport_offset(skb) - 1;
-		} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
-			ipv6_hdr(skb)->payload_len = 0;
-			tcp_hdr(skb)->check =
-				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-						 &ipv6_hdr(skb)->daddr,
-						 0, IPPROTO_TCP, 0);
-			ipcse = 0;
-		}
-		ipcss = skb_network_offset(skb);
-		ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data;
-		tucss = skb_transport_offset(skb);
-		tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
-		tucse = 0;
-
-		cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
-			       E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
+	if (!skb_is_gso(skb))
+		return 0;
 
-		i = tx_ring->next_to_use;
-		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
-		buffer_info = &tx_ring->buffer_info[i];
+	if (skb_header_cloned(skb)) {
+		err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+		if (err)
+			return err;
+	}
 
-		context_desc->lower_setup.ip_fields.ipcss  = ipcss;
-		context_desc->lower_setup.ip_fields.ipcso  = ipcso;
-		context_desc->lower_setup.ip_fields.ipcse  = cpu_to_le16(ipcse);
-		context_desc->upper_setup.tcp_fields.tucss = tucss;
-		context_desc->upper_setup.tcp_fields.tucso = tucso;
-		context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
-		context_desc->tcp_seg_setup.fields.mss     = cpu_to_le16(mss);
-		context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
-		context_desc->cmd_and_length = cpu_to_le32(cmd_length);
+	hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+	mss = skb_shinfo(skb)->gso_size;
+	if (skb->protocol == htons(ETH_P_IP)) {
+		struct iphdr *iph = ip_hdr(skb);
+		iph->tot_len = 0;
+		iph->check = 0;
+		tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								iph->daddr, 0,
+								IPPROTO_TCP,
+								0);
+		cmd_length = E1000_TXD_CMD_IP;
+		ipcse = skb_transport_offset(skb) - 1;
+#ifdef NETIF_F_TSO6
+	} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+		ipv6_hdr(skb)->payload_len = 0;
+		tcp_hdr(skb)->check =
+			~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						&ipv6_hdr(skb)->daddr,
+						0, IPPROTO_TCP, 0);
+		ipcse = 0;
+#endif
+	}
+	ipcss = skb_network_offset(skb);
+	ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data;
+	tucss = skb_transport_offset(skb);
+	tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
+	tucse = 0;
 
-		buffer_info->time_stamp = jiffies;
-		buffer_info->next_to_watch = i;
+	cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
+			E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
 
-		i++;
-		if (i == tx_ring->count)
-			i = 0;
-		tx_ring->next_to_use = i;
+	i = tx_ring->next_to_use;
+	context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+	buffer_info = &tx_ring->buffer_info[i];
 
-		return 1;
-	}
+	context_desc->lower_setup.ip_fields.ipcss  = ipcss;
+	context_desc->lower_setup.ip_fields.ipcso  = ipcso;
+	context_desc->lower_setup.ip_fields.ipcse  = cpu_to_le16(ipcse);
+	context_desc->upper_setup.tcp_fields.tucss = tucss;
+	context_desc->upper_setup.tcp_fields.tucso = tucso;
+	context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
+	context_desc->tcp_seg_setup.fields.mss     = cpu_to_le16(mss);
+	context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
+	context_desc->cmd_and_length = cpu_to_le32(cmd_length);
+
+	buffer_info->time_stamp = jiffies;
+	buffer_info->next_to_watch = i;
+
+	i++;
+	if (i == tx_ring->count)
+		i = 0;
+	tx_ring->next_to_use = i;
 
+	return 1;
+#else
 	return 0;
+#endif
 }
 
 static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
@@ -2876,34 +4177,49 @@
 	struct e1000_buffer *buffer_info;
 	unsigned int i;
 	u8 css;
+	u32 cmd_len = E1000_TXD_CMD_DEXT;
 
-	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		css = skb_transport_offset(skb);
-
-		i = tx_ring->next_to_use;
-		buffer_info = &tx_ring->buffer_info[i];
-		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+	if (skb->ip_summed != CHECKSUM_PARTIAL)
+		return 0;
 
-		context_desc->lower_setup.ip_config = 0;
-		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso =
-					css + skb->csum_offset;
-		context_desc->upper_setup.tcp_fields.tucse = 0;
-		context_desc->tcp_seg_setup.data = 0;
-		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+		if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+			cmd_len |= E1000_TXD_CMD_TCP;
+		break;
+	case __constant_htons(ETH_P_IPV6):
+		/* XXX not handling all IPV6 headers */
+		if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+			cmd_len |= E1000_TXD_CMD_TCP;
+		break;
+	default:
+		if (unlikely(net_ratelimit())) 
+			e_warn("checksum_partial proto=%x!\n", skb->protocol);
+		break;
+	}
 
-		buffer_info->time_stamp = jiffies;
-		buffer_info->next_to_watch = i;
+  	css = skb_transport_offset(skb);
 
-		i++;
-		if (i == tx_ring->count)
-			i = 0;
-		tx_ring->next_to_use = i;
+	i = tx_ring->next_to_use;
+	buffer_info = &tx_ring->buffer_info[i];
+	context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
 
-		return 1;
-	}
+	context_desc->lower_setup.ip_config = 0;
+	context_desc->upper_setup.tcp_fields.tucss = css;
+	context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
+	context_desc->upper_setup.tcp_fields.tucse = 0;
+	context_desc->tcp_seg_setup.data = 0;
+	context_desc->cmd_and_length = cpu_to_le32(cmd_len);
+
+	buffer_info->time_stamp = jiffies;
+	buffer_info->next_to_watch = i;
+
+	i++;
+	if (i == tx_ring->count)
+		i = 0;
+	tx_ring->next_to_use = i;
 
-	return 0;
+	return 1;
 }
 
 #define E1000_MAX_PER_TXD	8192
@@ -2926,11 +4242,6 @@
 		buffer_info = &tx_ring->buffer_info[i];
 		size = min(len, max_per_txd);
 
-		/* Workaround for premature desc write-backs
-		 * in TSO mode.  Append 4-byte sentinel desc */
-		if (mss && !nr_frags && size == len && size > 8)
-			size -= 4;
-
 		buffer_info->length = size;
 		/* set time_stamp *before* dma to help avoid a possible race */
 		buffer_info->time_stamp = jiffies;
@@ -2964,10 +4275,6 @@
 		while (len) {
 			buffer_info = &tx_ring->buffer_info[i];
 			size = min(len, max_per_txd);
-			/* Workaround for premature desc write-backs
-			 * in TSO mode.  Append 4-byte sentinel desc */
-			if (mss && f == (nr_frags-1) && size == len && size > 8)
-				size -= 4;
 
 			buffer_info->length = size;
 			buffer_info->time_stamp = jiffies;
@@ -3052,16 +4359,20 @@
 
 	tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
 
-	/* Force memory writes to complete before letting h/w
+	/*
+	 * Force memory writes to complete before letting h/w
 	 * know there are new descriptors to fetch.  (Only
 	 * applicable for weak-ordered memory model archs,
-	 * such as IA-64). */
+	 * such as IA-64).
+	 */
 	wmb();
 
 	tx_ring->next_to_use = i;
 	writel(i, adapter->hw.hw_addr + tx_ring->tail);
-	/* we need this if more than one processor can write to our tail
-	 * at a time, it synchronizes IO on IA64/Altix systems */
+	/*
+	 * we need this if more than one processor can write to our tail
+	 * at a time, it synchronizes IO on IA64/Altix systems
+	 */
 	mmiowb();
 }
 
@@ -3098,7 +4409,8 @@
 
 		offset = (u8 *)udp + 8 - skb->data;
 		length = skb->len - offset;
-		return e1000e_mng_write_dhcp_info(hw, (u8 *)udp + 8, length);
+		return e1000_mng_write_dhcp_info_generic(hw, (u8 *)udp + 8,
+		                                         length);
 	}
 
 	return 0;
@@ -3109,13 +4421,17 @@
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 
 	netif_stop_queue(netdev);
-	/* Herbert's original patch had:
+	/*
+	 * Herbert's original patch had:
 	 *  smp_mb__after_netif_stop_queue();
-	 * but since that doesn't exist yet, just open code it. */
+	 * but since that doesn't exist yet, just open code it.
+	 */
 	smp_mb();
 
-	/* We need to check again in a case another CPU has just
-	 * made room available. */
+	/*
+	 * We need to check again in a case another CPU has just
+	 * made room available.
+	 */
 	if (e1000_desc_unused(adapter->tx_ring) < size)
 		return -EBUSY;
 
@@ -3144,9 +4460,11 @@
 	unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
 	unsigned int tx_flags = 0;
 	unsigned int len = skb->len - skb->data_len;
+#ifdef NETIF_F_LLTX
 	unsigned long irq_flags;
+#endif
 	unsigned int nr_frags;
-	unsigned int mss;
+	unsigned int mss = 0;
 	int count = 0;
 	int tso;
 	unsigned int f;
@@ -3161,29 +4479,37 @@
 		return NETDEV_TX_OK;
 	}
 
+#ifdef NETIF_F_TSO
 	mss = skb_shinfo(skb)->gso_size;
-	/* The controller does a simple calculation to
+	/*
+	 * The controller does a simple calculation to
 	 * make sure there is enough room in the FIFO before
 	 * initiating the DMA for each buffer.  The calc is:
 	 * 4 = ceil(buffer len/mss).  To make sure we don't
 	 * overrun the FIFO, adjust the max buffer len if mss
-	 * drops. */
+	 * drops.
+	 */
 	if (mss) {
 		u8 hdr_len;
 		max_per_txd = min(mss << 2, max_per_txd);
 		max_txd_pwr = fls(max_per_txd) - 1;
 
-		/* TSO Workaround for 82571/2/3 Controllers -- if skb->data
-		* points to just header, pull a few bytes of payload from
-		* frags into skb->data */
+		/*
+		 * TSO Workaround for 82571/2/3 Controllers -- if skb->data
+		 * points to just header, pull a few bytes of payload from
+		 * frags into skb->data
+		 */
 		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+		/*
+		 * we do this workaround for ES2LAN, but it is un-necessary,
+		 * avoiding it could save a lot of cycles
+		 */
 		if (skb->data_len && (hdr_len == len)) {
 			unsigned int pull_size;
 
 			pull_size = min((unsigned int)4, skb->data_len);
 			if (!__pskb_pull_tail(skb, pull_size)) {
-				ndev_err(netdev,
-					 "__pskb_pull_tail failed.\n");
+				e_err("__pskb_pull_tail failed.\n");
 				dev_kfree_skb_any(skb);
 				return NETDEV_TX_OK;
 			}
@@ -3195,6 +4521,10 @@
 	if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
 		count++;
 	count++;
+#else
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+	count++;
+#endif
 
 	count += TXD_USE_COUNT(len, max_txd_pwr);
 
@@ -3206,14 +4536,20 @@
 	if (adapter->hw.mac.tx_pkt_filtering)
 		e1000_transfer_dhcp_info(adapter, skb);
 
+#ifdef NETIF_F_LLTX
 	if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags))
 		/* Collision - tell upper layer to requeue */
 		return NETDEV_TX_LOCKED;
+#endif
 
-	/* need: count + 2 desc gap to keep tail from touching
-	 * head, otherwise try next time */
+	/*
+	 * need: count + 2 desc gap to keep tail from touching
+	 * head, otherwise try next time
+	 */
 	if (e1000_maybe_stop_tx(netdev, count + 2)) {
+#ifdef NETIF_F_LLTX
 		spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+#endif
 		return NETDEV_TX_BUSY;
 	}
 
@@ -3225,9 +4561,11 @@
 	first = tx_ring->next_to_use;
 
 	tso = e1000_tso(adapter, skb);
-	if (tso < 0) {
+	if (unlikely(tso < 0)) {
 		dev_kfree_skb_any(skb);
+#ifdef NETIF_F_LLTX
 		spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+#endif
 		return NETDEV_TX_OK;
 	}
 
@@ -3236,17 +4574,21 @@
 	else if (e1000_tx_csum(adapter, skb))
 		tx_flags |= E1000_TX_FLAGS_CSUM;
 
-	/* Old method was to assume IPv4 packet by default if TSO was enabled.
+	/*
+	 * Old method was to assume IPv4 packet by default if TSO was enabled.
 	 * 82571 hardware supports TSO capabilities for IPv6 as well...
-	 * no longer assume, we must. */
+	 * no longer assume, we must.
+	 */
 	if (skb->protocol == htons(ETH_P_IP))
 		tx_flags |= E1000_TX_FLAGS_IPV4;
 
 	count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss);
-	if (count < 0) {
+	if (unlikely(count < 0)) {
 		/* handle pci_map_single() error in e1000_tx_map */
 		dev_kfree_skb_any(skb);
+#ifdef NETIF_F_LLTX
 		spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+#endif
 		return NETDEV_TX_OK;
 	}
 
@@ -3257,7 +4599,9 @@
 	/* Make sure there is space in the ring for the next send. */
 	e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
 
+#ifdef NETIF_F_LLTX
 	spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+#endif
 	return NETDEV_TX_OK;
 }
 
@@ -3279,7 +4623,7 @@
 	struct e1000_adapter *adapter;
 	adapter = container_of(work, struct e1000_adapter, reset_task);
 
-	e1000e_reinit_locked(adapter);
+	e1000_reinit_locked(adapter);
 }
 
 /**
@@ -3309,41 +4653,40 @@
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 
-	if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
-	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-		ndev_err(netdev, "Invalid MTU setting\n");
+	if ((new_mtu < 68) || (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+		e_err("Invalid MTU setting\n");
 		return -EINVAL;
 	}
 
 	/* Jumbo frame size limits */
 	if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
 		if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
-			ndev_err(netdev, "Jumbo Frames not supported.\n");
-			return -EINVAL;
-		}
-		if (adapter->hw.phy.type == e1000_phy_ife) {
-			ndev_err(netdev, "Jumbo Frames not supported.\n");
+			e_err("Jumbo Frames not supported.\n");
 			return -EINVAL;
 		}
 	}
 
 #define MAX_STD_JUMBO_FRAME_SIZE 9234
 	if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
-		ndev_err(netdev, "MTU > 9216 not supported.\n");
+		e_err("MTU > 9216 not supported.\n");
 		return -EINVAL;
 	}
 
 	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
 		msleep(1);
-	/* e1000e_down has a dependency on max_frame_size */
-	adapter->hw.mac.max_frame_size = max_frame;
+	/* e1000_down has a dependency on max_frame_size */
+	adapter->max_frame_size = max_frame;
 	if (netif_running(netdev))
-		e1000e_down(adapter);
+		e1000_down(adapter);
 
-	/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+	/*
+	 * NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
 	 * means we reserve 2 more, this pushes us to allocate from the next
 	 * larger slab size.
-	 * i.e. RXBUFFER_2048 --> size-4096 slab */
+	 * i.e. RXBUFFER_2048 --> size-4096 slab
+	 * However with the new *_jumbo_rx* routines, jumbo receives will use
+	 * fragmented skbs
+	 */
 
 	if (max_frame <= 256)
 		adapter->rx_buffer_len = 256;
@@ -3353,23 +4696,31 @@
 		adapter->rx_buffer_len = 1024;
 	else if (max_frame <= 2048)
 		adapter->rx_buffer_len = 2048;
+#ifdef CONFIG_E1000E_NAPI
 	else
 		adapter->rx_buffer_len = 4096;
+#else
+	else if (max_frame <= 4096)
+		adapter->rx_buffer_len = 4096;
+	else if (max_frame <= 8192)
+		adapter->rx_buffer_len = 8192;
+	else if (max_frame <= 16384)
+		adapter->rx_buffer_len = 16384;
+#endif
 
 	/* adjust allocation if LPE protects us, and we aren't using SBP */
 	if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
 	     (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
 		adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
-					 + ETH_FCS_LEN ;
+					 + ETH_FCS_LEN;
 
-	ndev_info(netdev, "changing MTU from %d to %d\n",
-		netdev->mtu, new_mtu);
+	e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
 	netdev->mtu = new_mtu;
 
 	if (netif_running(netdev))
-		e1000e_up(adapter);
+		e1000_up(adapter);
 	else
-		e1000e_reset(adapter);
+		e1000_reset(adapter);
 
 	clear_bit(__E1000_RESETTING, &adapter->state);
 
@@ -3381,9 +4732,8 @@
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct mii_ioctl_data *data = if_mii(ifr);
-	unsigned long irq_flags;
 
-	if (adapter->hw.media_type != e1000_media_type_copper)
+	if (adapter->hw.phy.media_type != e1000_media_type_copper)
 		return -EOPNOTSUPP;
 
 	switch (cmd) {
@@ -3393,13 +4743,40 @@
 	case SIOCGMIIREG:
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		spin_lock_irqsave(&adapter->stats_lock, irq_flags);
-		if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F,
-				   &data->val_out)) {
-			spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+		switch (data->reg_num & 0x1F) {
+		case MII_BMCR:
+			data->val_out = adapter->phy_regs.bmcr;
+			break;
+		case MII_BMSR:
+			data->val_out = adapter->phy_regs.bmsr;
+			break;
+		case MII_PHYSID1:
+			data->val_out = (adapter->hw.phy.id >> 16);
+			break;
+		case MII_PHYSID2:
+			data->val_out = (adapter->hw.phy.id & 0xFFFF);
+			break;
+		case MII_ADVERTISE:
+			data->val_out = adapter->phy_regs.advertise;
+			break;
+		case MII_LPA:
+			data->val_out = adapter->phy_regs.lpa;
+			break;
+		case MII_EXPANSION:
+			data->val_out = adapter->phy_regs.expansion;
+			break;
+		case MII_CTRL1000:
+			data->val_out = adapter->phy_regs.ctrl1000;
+			break;
+		case MII_STAT1000:
+			data->val_out = adapter->phy_regs.stat1000;
+			break;
+		case MII_ESTATUS:
+			data->val_out = adapter->phy_regs.estatus;
+			break;
+		default:
 			return -EIO;
 		}
-		spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
 		break;
 	case SIOCSMIIREG:
 	default:
@@ -3415,6 +4792,10 @@
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
 		return e1000_mii_ioctl(netdev, ifr, cmd);
+#ifdef ETHTOOL_OPS_COMPAT
+	case SIOCETHTOOL:
+		return ethtool_ioctl(ifr);
+#endif
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -3433,13 +4814,15 @@
 
 	if (netif_running(netdev)) {
 		WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
-		e1000e_down(adapter);
+		e1000_down(adapter);
 		e1000_free_irq(adapter);
 	}
 
+#ifdef CONFIG_PM
 	retval = pci_save_state(pdev);
 	if (retval)
 		return retval;
+#endif
 
 	status = er32(STATUS);
 	if (status & E1000_STATUS_LU)
@@ -3465,16 +4848,19 @@
 			E1000_CTRL_EN_PHY_PWR_MGMT;
 		ew32(CTRL, ctrl);
 
-		if (adapter->hw.media_type == e1000_media_type_fiber ||
-		   adapter->hw.media_type == e1000_media_type_internal_serdes) {
+		if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
+		   adapter->hw.phy.media_type == e1000_media_type_internal_serdes) {
 			/* keep the laser running in D3 */
 			ctrl_ext = er32(CTRL_EXT);
 			ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
 			ew32(CTRL_EXT, ctrl_ext);
 		}
 
+		if (adapter->flags & FLAG_IS_ICH)
+			e1000_disable_gig_wol_ich8lan(&adapter->hw);
+
 		/* Allow time for pending master requests to run */
-		e1000e_disable_pcie_master(&adapter->hw);
+		e1000_disable_pcie_master_generic(&adapter->hw);
 
 		ew32(WUC, E1000_WUC_PME_EN);
 		ew32(WUFC, wufc);
@@ -3487,8 +4873,6 @@
 		pci_enable_wake(pdev, PCI_D3cold, 0);
 	}
 
-	e1000_release_manageability(adapter);
-
 	/* make sure adapter isn't asleep if manageability is enabled */
 	if (adapter->flags & FLAG_MNG_PT_ENABLED) {
 		pci_enable_wake(pdev, PCI_D3hot, 1);
@@ -3496,10 +4880,12 @@
 	}
 
 	if (adapter->hw.phy.type == e1000_phy_igp_3)
-		e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+		e1000_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
 
-	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
-	 * would have already happened in close and is redundant. */
+	/*
+	 * Release control of h/w to f/w.  If f/w is AMT enabled, this
+	 * would have already happened in close and is redundant.
+	 */
 	e1000_release_hw_control(adapter);
 
 	pci_disable_device(pdev);
@@ -3537,31 +4923,60 @@
 			return err;
 	}
 
-	e1000e_power_up_phy(adapter);
-	e1000e_reset(adapter);
+	e1000_power_up_phy(hw);
+	e1000_reset(adapter);
 	ew32(WUS, ~0);
 
 	e1000_init_manageability(adapter);
 
 	if (netif_running(netdev))
-		e1000e_up(adapter);
+		e1000_up(adapter);
 
 	netif_device_attach(netdev);
 
-	/* If the controller has AMT, do not set DRV_LOAD until the interface
+	/*
+	 * If the controller has AMT, do not set DRV_LOAD until the interface
 	 * is up.  For all other cases, let the f/w know that the h/w is now
-	 * under the control of the driver. */
-	if (!(adapter->flags & FLAG_HAS_AMT) || !e1000e_check_mng_mode(&adapter->hw))
+	 * under the control of the driver.
+	 */
+	if (!(adapter->flags & FLAG_HAS_AMT))
 		e1000_get_hw_control(adapter);
 
 	return 0;
 }
-#endif
+#endif /* CONFIG_PM */
 
+#ifndef USE_REBOOT_NOTIFIER
 static void e1000_shutdown(struct pci_dev *pdev)
 {
 	e1000_suspend(pdev, PMSG_SUSPEND);
 }
+#else
+static struct pci_driver e1000_driver;
+static int e1000_notify_reboot(struct notifier_block *nb, unsigned long event,
+			       void *ptr)
+{
+	struct pci_dev *pdev = NULL;
+
+	switch (event) {
+	case SYS_DOWN:
+	case SYS_HALT:
+	case SYS_POWER_OFF:
+		while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
+			if (pci_dev_driver(pdev) == &e1000_driver)
+				e1000_suspend(pdev, PMSG_SUSPEND);
+		}
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block e1000_notifier_reboot = {
+	.notifier_call	= e1000_notify_reboot,
+	.next		= NULL,
+	.priority	= 0
+};
+#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
@@ -3577,11 +4992,15 @@
 	e1000_intr(adapter->pdev->irq, netdev);
 
 	e1000_clean_tx_irq(adapter);
+#ifndef CONFIG_E1000E_NAPI
+	adapter->clean_rx(adapter);
+#endif
 
 	enable_irq(adapter->pdev->irq);
 }
 #endif
 
+#ifdef HAVE_PCI_ERS
 /**
  * e1000_io_error_detected - called when PCI error is detected
  * @pdev: Pointer to PCI device
@@ -3599,7 +5018,7 @@
 	netif_device_detach(netdev);
 
 	if (netif_running(netdev))
-		e1000e_down(adapter);
+		e1000_down(adapter);
 	pci_disable_device(pdev);
 
 	/* Request a slot slot reset. */
@@ -3629,7 +5048,7 @@
 	pci_enable_wake(pdev, PCI_D3hot, 0);
 	pci_enable_wake(pdev, PCI_D3cold, 0);
 
-	e1000e_reset(adapter);
+	e1000_reset(adapter);
 	ew32(WUS, ~0);
 
 	return PCI_ERS_RESULT_RECOVERED;
@@ -3651,7 +5070,7 @@
 	e1000_init_manageability(adapter);
 
 	if (netif_running(netdev)) {
-		if (e1000e_up(adapter)) {
+		if (e1000_up(adapter)) {
 			dev_err(&pdev->dev,
 				"can't bring device back up after reset\n");
 			return;
@@ -3660,44 +5079,44 @@
 
 	netif_device_attach(netdev);
 
-	/* If the controller has AMT, do not set DRV_LOAD until the interface
+	/*
+	 * If the controller has AMT, do not set DRV_LOAD until the interface
 	 * is up.  For all other cases, let the f/w know that the h/w is now
-	 * under the control of the driver. */
-	if (!(adapter->flags & FLAG_HAS_AMT) ||
-	    !e1000e_check_mng_mode(&adapter->hw))
+	 * under the control of the driver.
+	 */
+	if (!(adapter->flags & FLAG_HAS_AMT))
 		e1000_get_hw_control(adapter);
 
 }
+#endif /* HAVE_PCI_ERS */
 
 static void e1000_print_device_info(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
-	u32 part_num;
+	u32 pba_num;
 
 	/* print bus type/speed/width info */
-	ndev_info(netdev, "(PCI Express:2.5GB/s:%s) "
-		  "%02x:%02x:%02x:%02x:%02x:%02x\n",
-		  /* bus width */
-		 ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
-		  "Width x1"),
-		  /* MAC address */
-		  netdev->dev_addr[0], netdev->dev_addr[1],
-		  netdev->dev_addr[2], netdev->dev_addr[3],
-		  netdev->dev_addr[4], netdev->dev_addr[5]);
-	ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n",
-		  (hw->phy.type == e1000_phy_ife)
-		   ? "10/100" : "1000");
-	e1000e_read_part_num(hw, &part_num);
-	ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
-		  hw->mac.type, hw->phy.type,
-		  (part_num >> 8), (part_num & 0xff));
+	e_info("(PCI Express:2.5GB/s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       /* bus width */
+	      ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
+	       "Width x1"),
+	       /* MAC address */
+	       netdev->dev_addr[0], netdev->dev_addr[1],
+	       netdev->dev_addr[2], netdev->dev_addr[3],
+	       netdev->dev_addr[4], netdev->dev_addr[5]);
+	e_info("Intel(R) PRO/%s Network Connection\n",
+	       (hw->phy.type == e1000_phy_ife) ? "10/100" : "1000");
+	e1000_read_pba_num_generic(hw, &pba_num);
+	e_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+	       hw->mac.type, hw->phy.type,
+	       (pba_num >> 8), (pba_num & 0xff));
 }
 
 /**
  * e1000_probe - Device Initialization Routine
  * @pdev: PCI device information struct
- * @ent: entry in e1000_pci_tbl
+ * @ent: entry in e1000e_pci_tbl
  *
  * Returns 0 on success, negative on failure
  *
@@ -3712,8 +5131,6 @@
 	struct e1000_adapter *adapter;
 	struct e1000_hw *hw;
 	const struct e1000_info *ei = e1000_info_tbl[ent->driver_data];
-	unsigned long mmio_start, mmio_len;
-	unsigned long flash_start, flash_len;
 
 	static int cards_found;
 	int i, err, pci_using_dac;
@@ -3736,8 +5153,9 @@
 			err = pci_set_consistent_dma_mask(pdev,
 							  DMA_32BIT_MASK);
 			if (err) {
-				dev_err(&pdev->dev, "No usable DMA "
-					"configuration, aborting\n");
+				printk(KERN_ERR "%s: No usable DMA "
+				       "configuration, aborting\n",
+				       pci_name(pdev));
 				goto err_dma;
 			}
 		}
@@ -3754,6 +5172,7 @@
 	if (!netdev)
 		goto err_alloc_etherdev;
 
+	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
@@ -3764,27 +5183,50 @@
 	adapter->ei = ei;
 	adapter->pba = ei->pba;
 	adapter->flags = ei->flags;
-	adapter->hw.adapter = adapter;
+	adapter->hw.back = adapter;
 	adapter->hw.mac.type = ei->mac;
 	adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
+	adapter->stats_freq_us = 2 * 1000000; /* default watchdog timer 2sec */
+
+	/* PCI config space info */
 
-	mmio_start = pci_resource_start(pdev, 0);
-	mmio_len = pci_resource_len(pdev, 0);
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_device_id = pdev->subsystem_device;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
 
 	err = -EIO;
-	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+	adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, 0),
+				      pci_resource_len(pdev, 0));
 	if (!adapter->hw.hw_addr)
 		goto err_ioremap;
 
 	if ((adapter->flags & FLAG_HAS_FLASH) &&
 	    (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
-		flash_start = pci_resource_start(pdev, 1);
-		flash_len = pci_resource_len(pdev, 1);
-		adapter->hw.flash_address = ioremap(flash_start, flash_len);
+		adapter->hw.flash_address = ioremap(pci_resource_start(pdev, 1),
+						    pci_resource_len(pdev, 1));
 		if (!adapter->hw.flash_address)
 			goto err_flashmap;
 	}
 
+	adapter->bd_number = cards_found++;
+
+	e1000_check_options(adapter);
+
+	/* setup adapter struct */
+	err = e1000_sw_init(adapter);
+	if (err)
+		goto err_sw_init;
+
+	if (ei->get_variants) {
+		err = ei->get_variants(adapter);
+		if (err)
+			goto err_hw_init;
+	}
+
 	/* construct the net_device struct */
 	netdev->open			= &e1000_open;
 	netdev->stop			= &e1000_close;
@@ -3794,10 +5236,12 @@
 	netdev->set_mac_address		= &e1000_set_mac;
 	netdev->change_mtu		= &e1000_change_mtu;
 	netdev->do_ioctl		= &e1000_ioctl;
-	e1000e_set_ethtool_ops(netdev);
+	e1000_set_ethtool_ops(netdev);
 	netdev->tx_timeout		= &e1000_tx_timeout;
 	netdev->watchdog_timeo		= 5 * HZ;
-	netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
+#ifdef CONFIG_E1000E_NAPI
+	netif_napi_add(netdev, &adapter->napi, e1000_poll, 64);
+#endif
 	netdev->vlan_rx_register	= e1000_vlan_rx_register;
 	netdev->vlan_rx_add_vid		= e1000_vlan_rx_add_vid;
 	netdev->vlan_rx_kill_vid	= e1000_vlan_rx_kill_vid;
@@ -3806,40 +5250,20 @@
 #endif
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
-	netdev->mem_start = mmio_start;
-	netdev->mem_end = mmio_start + mmio_len;
-
-	adapter->bd_number = cards_found++;
-
-	/* setup adapter struct */
-	err = e1000_sw_init(adapter);
-	if (err)
-		goto err_sw_init;
-
-	err = -EIO;
-
-	memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
-	memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
-	memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
-
-	err = ei->get_invariants(adapter);
-	if (err)
-		goto err_hw_init;
-
 	hw->mac.ops.get_bus_info(&adapter->hw);
 
-	adapter->hw.phy.wait_for_link = 0;
+	adapter->hw.phy.autoneg_wait_to_complete = 0;
 
 	/* Copper options */
-	if (adapter->hw.media_type == e1000_media_type_copper) {
+	if (adapter->hw.phy.media_type == e1000_media_type_copper) {
 		adapter->hw.phy.mdix = AUTO_ALL_MODES;
 		adapter->hw.phy.disable_polarity_correction = 0;
 		adapter->hw.phy.ms_type = e1000_ms_hw_default;
 	}
 
-	if (e1000_check_reset_block(&adapter->hw))
-		ndev_info(netdev,
-			  "PHY reset is blocked due to SOL/IDER session.\n");
+	if (hw->phy.ops.check_reset_block &&
+	    hw->phy.ops.check_reset_block(hw))
+		e_info("PHY reset is blocked due to SOL/IDER session.\n");
 
 	netdev->features = NETIF_F_SG |
 			   NETIF_F_HW_CSUM |
@@ -3849,21 +5273,31 @@
 	if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
 		netdev->features |= NETIF_F_HW_VLAN_FILTER;
 
+#ifdef NETIF_F_TSO
 	netdev->features |= NETIF_F_TSO;
+#ifdef NETIF_F_TSO6
 	netdev->features |= NETIF_F_TSO6;
+#endif
+#endif
 
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
-	/* We should not be using LLTX anymore, but we are still TX faster with
-	 * it. */
+#ifdef NETIF_F_LLTX
+	/*
+	 * We should not be using LLTX anymore, but we are still Tx faster with
+	 * it.
+	 */
 	netdev->features |= NETIF_F_LLTX;
+#endif
 
-	if (e1000e_enable_mng_pass_thru(&adapter->hw))
+	if (e1000_enable_mng_pass_thru(&adapter->hw))
 		adapter->flags |= FLAG_MNG_PT_ENABLED;
 
-	/* before reading the NVM, reset the controller to
-	 * put the device in a known good starting state */
+	/*
+	 * before reading the NVM, reset the controller to
+	 * put the device in a known good starting state
+	 */
 	adapter->hw.mac.ops.reset_hw(&adapter->hw);
 
 	/*
@@ -3871,28 +5305,31 @@
 	 * attempt. Let's give it a few tries
 	 */
 	for (i = 0;; i++) {
-		if (e1000_validate_nvm_checksum(&adapter->hw) >= 0)
+		if (hw->nvm.ops.validate(hw) >= 0)
 			break;
 		if (i == 2) {
-			ndev_err(netdev, "The NVM Checksum Is Not Valid\n");
+			e_err("The NVM Checksum Is Not Valid\n");
 			err = -EIO;
 			goto err_eeprom;
 		}
 	}
 
 	/* copy the MAC address out of the NVM */
-	if (e1000e_read_mac_addr(&adapter->hw))
-		ndev_err(netdev, "NVM Read Error while reading MAC address\n");
+	if (e1000_read_mac_addr(&adapter->hw))
+		e_err("NVM Read Error while reading MAC address\n");
 
 	memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+#ifdef ETHTOOL_GPERMADDR
 	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
 	if (!is_valid_ether_addr(netdev->perm_addr)) {
-		ndev_err(netdev, "Invalid MAC Address: "
-			 "%02x:%02x:%02x:%02x:%02x:%02x\n",
-			 netdev->perm_addr[0], netdev->perm_addr[1],
-			 netdev->perm_addr[2], netdev->perm_addr[3],
-			 netdev->perm_addr[4], netdev->perm_addr[5]);
+#else
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
+#endif
+		e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		      netdev->dev_addr[0], netdev->dev_addr[1],
+		      netdev->dev_addr[2], netdev->dev_addr[3],
+		      netdev->dev_addr[4], netdev->dev_addr[5]);
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -3908,13 +5345,11 @@
 	INIT_WORK(&adapter->reset_task, e1000_reset_task);
 	INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
 
-	e1000e_check_options(adapter);
-
 	/* Initialize link parameters. User can change them with ethtool */
 	adapter->hw.mac.autoneg = 1;
 	adapter->fc_autoneg = 1;
-	adapter->hw.mac.original_fc = e1000_fc_default;
-	adapter->hw.mac.fc = e1000_fc_default;
+	adapter->hw.fc.original_type = e1000_fc_default;
+	adapter->hw.fc.type = e1000_fc_default;
 	adapter->hw.phy.autoneg_advertised = 0x2f;
 
 	/* ring size defaults */
@@ -3932,11 +5367,11 @@
 	} else if (adapter->flags & FLAG_APME_IN_CTRL3) {
 		if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
 		    (adapter->hw.bus.func == 1))
-			e1000_read_nvm(&adapter->hw,
-				NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+			hw->nvm.ops.read(&adapter->hw, NVM_INIT_CONTROL3_PORT_B,
+			                 1, &eeprom_data);
 		else
-			e1000_read_nvm(&adapter->hw,
-				NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+			hw->nvm.ops.read(&adapter->hw, NVM_INIT_CONTROL3_PORT_A,
+			                 1, &eeprom_data);
 	}
 
 	/* fetch WoL from EEPROM */
@@ -3955,13 +5390,14 @@
 	adapter->wol = adapter->eeprom_wol;
 
 	/* reset the hardware with the new settings */
-	e1000e_reset(adapter);
+	e1000_reset(adapter);
 
-	/* If the controller has AMT, do not set DRV_LOAD until the interface
+	/*
+	 * If the controller has AMT, do not set DRV_LOAD until the interface
 	 * is up.  For all other cases, let the f/w know that the h/w is now
-	 * under the control of the driver. */
-	if (!(adapter->flags & FLAG_HAS_AMT) ||
-	    !e1000e_check_mng_mode(&adapter->hw))
+	 * under the control of the driver.
+	 */
+	if (!(adapter->flags & FLAG_HAS_AMT))
 		e1000_get_hw_control(adapter);
 
 	/* tell the stack to leave us alone until e1000_open() is called */
@@ -3978,19 +5414,20 @@
 	return 0;
 
 err_register:
-err_hw_init:
-	e1000_release_hw_control(adapter);
+	if (!(adapter->flags & FLAG_HAS_AMT))
+		e1000_release_hw_control(adapter);
 err_eeprom:
-	if (!e1000_check_reset_block(&adapter->hw))
-		e1000_phy_hw_reset(&adapter->hw);
-
-	if (adapter->hw.flash_address)
-		iounmap(adapter->hw.flash_address);
-
-err_flashmap:
+	if (hw->phy.ops.check_reset_block &&
+	    !hw->phy.ops.check_reset_block(hw))
+		hw->phy.ops.reset(hw);
+err_hw_init:
+	hw->mac.ops.remove_device(&adapter->hw);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 err_sw_init:
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+err_flashmap:
 	iounmap(adapter->hw.hw_addr);
 err_ioremap:
 	free_netdev(netdev);
@@ -4015,26 +5452,34 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
 
-	/* flush_scheduled work may reschedule our watchdog task, so
-	 * explicitly disable watchdog tasks from being rescheduled  */
+	/*
+	 * flush_scheduled work may reschedule our watchdog task, so
+	 * explicitly disable watchdog tasks from being rescheduled
+	 */
 	set_bit(__E1000_DOWN, &adapter->state);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
 
 	flush_scheduled_work();
 
-	e1000_release_manageability(adapter);
-
-	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
-	 * would have already happened in close and is redundant. */
+	/*
+	 * Release control of h/w to f/w.  If f/w is AMT enabled, this
+	 * would have already happened in close and is redundant.
+	 */
 	e1000_release_hw_control(adapter);
 
 	unregister_netdev(netdev);
 
-	if (!e1000_check_reset_block(&adapter->hw))
-		e1000_phy_hw_reset(&adapter->hw);
-
+	if (hw->phy.ops.check_reset_block &&
+	    !hw->phy.ops.check_reset_block(hw))
+		hw->phy.ops.reset(hw);
+
+#ifdef CONFIG_E1000E_MSIX
+	e1000_reset_interrupt_capability(adapter);
+#endif /* CONFIG_E1000E_MSIX */
+	hw->mac.ops.remove_device(&adapter->hw);
 	kfree(adapter->tx_ring);
 	kfree(adapter->rx_ring);
 
@@ -4048,31 +5493,37 @@
 	pci_disable_device(pdev);
 }
 
+#ifdef HAVE_PCI_ERS
 /* PCI Error Recovery (ERS) */
 static struct pci_error_handlers e1000_err_handler = {
 	.error_detected = e1000_io_error_detected,
 	.slot_reset = e1000_io_slot_reset,
 	.resume = e1000_io_resume,
 };
+#endif
 
-static struct pci_device_id e1000_pci_tbl[] = {
-	/*
-	 * Support for 82571/2/3, es2lan and ich8 will be phased in
-	 * stepwise.
-
+static struct pci_device_id e1000e_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER), board_82571 },
+
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 },
+
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
+
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
+
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
 	  board_80003es2lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
@@ -4081,6 +5532,7 @@
 	  board_80003es2lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT),
 	  board_80003es2lan },
+
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan },
@@ -4088,31 +5540,45 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan },
-	*/
 
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan },
+
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LM), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan },
+
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan },
 
 	{ }	/* terminate list */
 };
-MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+MODULE_DEVICE_TABLE(pci, e1000e_pci_tbl);
 
 /* PCI Device API Driver */
 static struct pci_driver e1000_driver = {
 	.name     = e1000e_driver_name,
-	.id_table = e1000_pci_tbl,
+	.id_table = e1000e_pci_tbl,
 	.probe    = e1000_probe,
 	.remove   = __devexit_p(e1000_remove),
 #ifdef CONFIG_PM
-	/* Power Managment Hooks */
+	/* Power Management Hooks */
 	.suspend  = e1000_suspend,
 	.resume   = e1000_resume,
 #endif
+#ifndef USE_REBOOT_NOTIFIER
 	.shutdown = e1000_shutdown,
+#endif
+#ifdef HAVE_PCI_ERS
 	.err_handler = &e1000_err_handler
+#endif
 };
 
 /**
@@ -4126,10 +5592,16 @@
 	int ret;
 	printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n",
 	       e1000e_driver_name, e1000e_driver_version);
-	printk(KERN_INFO "%s: Copyright (c) 1999-2007 Intel Corporation.\n",
+	printk(KERN_INFO "%s: Copyright (c) 1999-2008 Intel Corporation.\n",
 	       e1000e_driver_name);
 	ret = pci_register_driver(&e1000_driver);
-
+	pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name,
+			       PM_QOS_DEFAULT_VALUE);
+#ifdef USE_REBOOT_NOTIFIER
+	if (ret >= 0)
+		register_reboot_notifier(&e1000_notifier_reboot);
+#endif
+				
 	return ret;
 }
 module_init(e1000_init_module);
@@ -4142,7 +5614,11 @@
  **/
 static void __exit e1000_exit_module(void)
 {
+#ifdef USE_REBOOT_NOTIFIER
+	unregister_reboot_notifier(&e1000_notifier_reboot);
+#endif
 	pci_unregister_driver(&e1000_driver);
+	pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, e1000e_driver_name);
 }
 module_exit(e1000_exit_module);
 
@@ -4152,4 +5628,4 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-/* e1000_main.c */
+/* netdev.c */
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/param.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/param.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/param.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/param.c	2008-06-23 18:27:33.000000000 +0200
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
+  Copyright(c) 1999 - 2008 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -30,7 +30,8 @@
 
 #include "e1000.h"
 
-/* This is the only thing that needs to be changed to adjust the
+/*
+ * This is the only thing that needs to be changed to adjust the
  * maximum number of ports that the driver can manage.
  */
 
@@ -46,22 +47,40 @@
 MODULE_PARM_DESC(copybreak,
 	"Maximum size of packet that is copied to a new buffer on receive");
 
-/* All parameters are treated the same, as an integer array of values.
+/*
+ * All parameters are treated the same, as an integer array of values.
  * This macro just reduces the need to repeat the same declaration code
  * over and over (plus this helps to avoid typo bugs).
  */
 
 #define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+#ifndef module_param_array
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+#define E1000_PARAM(X, desc) \
+	static const int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
+	static unsigned int num_##X;				 \
+	MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
+	MODULE_PARM_DESC(X, desc);
+#else
 #define E1000_PARAM(X, desc)					\
 	static int __devinitdata X[E1000_MAX_NIC+1]		\
 		= E1000_PARAM_INIT;				\
 	static unsigned int num_##X;				\
 	module_param_array_named(X, X, int, &num_##X, 0);	\
 	MODULE_PARM_DESC(X, desc);
+#endif
 
-
-/* Transmit Interrupt Delay in units of 1.024 microseconds
- *  Tx interrupt delay needs to typically be set to something non zero
+/*
+ * Transmit Interrupt Delay in units of 1.024 microseconds
+ * Tx interrupt delay needs to typically be set to something non zero
  *
  * Valid Range: 0-65535
  */
@@ -70,7 +89,8 @@
 #define MAX_TXDELAY 0xFFFF
 #define MIN_TXDELAY 0
 
-/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+/*
+ * Transmit Absolute Interrupt Delay in units of 1.024 microseconds
  *
  * Valid Range: 0-65535
  */
@@ -79,8 +99,9 @@
 #define MAX_TXABSDELAY 0xFFFF
 #define MIN_TXABSDELAY 0
 
-/* Receive Interrupt Delay in units of 1.024 microseconds
- *   hardware will likely hang if you set this to anything but zero.
+/*
+ * Receive Interrupt Delay in units of 1.024 microseconds
+ * hardware will likely hang if you set this to anything but zero.
  *
  * Valid Range: 0-65535
  */
@@ -89,7 +110,8 @@
 #define MAX_RXDELAY 0xFFFF
 #define MIN_RXDELAY 0
 
-/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+/*
+ * Receive Absolute Interrupt Delay in units of 1.024 microseconds
  *
  * Valid Range: 0-65535
  */
@@ -98,7 +120,8 @@
 #define MAX_RXABSDELAY 0xFFFF
 #define MIN_RXABSDELAY 0
 
-/* Interrupt Throttle Rate (interrupts/sec)
+/*
+ * Interrupt Throttle Rate (interrupts/sec)
  *
  * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
  */
@@ -107,7 +130,20 @@
 #define MAX_ITR 100000
 #define MIN_ITR 100
 
-/* Enable Smart Power Down of the PHY
+#ifdef CONFIG_E1000E_MSIX
+/* IntMode (Interrupt Mode)
+ *
+ * Valid Range: 0 - 2
+ *
+ * Default Value: 2 (MSI-X)
+ */
+E1000_PARAM(IntMode, "Interrupt Mode");
+#define MAX_INTMODE	2
+#define MIN_INTMODE	0
+
+#endif /* CONFIG_E1000E_MSIX */
+/*
+ * Enable Smart Power Down of the PHY
  *
  * Valid Range: 0, 1
  *
@@ -115,7 +151,8 @@
  */
 E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
 
-/* Enable Kumeran Lock Loss workaround
+/*
+ * Enable Kumeran Lock Loss workaround
  *
  * Valid Range: 0, 1
  *
@@ -153,17 +190,16 @@
 	case enable_option:
 		switch (*value) {
 		case OPTION_ENABLED:
-			ndev_info(adapter->netdev, "%s Enabled\n", opt->name);
+			e_info("%s Enabled\n", opt->name);
 			return 0;
 		case OPTION_DISABLED:
-			ndev_info(adapter->netdev, "%s Disabled\n", opt->name);
+			e_info("%s Disabled\n", opt->name);
 			return 0;
 		}
 		break;
 	case range_option:
 		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
-			ndev_info(adapter->netdev,
-					"%s set to %i\n", opt->name, *value);
+			e_info("%s set to %i\n", opt->name, *value);
 			return 0;
 		}
 		break;
@@ -175,8 +211,7 @@
 			ent = &opt->arg.l.p[i];
 			if (*value == ent->i) {
 				if (ent->str[0] != '\0')
-					ndev_info(adapter->netdev, "%s\n",
-						  ent->str);
+					e_info("%s\n", ent->str);
 				return 0;
 			}
 		}
@@ -186,14 +221,14 @@
 		BUG();
 	}
 
-	ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n",
-	       opt->name, *value, opt->err);
+	e_info("Invalid %s value specified (%i) %s\n", opt->name, *value,
+	       opt->err);
 	*value = opt->def;
 	return -1;
 }
 
 /**
- * e1000e_check_options - Range Checking for Command Line Parameters
+ * e1000_check_options - Range Checking for Command Line Parameters
  * @adapter: board private structure
  *
  * This routine checks all command line parameters for valid user
@@ -201,16 +236,14 @@
  * value exists, a default value is used.  The final value is stored
  * in a variable in the adapter structure.
  **/
-void __devinit e1000e_check_options(struct e1000_adapter *adapter)
+void __devinit e1000_check_options(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	struct net_device *netdev = adapter->netdev;
 	int bd = adapter->bd_number;
 
 	if (bd >= E1000_MAX_NIC) {
-		ndev_notice(netdev,
-		       "Warning: no configuration for board #%i\n", bd);
-		ndev_notice(netdev, "Using defaults for all values\n");
+		e_notice("Warning: no configuration for board #%i\n", bd);
+		e_notice("Using defaults for all values\n");
 	}
 
 	{ /* Transmit Interrupt Delay */
@@ -262,8 +295,10 @@
 					 .max = MAX_RXDELAY } }
 		};
 
-		/* modify min and default if 82573 for slow ping w/a,
-		 * a value greater than 8 needs to be set for RDTR */
+		/*
+		 * modify min and default if 82573 for slow ping w/a,
+		 * a value greater than 8 needs to be set for RDTR
+		 */
 		if (adapter->flags & FLAG_HAS_ASPM) {
 			opt.def = 32;
 			opt.arg.r.min = 8;
@@ -311,32 +346,41 @@
 			adapter->itr = InterruptThrottleRate[bd];
 			switch (adapter->itr) {
 			case 0:
-				ndev_info(netdev, "%s turned off\n",
-					opt.name);
+				e_info("%s turned off\n", opt.name);
 				break;
 			case 1:
-				ndev_info(netdev,
-					  "%s set to dynamic mode\n",
-					  opt.name);
+				e_info("%s set to dynamic mode\n", opt.name);
 				adapter->itr_setting = adapter->itr;
 				adapter->itr = 20000;
 				break;
 			case 3:
-				ndev_info(netdev,
-					"%s set to dynamic conservative mode\n",
+				e_info("%s set to dynamic conservative mode\n",
 					opt.name);
 				adapter->itr_setting = adapter->itr;
 				adapter->itr = 20000;
 				break;
 			default:
-				e1000_validate_option(&adapter->itr, &opt,
-					adapter);
 				/*
-				 * save the setting, because the dynamic bits
-				 * change itr. clear the lower two bits
-				 * because they are used as control
+				 * Save the setting, because the dynamic bits
+				 * change itr.
 				 */
-				adapter->itr_setting = adapter->itr & ~3;
+				if (e1000_validate_option(&adapter->itr, &opt,
+				                          adapter) &&
+				    (adapter->itr == 3)) {
+					/*
+					 * In case of invalid user value,
+					 * default to conservative mode.
+					 */
+					adapter->itr_setting = adapter->itr;
+					adapter->itr = 20000;
+				} else {
+					/*
+					 * Clear the lower two bits because
+					 * they are used as control.
+					 */
+					adapter->itr_setting =
+						adapter->itr & ~3;
+				}
 				break;
 			}
 		} else {
@@ -344,6 +388,26 @@
 			adapter->itr = 20000;
 		}
 	}
+#ifdef CONFIG_E1000E_MSIX
+	{ /* Interrupt Mode */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Interrupt Mode",
+			.err  = "defaulting to 2 (MSI-X)",
+			.def  = E1000E_INT_MODE_MSIX,
+			.arg  = { .r = { .min = MIN_INTMODE,
+			.max = MAX_INTMODE }}
+		};
+
+		if (num_IntMode > bd) {
+			unsigned int int_mode = IntMode[bd];
+			e1000_validate_option(&int_mode, &opt, adapter);
+			adapter->int_mode = int_mode;
+		} else {
+			adapter->int_mode = opt.def;
+		}
+	}
+#endif /* CONFIG_E1000E_MSIX */
 	{ /* Smart Power Down */
 		const struct e1000_option opt = {
 			.type = enable_option,
@@ -372,11 +436,11 @@
 			unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
 			e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
 			if (hw->mac.type == e1000_ich8lan)
-				e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+				e1000_set_kmrn_lock_loss_workaround_ich8lan(hw,
 								kmrn_lock_loss);
 		} else {
 			if (hw->mac.type == e1000_ich8lan)
-				e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+				e1000_set_kmrn_lock_loss_workaround_ich8lan(hw,
 								       opt.def);
 		}
 	}
diff -urN linux-2.6.24.7-rt20/drivers/net/e1000e/phy.c linux-2.6.24.7-rt20-atom/drivers/net/e1000e/phy.c
--- linux-2.6.24.7-rt20/drivers/net/e1000e/phy.c	2008-10-06 08:30:18.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/e1000e/phy.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1773 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2007 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#include <linux/delay.h>
-
-#include "e1000.h"
-
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
-static s32 e1000_wait_autoneg(struct e1000_hw *hw);
-
-/* Cable length tables */
-static const u16 e1000_m88_cable_length_table[] =
-	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
-
-static const u16 e1000_igp_2_cable_length_table[] =
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3,
-	  6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22,
-	  26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40,
-	  44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61,
-	  66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82,
-	  87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95,
-	  100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121,
-	  124};
-#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
-		(sizeof(e1000_igp_2_cable_length_table) / \
-		 sizeof(e1000_igp_2_cable_length_table[0]))
-
-/**
- *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
- *  @hw: pointer to the HW structure
- *
- *  Read the PHY management control register and check whether a PHY reset
- *  is blocked.  If a reset is not blocked return 0, otherwise
- *  return E1000_BLK_PHY_RESET (12).
- **/
-s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
-{
-	u32 manc;
-
-	manc = er32(MANC);
-
-	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
-	       E1000_BLK_PHY_RESET : 0;
-}
-
-/**
- *  e1000e_get_phy_id - Retrieve the PHY ID and revision
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY registers and stores the PHY ID and possibly the PHY
- *  revision in the hardware structure.
- **/
-s32 e1000e_get_phy_id(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_id;
-
-	ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
-	if (ret_val)
-		return ret_val;
-
-	phy->id = (u32)(phy_id << 16);
-	udelay(20);
-	ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
-	if (ret_val)
-		return ret_val;
-
-	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
-	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
-
-	return 0;
-}
-
-/**
- *  e1000e_phy_reset_dsp - Reset PHY DSP
- *  @hw: pointer to the HW structure
- *
- *  Reset the digital signal processor.
- **/
-s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
-	if (ret_val)
-		return ret_val;
-
-	return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
-}
-
-/**
- *  e1000_read_phy_reg_mdic - Read MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the MDI control regsiter in the PHY at offset and stores the
- *  information read to data.
- **/
-static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-
-	if (offset > MAX_PHY_REG_ADDRESS) {
-		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
-		return -E1000_ERR_PARAM;
-	}
-
-	/* Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
-		(phy->addr << E1000_MDIC_PHY_SHIFT) |
-		(E1000_MDIC_OP_READ));
-
-	ew32(MDIC, mdic);
-
-	/* Poll the ready bit to see if the MDI read completed */
-	for (i = 0; i < 64; i++) {
-		udelay(50);
-		mdic = er32(MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		hw_dbg(hw, "MDI Read did not complete\n");
-		return -E1000_ERR_PHY;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		hw_dbg(hw, "MDI Error\n");
-		return -E1000_ERR_PHY;
-	}
-	*data = (u16) mdic;
-
-	return 0;
-}
-
-/**
- *  e1000_write_phy_reg_mdic - Write MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write to register at offset
- *
- *  Writes data to MDI control register in the PHY at offset.
- **/
-static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-
-	if (offset > MAX_PHY_REG_ADDRESS) {
-		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
-		return -E1000_ERR_PARAM;
-	}
-
-	/* Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = (((u32)data) |
-		(offset << E1000_MDIC_REG_SHIFT) |
-		(phy->addr << E1000_MDIC_PHY_SHIFT) |
-		(E1000_MDIC_OP_WRITE));
-
-	ew32(MDIC, mdic);
-
-	/* Poll the ready bit to see if the MDI read completed */
-	for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
-		udelay(5);
-		mdic = er32(MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		hw_dbg(hw, "MDI Write did not complete\n");
-		return -E1000_ERR_PHY;
-	}
-
-	return 0;
-}
-
-/**
- *  e1000e_read_phy_reg_m88 - Read m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = hw->phy.ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000_read_phy_reg_mdic(hw,
-					  MAX_PHY_REG_ADDRESS & offset,
-					  data);
-
-	hw->phy.ops.release_phy(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_m88 - Write m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val;
-
-	ret_val = hw->phy.ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1000_write_phy_reg_mdic(hw,
-					   MAX_PHY_REG_ADDRESS & offset,
-					   data);
-
-	hw->phy.ops.release_phy(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_igp - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = hw->phy.ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000_write_phy_reg_mdic(hw,
-						   IGP01E1000_PHY_PAGE_SELECT,
-						   (u16)offset);
-		if (ret_val) {
-			hw->phy.ops.release_phy(hw);
-			return ret_val;
-		}
-	}
-
-	ret_val = e1000_read_phy_reg_mdic(hw,
-					  MAX_PHY_REG_ADDRESS & offset,
-					  data);
-
-	hw->phy.ops.release_phy(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_igp - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val;
-
-	ret_val = hw->phy.ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000_write_phy_reg_mdic(hw,
-						   IGP01E1000_PHY_PAGE_SELECT,
-						   (u16)offset);
-		if (ret_val) {
-			hw->phy.ops.release_phy(hw);
-			return ret_val;
-		}
-	}
-
-	ret_val = e1000_write_phy_reg_mdic(hw,
-					   MAX_PHY_REG_ADDRESS & offset,
-					   data);
-
-	hw->phy.ops.release_phy(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_read_kmrn_reg - Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
- *  using the kumeran interface.  The information retrieved is stored in data.
- *  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val;
-
-	ret_val = hw->phy.ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-		       E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
-	ew32(KMRNCTRLSTA, kmrnctrlsta);
-
-	udelay(2);
-
-	kmrnctrlsta = er32(KMRNCTRLSTA);
-	*data = (u16)kmrnctrlsta;
-
-	hw->phy.ops.release_phy(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_write_kmrn_reg - Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary.  Then write the data to PHY register
- *  at the offset using the kumeran interface.  Release any acquired semaphores
- *  before exiting.
- **/
-s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val;
-
-	ret_val = hw->phy.ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-		       E1000_KMRNCTRLSTA_OFFSET) | data;
-	ew32(KMRNCTRLSTA, kmrnctrlsta);
-
-	udelay(2);
-	hw->phy.ops.release_phy(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
- *  and downshift values are set also.
- **/
-s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-
-	/* Enable CRS on TX. This must be set for half-duplex operation. */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
-	/* Options:
-	 *   MDI/MDI-X = 0 (default)
-	 *   0 - Auto for all speeds
-	 *   1 - MDI mode
-	 *   2 - MDI-X mode
-	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-	 */
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
-	switch (phy->mdix) {
-	case 1:
-		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-		break;
-	case 2:
-		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-		break;
-	case 3:
-		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-		break;
-	case 0:
-	default:
-		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-		break;
-	}
-
-	/* Options:
-	 *   disable_polarity_correction = 0 (default)
-	 *       Automatic Correction for Reversed Cable Polarity
-	 *   0 - Disabled
-	 *   1 - Enabled
-	 */
-	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-	if (phy->disable_polarity_correction == 1)
-		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-
-	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	if (phy->revision < 4) {
-		/* Force TX_CLK in the Extended PHY Specific Control Register
-		 * to 25MHz clock.
-		 */
-		ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
-		if (ret_val)
-			return ret_val;
-
-		phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
-		if ((phy->revision == 2) &&
-		    (phy->id == M88E1111_I_PHY_ID)) {
-			/* 82573L PHY - set the downshift counter to 5x. */
-			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
-			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
-		} else {
-			/* Configure Master and Slave downshift values */
-			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-				      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-				     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-		}
-		ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Commit the changes. */
-	ret_val = e1000e_commit_phy(hw);
-	if (ret_val)
-		hw_dbg(hw, "Error committing the PHY changes\n");
-
-	return ret_val;
-}
-
-/**
- *  e1000e_copper_link_setup_igp - Setup igp PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
- *  igp PHY's.
- **/
-s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1000_phy_hw_reset(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error resetting the PHY.\n");
-		return ret_val;
-	}
-
-	/* Wait 15ms for MAC to configure PHY from NVM settings. */
-	msleep(15);
-
-	/* disable lplu d0 during driver init */
-	ret_val = e1000_set_d0_lplu_state(hw, 0);
-	if (ret_val) {
-		hw_dbg(hw, "Error Disabling LPLU D0\n");
-		return ret_val;
-	}
-	/* Configure mdi-mdix settings */
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
-	if (ret_val)
-		return ret_val;
-
-	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-
-	switch (phy->mdix) {
-	case 1:
-		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 2:
-		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 0:
-	default:
-		data |= IGP01E1000_PSCR_AUTO_MDIX;
-		break;
-	}
-	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data);
-	if (ret_val)
-		return ret_val;
-
-	/* set auto-master slave resolution settings */
-	if (hw->mac.autoneg) {
-		/* when autonegotiation advertisement is only 1000Mbps then we
-		 * should disable SmartSpeed and enable Auto MasterSlave
-		 * resolution as hardware default. */
-		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
-			/* Disable SmartSpeed */
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     &data);
-			if (ret_val)
-				return ret_val;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-
-			/* Set auto Master/Slave resolution process */
-			ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
-			if (ret_val)
-				return ret_val;
-
-			data &= ~CR_1000T_MS_ENABLE;
-			ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
-			if (ret_val)
-				return ret_val;
-		}
-
-		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
-		if (ret_val)
-			return ret_val;
-
-		/* load defaults for future use */
-		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
-			((data & CR_1000T_MS_VALUE) ?
-			e1000_ms_force_master :
-			e1000_ms_force_slave) :
-			e1000_ms_auto;
-
-		switch (phy->ms_type) {
-		case e1000_ms_force_master:
-			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_force_slave:
-			data |= CR_1000T_MS_ENABLE;
-			data &= ~(CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_auto:
-			data &= ~CR_1000T_MS_ENABLE;
-		default:
-			break;
-		}
-		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
- *  @hw: pointer to the HW structure
- *
- *  Reads the MII auto-neg advertisement register and/or the 1000T control
- *  register and if the PHY is already setup for auto-negotiation, then
- *  return successful.  Otherwise, setup advertisement and flow control to
- *  the appropriate values for the wanted auto-negotiation.
- **/
-static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 mii_autoneg_adv_reg;
-	u16 mii_1000t_ctrl_reg = 0;
-
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
-	ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
-	if (ret_val)
-		return ret_val;
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		/* Read the MII 1000Base-T Control Register (Address 9). */
-		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Need to parse both autoneg_advertised and fc and set up
-	 * the appropriate PHY registers.  First we will parse for
-	 * autoneg_advertised software override.  Since we can advertise
-	 * a plethora of combinations, we need to check each bit
-	 * individually.
-	 */
-
-	/* First we clear all the 10/100 mb speed bits in the Auto-Neg
-	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
-	 * the  1000Base-T Control Register (Address 9).
-	 */
-	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
-				 NWAY_AR_100TX_HD_CAPS |
-				 NWAY_AR_10T_FD_CAPS   |
-				 NWAY_AR_10T_HD_CAPS);
-	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
-
-	hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised);
-
-	/* Do we want to advertise 10 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
-		hw_dbg(hw, "Advertise 10mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
-	}
-
-	/* Do we want to advertise 10 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
-		hw_dbg(hw, "Advertise 10mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
-		hw_dbg(hw, "Advertise 100mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
-		hw_dbg(hw, "Advertise 100mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
-	}
-
-	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
-	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
-		hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n");
-
-	/* Do we want to advertise 1000 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
-		hw_dbg(hw, "Advertise 1000mb Full duplex\n");
-		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
-	}
-
-	/* Check for a software override of the flow control settings, and
-	 * setup the PHY advertisement registers accordingly.  If
-	 * auto-negotiation is enabled, then software will have to set the
-	 * "PAUSE" bits to the correct value in the Auto-Negotiation
-	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
-	 * negotiation.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames
-	 *	  but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *	  but we do not support receiving pause frames).
-	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
-	 *  other:  No software override.  The flow control configuration
-	 *	  in the EEPROM is used.
-	 */
-	switch (hw->mac.fc) {
-	case e1000_fc_none:
-		/* Flow control (RX & TX) is completely disabled by a
-		 * software over-ride.
-		 */
-		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_rx_pause:
-		/* RX Flow control is enabled, and TX Flow control is
-		 * disabled, by a software over-ride.
-		 */
-		/* Since there really isn't a way to advertise that we are
-		 * capable of RX Pause ONLY, we will advertise that we
-		 * support both symmetric and asymmetric RX PAUSE.  Later
-		 * (in e1000e_config_fc_after_link_up) we will disable the
-		 * hw's ability to send PAUSE frames.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_tx_pause:
-		/* TX Flow control is enabled, and RX Flow control is
-		 * disabled, by a software over-ride.
-		 */
-		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
-		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
-		break;
-	case e1000_fc_full:
-		/* Flow control (both RX and TX) is enabled by a software
-		 * over-ride.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	default:
-		hw_dbg(hw, "Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		return ret_val;
-	}
-
-	ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-	if (ret_val)
-		return ret_val;
-
-	hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
- *  @hw: pointer to the HW structure
- *
- *  Performs initial bounds checking on autoneg advertisement parameter, then
- *  configure to advertise the full capability.  Setup the PHY to autoneg
- *  and restart the negotiation process between the link partner.  If
- *  wait_for_link, then wait for autoneg to complete before exiting.
- **/
-static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_ctrl;
-
-	/* Perform some bounds checking on the autoneg advertisement
-	 * parameter.
-	 */
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/* If autoneg_advertised is zero, we assume it was not defaulted
-	 * by the calling code so we set to advertise full capability.
-	 */
-	if (phy->autoneg_advertised == 0)
-		phy->autoneg_advertised = phy->autoneg_mask;
-
-	hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n");
-	ret_val = e1000_phy_setup_autoneg(hw);
-	if (ret_val) {
-		hw_dbg(hw, "Error Setting up Auto-Negotiation\n");
-		return ret_val;
-	}
-	hw_dbg(hw, "Restarting Auto-Neg\n");
-
-	/* Restart auto-negotiation by setting the Auto Neg Enable bit and
-	 * the Auto Neg Restart bit in the PHY control register.
-	 */
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		return ret_val;
-
-	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		return ret_val;
-
-	/* Does the user want to wait for Auto-Neg to complete here, or
-	 * check at a later time (for example, callback routine).
-	 */
-	if (phy->wait_for_link) {
-		ret_val = e1000_wait_autoneg(hw);
-		if (ret_val) {
-			hw_dbg(hw, "Error while waiting for "
-				 "autoneg to complete\n");
-			return ret_val;
-		}
-	}
-
-	hw->mac.get_link_status = 1;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_copper_link - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
- **/
-s32 e1000e_setup_copper_link(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	bool link;
-
-	if (hw->mac.autoneg) {
-		/* Setup autoneg and flow control advertisement and perform
-		 * autonegotiation. */
-		ret_val = e1000_copper_link_autoneg(hw);
-		if (ret_val)
-			return ret_val;
-	} else {
-		/* PHY will be set to 10H, 10F, 100H or 100F
-		 * depending on user settings. */
-		hw_dbg(hw, "Forcing Speed and Duplex\n");
-		ret_val = e1000_phy_force_speed_duplex(hw);
-		if (ret_val) {
-			hw_dbg(hw, "Error Forcing Speed and Duplex\n");
-			return ret_val;
-		}
-	}
-
-	/* Check link status. Wait up to 100 microseconds for link to become
-	 * valid.
-	 */
-	ret_val = e1000e_phy_has_link_generic(hw,
-					     COPPER_LINK_UP_LIMIT,
-					     10,
-					     &link);
-	if (ret_val)
-		return ret_val;
-
-	if (link) {
-		hw_dbg(hw, "Valid link established!!!\n");
-		e1000e_config_collision_dist(hw);
-		ret_val = e1000e_config_fc_after_link_up(hw);
-	} else {
-		hw_dbg(hw, "Unable to establish link!!!\n");
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Waits for link and returns
- *  successful if link up is successful, else -E1000_ERR_PHY (-2).
- **/
-s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	/* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-
-	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	hw_dbg(hw, "IGP PSCR: %X\n", phy_data);
-
-	udelay(1);
-
-	if (phy->wait_for_link) {
-		hw_dbg(hw, "Waiting for forced speed/duplex link on IGP phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw,
-						     PHY_FORCE_LIMIT,
-						     100000,
-						     &link);
-		if (ret_val)
-			return ret_val;
-
-		if (!link)
-			hw_dbg(hw, "Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw,
-						     PHY_FORCE_LIMIT,
-						     100000,
-						     &link);
-		if (ret_val)
-			return ret_val;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Resets the PHY to commit the
- *  changes.  If time expires while waiting for link up, we reset the DSP.
- *  After reset, TX_CLK and CRS on TX must be set.  Return successful upon
- *  successful completion, else return corresponding error code.
- **/
-s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	/* Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data);
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	/* Reset the phy to commit changes. */
-	phy_data |= MII_CR_RESET;
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	udelay(1);
-
-	if (phy->wait_for_link) {
-		hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-						     100000, &link);
-		if (ret_val)
-			return ret_val;
-
-		if (!link) {
-			/* We didn't get link.
-			 * Reset the DSP and cross our fingers.
-			 */
-			ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d);
-			if (ret_val)
-				return ret_val;
-			ret_val = e1000e_phy_reset_dsp(hw);
-			if (ret_val)
-				return ret_val;
-		}
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-						     100000, &link);
-		if (ret_val)
-			return ret_val;
-	}
-
-	ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	/* Resetting the phy means we need to re-force TX_CLK in the
-	 * Extended PHY Specific Control Register to 25MHz clock from
-	 * the reset value of 2.5MHz.
-	 */
-	phy_data |= M88E1000_EPSCR_TX_CLK_25;
-	ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		return ret_val;
-
-	/* In addition, we must re-enable CRS on Tx for both half and full
-	 * duplex.
-	 */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
- *  @hw: pointer to the HW structure
- *  @phy_ctrl: pointer to current value of PHY_CONTROL
- *
- *  Forces speed and duplex on the PHY by doing the following: disable flow
- *  control, force speed/duplex on the MAC, disable auto speed detection,
- *  disable auto-negotiation, configure duplex, configure speed, configure
- *  the collision distance, write configuration to CTRL register.  The
- *  caller must write to the PHY_CONTROL register for these settings to
- *  take affect.
- **/
-void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl;
-
-	/* Turn off flow control when forcing speed/duplex */
-	mac->fc = e1000_fc_none;
-
-	/* Force speed/duplex on the mac */
-	ctrl = er32(CTRL);
-	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ctrl &= ~E1000_CTRL_SPD_SEL;
-
-	/* Disable Auto Speed Detection */
-	ctrl &= ~E1000_CTRL_ASDE;
-
-	/* Disable autoneg on the phy */
-	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
-
-	/* Forcing Full or Half Duplex? */
-	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
-		ctrl &= ~E1000_CTRL_FD;
-		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
-		hw_dbg(hw, "Half Duplex\n");
-	} else {
-		ctrl |= E1000_CTRL_FD;
-		*phy_ctrl |= MII_CR_FULL_DUPLEX;
-		hw_dbg(hw, "Full Duplex\n");
-	}
-
-	/* Forcing 10mb or 100mb? */
-	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
-		ctrl |= E1000_CTRL_SPD_100;
-		*phy_ctrl |= MII_CR_SPEED_100;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-		hw_dbg(hw, "Forcing 100mb\n");
-	} else {
-		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-		*phy_ctrl |= MII_CR_SPEED_10;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-		hw_dbg(hw, "Forcing 10mb\n");
-	}
-
-	e1000e_config_collision_dist(hw);
-
-	ew32(CTRL, ctrl);
-}
-
-/**
- *  e1000e_set_d3_lplu_state - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.
- **/
-s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		return ret_val;
-
-	if (!active) {
-		data &= ~IGP02E1000_PM_D3_LPLU;
-		ret_val = e1e_wphy(hw,
-					     IGP02E1000_PHY_POWER_MGMT,
-					     data);
-		if (ret_val)
-			return ret_val;
-		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained. */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						    &data);
-			if (ret_val)
-				return ret_val;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     &data);
-			if (ret_val)
-				return ret_val;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-						     data);
-			if (ret_val)
-				return ret_val;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		data |= IGP02E1000_PM_D3_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
-		if (ret_val)
-			return ret_val;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
-		if (ret_val)
-			return ret_val;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_check_downshift - Checks whether a downshift in speed occured
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns 1
- *
- *  A downshift is detected by querying the PHY link health.
- **/
-s32 e1000e_check_downshift(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	switch (phy->type) {
-	case e1000_phy_m88:
-	case e1000_phy_gg82563:
-		offset	= M88E1000_PHY_SPEC_STATUS;
-		mask	= M88E1000_PSSR_DOWNSHIFT;
-		break;
-	case e1000_phy_igp_2:
-	case e1000_phy_igp_3:
-		offset	= IGP01E1000_PHY_LINK_HEALTH;
-		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
-		break;
-	default:
-		/* speed downshift not supported */
-		phy->speed_downgraded = 0;
-		return 0;
-	}
-
-	ret_val = e1e_rphy(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->speed_downgraded = (phy_data & mask);
-
-	return ret_val;
-}
-
-/**
- *  e1000_check_polarity_m88 - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY specific status register.
- **/
-static s32 e1000_check_polarity_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
-				      ? e1000_rev_polarity_reversed
-				      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000_check_polarity_igp - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY port status register, and the
- *  current speed (since there is no polarity at 100Mbps).
- **/
-static s32 e1000_check_polarity_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data, offset, mask;
-
-	/* Polarity is determined based on the speed of
-	 * our connection. */
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		return ret_val;
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		offset	= IGP01E1000_PHY_PCS_INIT_REG;
-		mask	= IGP01E1000_PHY_POLARITY_MASK;
-	} else {
-		/* This really only applies to 10Mbps since
-		 * there is no polarity for 100Mbps (always 0).
-		 */
-		offset	= IGP01E1000_PHY_PORT_STATUS;
-		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
-	}
-
-	ret_val = e1e_rphy(hw, offset, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & mask)
-				      ? e1000_rev_polarity_reversed
-				      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000_wait_autoneg - Wait for auto-neg compeletion
- *  @hw: pointer to the HW structure
- *
- *  Waits for auto-negotiation to complete or for the auto-negotiation time
- *  limit to expire, which ever happens first.
- **/
-static s32 e1000_wait_autoneg(struct e1000_hw *hw)
-{
-	s32 ret_val = 0;
-	u16 i, phy_status;
-
-	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
-	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_AUTONEG_COMPLETE)
-			break;
-		msleep(100);
-	}
-
-	/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
-	 * has completed.
-	 */
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_has_link_generic - Polls PHY for link
- *  @hw: pointer to the HW structure
- *  @iterations: number of times to poll for link
- *  @usec_interval: delay between polling attempts
- *  @success: pointer to whether polling was successful or not
- *
- *  Polls the PHY status register for link, 'iterations' number of times.
- **/
-s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-			       u32 usec_interval, bool *success)
-{
-	s32 ret_val = 0;
-	u16 i, phy_status;
-
-	for (i = 0; i < iterations; i++) {
-		/* Some PHYs require the PHY_STATUS register to be read
-		 * twice due to the link bit being sticky.  No harm doing
-		 * it across the board.
-		 */
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_LINK_STATUS)
-			break;
-		if (usec_interval >= 1000)
-			mdelay(usec_interval/1000);
-		else
-			udelay(usec_interval);
-	}
-
-	*success = (i < iterations);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_get_cable_length_m88 - Determine cable length for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY specific status register to retrieve the cable length
- *  information.  The cable length is determined by averaging the minimum and
- *  maximum values to get the "average" cable length.  The m88 PHY has four
- *  possible cable length values, which are:
- *	Register Value		Cable Length
- *	0			< 50 meters
- *	1			50 - 80 meters
- *	2			80 - 110 meters
- *	3			110 - 140 meters
- *	4			> 140 meters
- **/
-s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, index;
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-		M88E1000_PSSR_CABLE_LENGTH_SHIFT;
-	phy->min_cable_length = e1000_m88_cable_length_table[index];
-	phy->max_cable_length = e1000_m88_cable_length_table[index+1];
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY
- *  @hw: pointer to the HW structure
- *
- *  The automatic gain control (agc) normalizes the amplitude of the
- *  received signal, adjusting for the attenuation produced by the
- *  cable.  By reading the AGC registers, which reperesent the
- *  cobination of course and fine gain value, the value can be put
- *  into a lookup table to obtain the approximate cable length
- *  for each channel.
- **/
-s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, i, agc_value = 0;
-	u16 cur_agc_index, max_agc_index = 0;
-	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
-	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
-							 {IGP02E1000_PHY_AGC_A,
-							  IGP02E1000_PHY_AGC_B,
-							  IGP02E1000_PHY_AGC_C,
-							  IGP02E1000_PHY_AGC_D};
-
-	/* Read the AGC registers for all channels */
-	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
-		ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);
-		if (ret_val)
-			return ret_val;
-
-		/* Getting bits 15:9, which represent the combination of
-		 * course and fine gain values.  The result is a number
-		 * that can be put into the lookup table to obtain the
-		 * approximate cable length. */
-		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
-				IGP02E1000_AGC_LENGTH_MASK;
-
-		/* Array index bound check. */
-		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
-		    (cur_agc_index == 0))
-			return -E1000_ERR_PHY;
-
-		/* Remove min & max AGC values from calculation. */
-		if (e1000_igp_2_cable_length_table[min_agc_index] >
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			min_agc_index = cur_agc_index;
-		if (e1000_igp_2_cable_length_table[max_agc_index] <
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			max_agc_index = cur_agc_index;
-
-		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
-	}
-
-	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
-		      e1000_igp_2_cable_length_table[max_agc_index]);
-	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
-
-	/* Calculate cable length with the error range of +/- 10 meters. */
-	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
-				 (agc_value - IGP02E1000_AGC_RANGE) : 0;
-	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_get_phy_info_m88 - Retrieve PHY information
- *  @hw: pointer to the HW structure
- *
- *  Valid for only copper links.  Read the PHY status register (sticky read)
- *  to verify that link is up.  Read the PHY special control register to
- *  determine the polarity and 10base-T extended distance.  Read the PHY
- *  special status register to determine MDI/MDIx and current speed.  If
- *  speed is 1000, then determine cable length, local and remote receiver.
- **/
-s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32  ret_val;
-	u16 phy_data;
-	bool link;
-
-	if (hw->media_type != e1000_media_type_copper) {
-		hw_dbg(hw, "Phy info is only valid for copper media\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		return ret_val;
-
-	if (!link) {
-		hw_dbg(hw, "Phy info is only valid if link is up\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy->polarity_correction = (phy_data &
-				    M88E1000_PSCR_POLARITY_REVERSAL);
-
-	ret_val = e1000_check_polarity_m88(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		return ret_val;
-
-	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX);
-
-	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
-		ret_val = e1000_get_cable_length(hw);
-		if (ret_val)
-			return ret_val;
-
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
-		if (ret_val)
-			return ret_val;
-
-		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
-				? e1000_1000t_rx_status_ok
-				: e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
-				 ? e1000_1000t_rx_status_ok
-				 : e1000_1000t_rx_status_not_ok;
-	} else {
-		/* Set values to "undefined" */
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_get_phy_info_igp - Retrieve igp PHY information
- *  @hw: pointer to the HW structure
- *
- *  Read PHY status to determine if link is up.  If link is up, then
- *  set/determine 10base-T extended distance and polarity correction.  Read
- *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
- *  determine on the cable length, local and remote receiver.
- **/
-s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		return ret_val;
-
-	if (!link) {
-		hw_dbg(hw, "Phy info is only valid if link is up\n");
-		return -E1000_ERR_CONFIG;
-	}
-
-	phy->polarity_correction = 1;
-
-	ret_val = e1000_check_polarity_igp(hw);
-	if (ret_val)
-		return ret_val;
-
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		return ret_val;
-
-	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX);
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		ret_val = e1000_get_cable_length(hw);
-		if (ret_val)
-			return ret_val;
-
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
-		if (ret_val)
-			return ret_val;
-
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-				? e1000_1000t_rx_status_ok
-				: e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-				 ? e1000_1000t_rx_status_ok
-				 : e1000_1000t_rx_status_not_ok;
-	} else {
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_sw_reset - PHY software reset
- *  @hw: pointer to the HW structure
- *
- *  Does a software reset of the PHY by reading the PHY control register and
- *  setting/write the control register reset bit to the PHY.
- **/
-s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 phy_ctrl;
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		return ret_val;
-
-	phy_ctrl |= MII_CR_RESET;
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		return ret_val;
-
-	udelay(1);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_hw_reset_generic - PHY hardware reset
- *  @hw: pointer to the HW structure
- *
- *  Verify the reset block is not blocking us from resetting.  Acquire
- *  semaphore (if necessary) and read/set/write the device control reset
- *  bit in the PHY.  Wait the appropriate delay time for the device to
- *  reset and relase the semaphore (if necessary).
- **/
-s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u32 ctrl;
-
-	ret_val = e1000_check_reset_block(hw);
-	if (ret_val)
-		return 0;
-
-	ret_val = phy->ops.acquire_phy(hw);
-	if (ret_val)
-		return ret_val;
-
-	ctrl = er32(CTRL);
-	ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
-	e1e_flush();
-
-	udelay(phy->reset_delay_us);
-
-	ew32(CTRL, ctrl);
-	e1e_flush();
-
-	udelay(150);
-
-	phy->ops.release_phy(hw);
-
-	return e1000_get_phy_cfg_done(hw);
-}
-
-/**
- *  e1000e_get_cfg_done - Generic configuration done
- *  @hw: pointer to the HW structure
- *
- *  Generic function to wait 10 milli-seconds for configuration to complete
- *  and return success.
- **/
-s32 e1000e_get_cfg_done(struct e1000_hw *hw)
-{
-	mdelay(10);
-	return 0;
-}
-
-/* Internal function pointers */
-
-/**
- *  e1000_get_phy_cfg_done - Generic PHY configuration done
- *  @hw: pointer to the HW structure
- *
- *  Return success if silicon family did not implement a family specific
- *  get_cfg_done function.
- **/
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_cfg_done)
-		return hw->phy.ops.get_cfg_done(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
- *  @hw: pointer to the HW structure
- *
- *  When the silicon family has not implemented a forced speed/duplex
- *  function for the PHY, simply return 0.
- **/
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.force_speed_duplex)
-		return hw->phy.ops.force_speed_duplex(hw);
-
-	return 0;
-}
-
-/**
- *  e1000e_get_phy_type_from_id - Get PHY type from id
- *  @phy_id: phy_id read from the phy
- *
- *  Returns the phy type from the id.
- **/
-enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
-{
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	switch (phy_id) {
-	case M88E1000_I_PHY_ID:
-	case M88E1000_E_PHY_ID:
-	case M88E1111_I_PHY_ID:
-	case M88E1011_I_PHY_ID:
-		phy_type = e1000_phy_m88;
-		break;
-	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
-		phy_type = e1000_phy_igp_2;
-		break;
-	case GG82563_E_PHY_ID:
-		phy_type = e1000_phy_gg82563;
-		break;
-	case IGP03E1000_E_PHY_ID:
-		phy_type = e1000_phy_igp_3;
-		break;
-	case IFE_E_PHY_ID:
-	case IFE_PLUS_E_PHY_ID:
-	case IFE_C_E_PHY_ID:
-		phy_type = e1000_phy_ife;
-		break;
-	default:
-		phy_type = e1000_phy_unknown;
-		break;
-	}
-	return phy_type;
-}
-
-/**
- *  e1000e_commit_phy - Soft PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a soft PHY reset on those that apply. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 e1000e_commit_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.commit_phy)
-		return hw->phy.ops.commit_phy(hw);
-
-	return 0;
-}
-
-/**
- *  e1000_set_d0_lplu_state - Sets low power link up state for D0
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D0
- *  and SmartSpeed is disabled when active is true, else clear lplu for D0
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
-{
-	if (hw->phy.ops.set_d0_lplu_state)
-		return hw->phy.ops.set_d0_lplu_state(hw, active);
-
-	return 0;
-}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/gpl.txt linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/gpl.txt
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/gpl.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/gpl.txt	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.c	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,1541 @@
+/** @file if_sdio.c
+ *  @brief This file contains SDIO IF (interface) module
+ *  related functions.
+ * 
+ * Copyright 2007 Intel Corporation and its suppliers. All rights reserved
+ * 
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+	10/14/05: add Doxygen format comments 
+	01/05/06: add kernel 2.6.x support
+	01/23/06: add fw downlaod
+	06/06/06: add macro SD_BLOCK_SIZE_FW_DL for firmware download
+		  add macro ALLOC_BUF_SIZE for cmd resp/Rx data skb buffer allocation
+****************************************************/
+
+#include	"if_sdio.h"
+
+#include <linux/firmware.h>
+
+/* define SD block size for firmware download */
+#define SD_BLOCK_SIZE_FW_DL	32
+/* define SD block size for data Tx/Rx */
+#define SD_BLOCK_SIZE		32
+
+#define ALLOC_BUF_SIZE		(((MAX(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, \
+					MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
+					+ SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
+
+/* Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY	2
+
+#define GPIO_PORT_TO_HIGH()	sd_set_gpo(priv, 1)
+#define GPIO_PORT_TO_LOW()	sd_set_gpo(priv, 0)
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+static wlan_private *pwlanpriv;
+static wlan_private *(*wlan_add_callback) (void *dev_id);
+static int (*wlan_remove_callback) (void *dev_id);
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+#define SDIO_CLK_RATE_6MHZ	6       /* MHz */
+#define SDIO_CLK_RATE_12MHZ	12      /* MHz */
+#define SDIO_CLK_RATE_25MHZ	25      /* MHz */
+#define SDIO_CLK_RATE_DEFAULT	0
+int clkrate = SDIO_CLK_RATE_DEFAULT;
+module_param(clkrate, int, 0);
+
+int request_gpio_irq_callback(void (*callback) (void *), void *arg);
+int release_gpio_irq_callback(void (*callback) (void *), void *arg);
+
+#define DEFAULT_HELPER_NAME "mrvl/helper_sd.bin"
+#define DEFAULT_FW_NAME "mrvl/sd8686.bin"
+
+//#define BUS_INTERFACE_CONTROL_REG	0x07
+#define BUS_IF_CTRL	0x07
+extern u8 *helper_name;
+extern u8 *fw_name;
+
+struct net_device *the_netdev = NULL;
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/* some sdio wrapper API */
+static int sdio_read_byte(struct sdio_func *func, u32 addr, u8 *pdata)
+{
+	int ret;
+	sdio_claim_host(func);
+	*pdata = sdio_readb(func, addr, &ret);
+	sdio_release_host(func);
+	return ret;
+}
+
+static int sdio_write_byte(struct sdio_func *func, u32 addr, u8 data)
+{
+	int ret;
+	sdio_claim_host(func);
+	sdio_writeb(func, data, addr, &ret);
+	sdio_release_host(func);
+	return ret;
+}
+
+static int sdio_card_readb(struct sdio_func *func, u32 addr, u8 *data)
+{
+	int ret;
+
+	sdio_claim_host(func);
+	*data = sdio_f0_readb(func, addr, &ret);
+	sdio_release_host(func);
+
+	return ret;
+}
+
+static int sdio_card_writeb(struct sdio_func *func, u32 addr, u8 data)
+{
+	int ret;
+
+	sdio_claim_host(func);
+	sdio_f0_writeb(func, data, addr, &ret);
+	sdio_release_host(func);
+
+	return ret;
+}
+
+int sbi_read_ioreg(wlan_private * priv, u32 reg, u8 *pdata)
+{
+	struct sdio_func *func = (struct sdio_func*)(priv->wlan_dev.card);
+	int ret;
+
+	ret = sdio_read_byte(func, reg, pdata);
+	return ret;
+}
+
+int sbi_write_ioreg(wlan_private * priv, u32 reg, u8 data)
+{
+    	struct sdio_func *func = (struct sdio_func*)(priv->wlan_dev.card);
+	int ret;
+
+	ret = sdio_write_byte(func, reg, data);
+	return ret;
+}
+
+int sbi_write_iomem(wlan_private * priv, u32 reg,
+			ssize_t cnt, ssize_t blksz, u8 * dat)
+{
+	struct sdio_func *func = (struct sdio_func*)(priv->wlan_dev.card);
+	int ret;
+	
+	/* feng: need set the block size here */
+	sdio_claim_host(func);
+	if (blksz != func->cur_blksize) { 
+		ret = sdio_set_block_size(func, blksz);
+		if (ret) {
+			sdio_release_host(func);
+			return ret;
+		}
+	}
+
+	ret = sdio_writesb(func, reg, dat, cnt * blksz);
+	sdio_release_host(func);
+	return ret;
+}
+
+int sbi_read_iomem(wlan_private * priv, u32 reg,
+			ssize_t cnt, ssize_t blksz, u8 * dat)
+{
+	struct sdio_func *func = (struct sdio_func*)(priv->wlan_dev.card);
+	int ret;
+
+	sdio_claim_host(func);
+	if (blksz != func->cur_blksize) { 
+		ret = sdio_set_block_size(func, blksz);
+		if (ret) {
+			sdio_release_host(func);
+			return ret;
+		}
+	}
+
+	ret = sdio_readsb(func, dat, reg, cnt * blksz);
+	sdio_release_host(func);
+	return ret;
+}
+
+void sbi_mmc_disable_host_int(wlan_private *priv) 
+{
+	struct sdio_func *func = (struct sdio_func *)(priv->wlan_dev.card);
+	struct mmc_host	*host;
+
+	host = func->card->host;
+	host->ops->enable_sdio_irq(host, 0);
+}
+
+void sbi_mmc_enable_host_int(wlan_private *priv, u8 bits)
+{
+	struct sdio_func *func = (struct sdio_func*)(priv->wlan_dev.card);
+	struct mmc_host	*host;
+
+	host = func->card->host;
+	host->ops->enable_sdio_irq(host, 1);
+}
+
+
+#if 0
+/** 
+ *  @brief This function adds the card
+ *  
+ *  @param card    A pointer to the card
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+sbi_add_card(void *card)
+{
+    if (!wlan_add_callback)
+        return WLAN_STATUS_FAILURE;
+
+	pwlanpriv = wlan_add_callback(card);
+
+    if (pwlanpriv)
+        return WLAN_STATUS_SUCCESS;
+    else
+        return WLAN_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief This function removes the card
+ *  
+ *  @param card    A pointer to the card
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+sbi_remove_card(void *card)
+{
+    if (!wlan_remove_callback)
+        return WLAN_STATUS_FAILURE;
+
+    pwlanpriv = NULL;
+    return wlan_remove_callback(card);
+}
+#endif
+
+/** 
+ *  @brief This function reads scratch registers
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param dat	   A pointer to keep returned data
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+mv_sdio_read_scratch(wlan_private * priv, u16 * dat)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 scr0;
+    u8 scr1;
+    ret = sbi_read_ioreg(priv, CARD_OCR_0_REG, &scr0);
+    if (ret < 0)
+        return WLAN_STATUS_FAILURE;
+
+    ret = sbi_read_ioreg(priv, CARD_OCR_1_REG, &scr1);
+    PRINTM(INFO, "CARD_OCR_0_REG = 0x%x, CARD_OCR_1_REG = 0x%x\n", scr0,
+           scr1);
+    if (ret < 0)
+        return WLAN_STATUS_FAILURE;
+
+    *dat = (((u16) scr1) << 8) | scr0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function polls the card status register.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param bits    	the bit mask
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+mv_sdio_poll_card_status(wlan_private * priv, u8 bits)
+{
+    int tries;
+    int rval;
+    u8 cs;
+
+    for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
+        rval = sbi_read_ioreg(priv,
+                               CARD_STATUS_REG, &cs);
+        if (rval == 0 && (cs & bits) == bits) {
+            return WLAN_STATUS_SUCCESS;
+        }
+
+        udelay(1);
+    }
+
+    PRINTM(WARN, "mv_sdio_poll_card_status: FAILED!:%d\n", rval);
+    return WLAN_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief This function programs the firmware image.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param firmware 	A pointer to the buffer of firmware image
+ *  @param firmwarelen 	the length of firmware image
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+sbi_prog_firmware_image(wlan_private * priv,
+                        const u8 * firmware, int firmwarelen)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 firmwarestat;
+    u8 *fwbuf = priv->adapter->TmpTxBuf;
+    int fwblknow;
+    u32 tx_len;
+#ifdef FW_DOWNLOAD_SPEED
+    u32 tv1, tv2;
+#endif
+
+    ENTER();
+
+    /* Check if the firmware is already downloaded */
+    if ((ret = mv_sdio_read_scratch(priv, &firmwarestat)) < 0) {
+        PRINTM(INFO, "read scratch returned <0\n");
+        goto done;
+    }
+
+    if (firmwarestat == FIRMWARE_READY) {
+        PRINTM(INFO, "FW already downloaded!\n");
+        ret = WLAN_STATUS_SUCCESS;
+        goto done;
+    }
+
+    PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
+           firmwarelen, SD_BLOCK_SIZE_FW_DL);
+
+#ifdef FW_DOWNLOAD_SPEED
+    tv1 = get_utimeofday();
+#endif
+    /* Perform firmware data transfer */
+    tx_len =
+        (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE_FW_DL) - SDIO_HEADER_LEN;
+    for (fwblknow = 0; fwblknow < firmwarelen; fwblknow += tx_len) {
+
+        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+        ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+        if (ret < 0) {
+            PRINTM(FATAL, "FW download died @ %d\n", fwblknow);
+            goto done;
+        }
+
+        /* Set blocksize to transfer - checking for last block */
+        if (firmwarelen - fwblknow < tx_len)
+            tx_len = firmwarelen - fwblknow;
+
+        fwbuf[0] = ((tx_len & 0x000000ff) >> 0);        /* Little-endian */
+        fwbuf[1] = ((tx_len & 0x0000ff00) >> 8);
+        fwbuf[2] = ((tx_len & 0x00ff0000) >> 16);
+        fwbuf[3] = ((tx_len & 0xff000000) >> 24);
+
+        /* Copy payload to buffer */
+        memcpy(&fwbuf[SDIO_HEADER_LEN], &firmware[fwblknow], tx_len);
+
+        PRINTM(INFO, ".");
+
+        /* Send data */
+        ret = sbi_write_iomem(priv,
+                               priv->wlan_dev.ioport,
+                               FIRMWARE_TRANSFER_NBLOCK,
+                               SD_BLOCK_SIZE_FW_DL, fwbuf);
+
+        if (ret < 0) {
+            PRINTM(FATAL, "IO error: transferring block @ %d\n", fwblknow);
+            goto done;
+        }
+    }
+
+#ifdef FW_DOWNLOAD_SPEED
+    tv2 = get_utimeofday();
+    PRINTM(INFO, "helper: %ld.%03ld.%03ld ", tv1 / 1000000,
+           (tv1 % 1000000) / 1000, tv1 % 1000);
+    PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+    tv2 -= tv1;
+    PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+#endif
+    mdelay(1);
+
+    /* Write last EOF data */
+    PRINTM(INFO, "\nTransferring EOF block\n");
+    memset(fwbuf, 0x0, SD_BLOCK_SIZE_FW_DL);
+    ret = sbi_write_iomem(priv,
+                           priv->wlan_dev.ioport,
+                           1, SD_BLOCK_SIZE_FW_DL, fwbuf);
+
+    if (ret < 0) {
+        PRINTM(FATAL, "IO error in writing EOF FW block\n");
+        goto done;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+
+  done:
+    return ret;
+}
+
+/** 
+ *  @brief This function downloads firmware image to the card.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param firmware	A pointer to firmware image buffer
+ *  @param firmwarelen	the length of firmware image
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+sbi_download_wlan_fw_image(wlan_private * priv,
+                           const u8 * firmware, int firmwarelen)
+{
+    u8 base0;
+    u8 base1;
+    int ret = WLAN_STATUS_SUCCESS;
+    int offset;
+    u8 *fwbuf = priv->adapter->TmpTxBuf;
+    int timeout = 5000;
+    u16 len;
+    int txlen = 0;
+    int tx_blocks = 0;
+    int i = 0;
+#ifdef FW_DOWNLOAD_SPEED
+    u32 tv1, tv2;
+#endif
+
+    ENTER();
+
+    PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
+
+#ifdef FW_DOWNLOAD_SPEED
+    tv1 = get_utimeofday();
+#endif
+
+    /* Wait initially for the first non-zero value */
+    do {
+        if ((ret = sbi_read_ioreg(priv,
+                                   HOST_F1_RD_BASE_0, &base0)) < 0) {
+            PRINTM(WARN, "Dev BASE0 register read failed:"
+                   " base0=0x%04X(%d)\n", base0, base0);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        if ((ret = sbi_read_ioreg(priv,
+                                   HOST_F1_RD_BASE_1, &base1)) < 0) {
+            PRINTM(WARN, "Dev BASE1 register read failed:"
+                   " base1=0x%04X(%d)\n", base1, base1);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        len = (((u16) base1) << 8) | base0;
+        mdelay(1);
+    } while (!len && --timeout);
+
+    if (!timeout) {
+        PRINTM(MSG, "Helper downloading finished.\n");
+        PRINTM(MSG, "Timeout for FW downloading!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+    ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+    if (ret < 0) {
+        PRINTM(FATAL, "FW download died, helper not ready\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    len &= ~B_BIT_0;
+
+    /* Perform firmware data transfer */
+    for (offset = 0; offset < firmwarelen; offset += txlen) {
+        txlen = len;
+
+        /* Set blocksize to transfer - checking for last block */
+        if (firmwarelen - offset < txlen) {
+            txlen = firmwarelen - offset;
+        }
+        /* PRINTM(INFO, "fw: offset=%d, txlen = 0x%04X(%d)\n", 
+           offset,txlen,txlen); */
+        PRINTM(INFO, ".");
+
+        tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL;
+
+        /* Copy payload to buffer */
+        memcpy(fwbuf, &firmware[offset], txlen);
+
+        /* Send data */
+        ret = sbi_write_iomem(priv,
+                               priv->wlan_dev.ioport,
+                               tx_blocks, SD_BLOCK_SIZE_FW_DL,
+                               fwbuf);
+
+        if (ret < 0) {
+            PRINTM(ERROR, "FW download, write iomem (%d) failed: %d\n", i,
+                   ret);
+            if (sbi_write_ioreg
+                (priv, CONFIGURATION_REG, 0x04) < 0) {
+                PRINTM(ERROR, "write ioreg failed (FN1 CFG)\n");
+            }
+        }
+
+        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+        ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+        if (ret < 0) {
+            PRINTM(FATAL, "FW download with helper died @ %d\n", offset);
+            goto done;
+        }
+
+        if ((ret = sbi_read_ioreg(priv,
+                                   HOST_F1_RD_BASE_0, &base0)) < 0) {
+            PRINTM(WARN, "Dev BASE0 register read failed:"
+                   " base0=0x%04X(%d)\n", base0, base0);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        if ((ret = sbi_read_ioreg(priv,
+                                   HOST_F1_RD_BASE_1, &base1)) < 0) {
+            PRINTM(WARN, "Dev BASE1 register read failed:"
+                   " base1=0x%04X(%d)\n", base1, base1);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        len = (((u16) base1) << 8) | base0;
+
+        if (!len) {
+            break;
+        }
+
+        if (len & B_BIT_0) {
+            i++;
+            if (i > MAX_WRITE_IOMEM_RETRY) {
+                PRINTM(FATAL, "FW download failure, over max retry count\n");
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            PRINTM(ERROR, "CRC error indicated by the helper:"
+                   " len = 0x%04X, txlen = %d\n", len, txlen);
+            len &= ~B_BIT_0;
+            /* Setting this to 0 to resend from same offset */
+            txlen = 0;
+        } else
+            i = 0;
+    }
+    PRINTM(INFO, "\nFW download over, size %d bytes\n", firmwarelen);
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+#ifdef FW_DOWNLOAD_SPEED
+    tv2 = get_utimeofday();
+    PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
+           (tv1 % 1000000) / 1000, tv1 % 1000);
+    PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+    tv2 -= tv1;
+    PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+#endif
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function reads data from the card.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param type	   	A pointer to keep type as data or command
+ *  @param nb		A pointer to keep the data/cmd length retured in buffer
+ *  @param payload 	A pointer to the data/cmd buffer
+ *  @param nb	   	the length of data/cmd buffer
+ *  @param npayload	the length of data/cmd buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+mv_sdio_card_to_host(wlan_private * priv,
+                     u32 * type, int *nb, u8 * payload, int npayload)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 buf_len = 0;
+    int buf_block_len;
+    int blksz;
+    u32 *pevent;
+
+    if (!payload) {
+        PRINTM(WARN, "payload NULL pointer received!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+
+    /* Read the length of data to be transferred */
+    ret = mv_sdio_read_scratch(priv, &buf_len);
+    if (ret < 0) {
+        PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+
+    if (buf_len <= SDIO_HEADER_LEN || buf_len > npayload) {
+        PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+
+    /* Allocate buffer */
+    blksz = SD_BLOCK_SIZE;
+    buf_block_len = (buf_len + blksz - 1) / blksz;
+
+    ret = sbi_read_iomem(priv, priv->wlan_dev.ioport,
+                          buf_block_len, blksz, payload);
+
+    if (ret < 0) {
+        PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+    *nb = buf_len;
+
+    DBG_HEXDUMP(IF_D, "SDIO Blk Rd", payload, blksz * buf_block_len);
+
+    *type = (payload[2] | (payload[3] << 8));
+    if (*type == MVSD_EVENT) {
+        pevent = (u32 *) & payload[4];
+        priv->adapter->EventCause = MVSD_EVENT | (((u16) (*pevent)) << 3);
+    }
+
+  exit:
+    return ret;
+}
+
+/** 
+ *  @brief This function enables the host interrupts mask
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param mask	   the interrupt mask
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+static int
+enable_host_int_mask(wlan_private * priv, u8 mask)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    /* Simply write the mask to the register */
+    ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, mask);
+
+    if (ret < 0) {
+        PRINTM(WARN, "ret = %d\n", ret);
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    priv->adapter->HisRegCpy = 1;
+
+    return ret;
+}
+
+/**  @brief This function disables the host interrupts mask.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param mask	   the interrupt mask
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+disable_host_int_mask(wlan_private * priv, u8 mask)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 host_int_mask;
+
+    /* Read back the host_int_mask register */
+    ret = sbi_read_ioreg(priv, HOST_INT_MASK_REG,
+                          &host_int_mask);
+    if (ret < 0) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Update with the mask and write back to the register */
+    host_int_mask &= ~mask;
+    ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG,
+                           host_int_mask);
+    if (ret < 0) {
+        PRINTM(WARN, "Unable to diable the host interrupt!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    return ret;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+int start_bus_clock(mmc_controller_t);
+int stop_bus_clock_2(mmc_controller_t);
+
+void
+gpio_irq_callback(void *arg)
+{
+    wlan_private *priv = (wlan_private *) arg;
+
+    //PRINTM(INFO, "gpio_irq_callback() called\n");
+    //if (wlan_host_sleep_gpio_int_event(priv))
+    //    PRINTM(FATAL, "gpio_irq_handler(): sending event failed\n");
+}
+
+/** 
+ *  @brief This function handles the interrupt.
+ *  
+ *  @param irq 	   The irq of device.
+ *  @param dev_id  A pointer to net_device structure
+ *  @param fp	   A pointer to pt_regs structure
+ *  @return 	   n/a
+ */
+static void sbi_interrupt(struct sdio_func  *func)
+{
+    wlan_interrupt(the_netdev);
+}
+
+static int sbi_dev_probe_func(struct sdio_func *func, const struct sdio_device_id *id)
+{
+	int result, ret = WLAN_STATUS_SUCCESS;
+    	u8 chiprev, bic;   
+
+	umd_dbg("enter, func = 0x%08x", func);
+    
+	result = sdio_read_byte(func, CARD_REVISION_REG, &chiprev);
+
+	/* read Revision Register to get the hw revision number */
+	if (result) {
+		printk("cannot read CARD_REVISION_REG\n");
+	} else {
+		umd_dbg("revision=0x%x\n", chiprev);
+		switch (chiprev) {
+		default:
+			/* enable async interrupt mode */
+			sdio_card_readb(func, BUS_IF_CTRL, &bic);
+			bic |= ASYNC_INT_MODE;
+			sdio_card_writeb(func, BUS_IF_CTRL, bic);
+			break;
+		}
+    	}
+
+	if (!wlan_add_callback)
+		goto done;
+
+	umd_dbg("will call sdio_enable_func");
+	sdio_claim_host(func);
+	ret = sdio_enable_func(func);
+	sdio_release_host(func);
+	if (ret) {
+		printk(KERN_ALERT "Fail to enable func\n");
+		ret = WLAN_STATUS_FAILURE;
+		goto done;
+	}
+
+	/* feng: here we need add the irq hook */
+	sdio_claim_host(func);
+	ret =  sdio_claim_irq(func, sbi_interrupt);
+	sdio_release_host(func);
+        
+	umd_dbg("Will call the wlan_add_callback");
+	pwlanpriv = wlan_add_callback(func);
+
+	if (pwlanpriv)
+		ret = WLAN_STATUS_SUCCESS;
+	else
+		ret = WLAN_STATUS_FAILURE;
+
+	//sdio_claim_host(func);
+       //sdio_dump_cccr(func);
+	//sdio_release_host(func);
+	umd_dbg("exit, ret = %d", ret);
+done:
+	LEAVE();
+	return ret;
+}
+
+static void sbi_dev_remove_func(struct sdio_func *func)
+{
+	if (!wlan_remove_callback)
+		return WLAN_STATUS_FAILURE;
+	pwlanpriv = NULL;
+
+	wlan_remove_callback(func);
+
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+}
+
+
+static const struct sdio_device_id sdio_8686_ids[] = {
+	{ SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN)		},
+	{ /* end: all zeroes */				},
+};
+
+//MODULE_DEVICE_TABLE(sdio, sdio_8686_ids);
+
+static struct sdio_driver sdio8686_driver = {
+	.probe		= sbi_dev_probe_func,
+	.remove		= sbi_dev_remove_func,
+	.name 		= "sdio_8686",
+	.id_table	= sdio_8686_ids,
+};
+
+int *sbi_register(wlan_notifier_fn_add add, 
+		wlan_notifier_fn_remove remove, void *arg)
+{
+	umd_enter();
+	wlan_add_callback = add;
+	wlan_remove_callback = remove;
+
+	sdio_register_driver(&sdio8686_driver);
+	umd_exit();
+	return (int *) wlan_add_callback;
+}
+
+void sbi_unregister(void)
+{
+	sdio_unregister_driver(&sdio8686_driver);
+
+	wlan_add_callback = NULL;
+	wlan_remove_callback = NULL;	
+}
+
+
+#if 0
+/** 
+ *  @brief This function registers the IF module in bus driver.
+ *  
+ *  @param add	   wlan driver's call back funtion for add card.
+ *  @param remove  wlan driver's call back funtion for remove card.
+ *  @param arg     not been used
+ *  @return	   An int pointer that keeps returned value
+ */
+int *
+sbi_register(wlan_notifier_fn_add add, wlan_notifier_fn_remove remove,
+             void *arg)
+{
+    int *sdio_ret;
+
+    ENTER();
+
+    wlan_add_callback = add;
+    wlan_remove_callback = remove;
+
+    if_sdio_notifier.add = (mmc_notifier_fn_t) sbi_add_card;
+    if_sdio_notifier.remove = (mmc_notifier_fn_t) sbi_remove_card;
+    isr_function = sbi_interrupt;
+    sdio_ret = sdio_register(MMC_REG_TYPE_USER, &if_sdio_notifier, 0);
+
+    LEAVE();
+
+    return sdio_ret;
+}
+
+/** 
+ *  @brief This function de-registers the IF module in bus driver.
+ *  
+ *  @return 	   n/a
+ */
+void
+sbi_unregister(void)
+{
+    sdio_unregister(MMC_REG_TYPE_USER, &if_sdio_notifier);
+}
+
+/** 
+ *  @brief This function reads the IO register.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param func	   funcion number
+ *  @param reg	   register to be read
+ *  @param dat	   A pointer to variable that keeps returned value
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_read_ioreg(wlan_private * priv, u32 reg, u8 * dat)
+{
+    return sbi_read_ioreg(priv, reg, dat);
+}
+
+/** 
+ *  @brief This function writes the IO register.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param func	   funcion number
+ *  @param reg	   register to be written
+ *  @param dat	   the value to be written
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_write_ioreg(wlan_private * priv, u32 reg, u8 dat)
+{
+    return sbi_write_ioreg(priv, reg, dat);
+}
+#endif
+
+/** 
+ *  @brief This function checks the interrupt status and handle it accordingly.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param ireg    A pointer to variable that keeps returned value
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+	int ret = WLAN_STATUS_SUCCESS;
+	u8 sdio_ireg = 0;
+	u8 *cmdBuf;
+	wlan_dev_t *wlan_dev = &priv->wlan_dev;
+	struct sk_buff *skb;
+
+	// feng: we mask it here, but this may be an issue
+	sbi_mmc_disable_host_int(priv);
+	
+	*ireg = 0;
+	if ((ret = sbi_read_ioreg(priv, HOST_INTSTATUS_REG, &sdio_ireg))) {
+		PRINTM(WARN, "sbi_read_ioreg: read int status register failed\n");
+		ret = WLAN_STATUS_FAILURE;
+		goto done;
+	}
+
+	if (sdio_ireg != 0) {
+		/*
+		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+		 * Clear the interrupt status register and re-enable the interrupt
+		 */
+		PRINTM(INFO, "sdio_ireg = 0x%x\n", sdio_ireg);
+		if ((ret = sbi_write_ioreg(priv, HOST_INTSTATUS_REG,
+				~(sdio_ireg) & (DN_LD_HOST_INT_STATUS | UP_LD_HOST_INT_STATUS))) <
+		    0) {
+		    PRINTM(WARN,
+		           "sbi_write_ioreg: clear int status register failed\n");
+		    ret = WLAN_STATUS_FAILURE;
+		    goto done;
+		}
+    	}
+
+	//sdio_unmask();
+
+    if (sdio_ireg & DN_LD_HOST_INT_STATUS) {    /* tx_done INT */
+	*ireg |= HIS_TxDnLdRdy;
+        if (!priv->wlan_dev.dnld_sent) {        /* tx_done already received */
+            PRINTM(INFO, "warning: tx_done already received:"
+                   " dnld_sent=0x%x int status=0x%x\n",
+                   priv->wlan_dev.dnld_sent, sdio_ireg);
+        } else {
+		wmm_process_fw_iface_tx_xfer_end(priv);
+		priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+        }
+    }
+
+    if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+
+        /* 
+         * DMA read data is by block alignment,so we need alloc extra block
+         * to avoid wrong memory access.
+         */
+        if (!(skb = dev_alloc_skb(ALLOC_BUF_SIZE))) {
+            PRINTM(WARN, "No free skb\n");
+            priv->stats.rx_dropped++;
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        /* 
+         * Transfer data from card
+         * skb->tail is passed as we are calling skb_put after we
+         * are reading the data
+         */
+        if (mv_sdio_card_to_host(priv, &wlan_dev->upld_typ,
+                                 (int *) &wlan_dev->upld_len, skb->tail,
+                                 ALLOC_BUF_SIZE) < 0) {
+            u8 cr = 0;
+
+            PRINTM(ERROR, "Card to host failed: int status=0x%x\n",
+                   sdio_ireg);
+            if (sbi_read_ioreg(priv, CONFIGURATION_REG, &cr) < 0)
+                PRINTM(ERROR, "read ioreg failed (FN1 CFG)\n");
+
+            PRINTM(INFO, "Config Reg val = %d\n", cr);
+            if (sbi_write_ioreg(priv, CONFIGURATION_REG, (cr | 0x04)) < 0)
+                PRINTM(ERROR, "write ioreg failed (FN1 CFG)\n");
+
+            PRINTM(INFO, "write success\n");
+            if (sbi_read_ioreg(priv, CONFIGURATION_REG, &cr) < 0)
+                PRINTM(ERROR, "read ioreg failed (FN1 CFG)\n");
+
+            PRINTM(INFO, "Config reg val =%x\n", cr);
+            ret = WLAN_STATUS_FAILURE;
+            kfree_skb(skb);
+            goto done;
+        }
+
+        switch (wlan_dev->upld_typ) {
+        case MVSD_DAT:
+            PRINTM(DATA, "Data <= FW\n");
+            *ireg |= HIS_RxUpLdRdy;
+            skb_put(skb, priv->wlan_dev.upld_len);
+            skb_pull(skb, SDIO_HEADER_LEN);
+            list_add_tail((struct list_head *) skb,
+                          (struct list_head *) &priv->adapter->RxSkbQ);
+            /* skb will be freed by kernel later */
+            break;
+
+        case MVSD_CMD:
+            *ireg |= HIS_CmdUpLdRdy;
+
+            /* take care of CurCmd = NULL case */
+            if (!priv->adapter->CurCmd) {
+                cmdBuf = priv->wlan_dev.upld_buf;
+            } else {
+                cmdBuf = priv->adapter->CurCmd->BufVirtualAddr;
+            }
+
+            priv->wlan_dev.upld_len -= SDIO_HEADER_LEN;
+            memcpy(cmdBuf, skb->data + SDIO_HEADER_LEN,
+                   MIN(MRVDRV_SIZE_OF_CMD_BUFFER, priv->wlan_dev.upld_len));
+            kfree_skb(skb);
+            break;
+
+        case MVSD_EVENT:
+            *ireg |= HIS_CardEvent;
+            /* event cause has been saved to priv->adapter->EventCause */
+            kfree_skb(skb);
+            break;
+
+        default:
+            PRINTM(ERROR, "SDIO unknown upld type = 0x%x\n",
+                   wlan_dev->upld_typ);
+            kfree_skb(skb);
+            break;
+        }
+    }
+
+    	ret = WLAN_STATUS_SUCCESS;
+done:
+	sbi_mmc_enable_host_int(priv, 0x00);
+    	return ret;
+}
+
+/** 
+ *  @brief This function is a dummy function.
+ *  
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_card_to_host(wlan_private * priv, u32 type,
+                 u32 * nb, u8 * payload, u16 npayload)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function is a dummy function.
+ *  
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_read_event_cause(wlan_private * priv)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function disables the host interrupts.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_disable_host_int(wlan_private * priv)
+{
+    return disable_host_int_mask(priv, HIM_DISABLE);
+}
+
+/** 
+ *  @brief This function enables the host interrupts.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_enable_host_int(wlan_private * priv)
+{
+    //sdio_enable_SDIO_INT();
+    return enable_host_int_mask(priv, HIM_ENABLE);
+}
+
+/** 
+ *  @brief This function de-registers the device.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_unregister_dev(wlan_private * priv)
+{
+	ENTER();
+
+	if (priv->wlan_dev.card != NULL) {
+		PRINTM(WARN, "Making the sdio dev card as NULL\n");
+	}
+
+	GPIO_PORT_TO_LOW();
+
+	LEAVE();
+	return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function registers the device.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_register_dev(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 reg;
+    struct sdio_func *func = (struct sdio_func *) priv->wlan_dev.card;
+
+    ENTER();
+
+    GPIO_PORT_TO_HIGH();
+
+    the_netdev = priv->wlan_dev.netdev;
+
+    priv->hotplug_device = &(func->card->dev);
+    if (helper_name == NULL) {
+        helper_name = DEFAULT_HELPER_NAME;
+    }
+    if (fw_name == NULL) {
+        fw_name = DEFAULT_FW_NAME;
+    }
+
+    /* Initialize the private structure */
+    strncpy(priv->wlan_dev.name, "sdio0", sizeof(priv->wlan_dev.name));
+    priv->wlan_dev.ioport = 0;
+    priv->wlan_dev.upld_rcv = 0;
+    priv->wlan_dev.upld_typ = 0;
+    priv->wlan_dev.upld_len = 0;
+
+    /* Read the IO port */
+    ret = sbi_read_ioreg(priv, IO_PORT_0_REG, &reg);
+    if (ret < 0)
+        goto failed;
+    else
+        priv->wlan_dev.ioport |= reg;
+
+    ret = sbi_read_ioreg(priv, IO_PORT_1_REG, &reg);
+    if (ret < 0)
+        goto failed;
+    else
+        priv->wlan_dev.ioport |= (reg << 8);
+
+    ret = sbi_read_ioreg(priv, IO_PORT_2_REG, &reg);
+    if (ret < 0)
+        goto failed;
+    else
+        priv->wlan_dev.ioport |= (reg << 16);
+
+    PRINTM(INFO, "SDIO FUNC1 IO port: 0x%x\n", priv->wlan_dev.ioport);
+
+    /* Disable host interrupt first. */
+    if ((ret = disable_host_int_mask(priv, 0xff)) < 0) {
+        PRINTM(WARN, "Warning: unable to disable host interrupt!\n");
+    }
+
+#if 0
+    /* Request the SDIO IRQ */
+    PRINTM(INFO, "Before request_irq Address is if==>%p\n", isr_function);
+    ret = sdio_request_irq(priv->wlan_dev.card,
+                           (handler_fn_t) isr_function, 0,
+                           "sdio_irq", priv->wlan_dev.netdev);
+
+    if (ret < 0) {
+        PRINTM(FATAL, "Failed to request IRQ on SDIO bus (%d)\n", ret);
+        goto failed;
+    }
+
+    PRINTM(INFO, "IrqLine: %d\n", card->ctrlr->tmpl->irq_line);
+    priv->wlan_dev.netdev->irq = card->ctrlr->tmpl->irq_line;
+    priv->adapter->irq = priv->wlan_dev.netdev->irq;
+    priv->adapter->chip_rev = card->chiprev;
+    if (request_gpio_irq_callback
+        ((void (*)(void *)) gpio_irq_callback, (void *) priv))
+        PRINTM(FATAL, "Failed to request GPIO IRQ callback\n");
+#endif
+
+	return WLAN_STATUS_SUCCESS;
+
+failed:
+	priv->wlan_dev.card = NULL;
+	return WLAN_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief This function sends data to the card.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param type	   data or command
+ *  @param payload A pointer to the data/cmd buffer
+ *  @param nb	   the length of data/cmd
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    int buf_block_len;
+    int blksz;
+    int i = 0;
+
+    ENTER();
+
+    priv->adapter->HisRegCpy = 0;
+
+    /* Allocate buffer and copy payload */
+    blksz = SD_BLOCK_SIZE;
+    buf_block_len = (nb + SDIO_HEADER_LEN + blksz - 1) / blksz;
+
+    /* This is SDIO specific header
+     *  length: byte[1][0], 
+     *  type: byte[3][2] (MVSD_DAT = 0, MVSD_CMD = 1, MVSD_EVENT = 3) 
+     */
+    priv->adapter->TmpTxBuf[0] = (nb + SDIO_HEADER_LEN) & 0xff;
+    priv->adapter->TmpTxBuf[1] = ((nb + SDIO_HEADER_LEN) >> 8) & 0xff;
+    priv->adapter->TmpTxBuf[2] = type;
+    priv->adapter->TmpTxBuf[3] = 0x0;
+
+    if (payload != NULL &&
+        (nb > 0 &&
+         nb <= (sizeof(priv->adapter->TmpTxBuf) - SDIO_HEADER_LEN))) {
+        if (type == MVMS_CMD)
+            memcpy(&priv->adapter->TmpTxBuf[SDIO_HEADER_LEN], payload, nb);
+    } else {
+        PRINTM(WARN, "sbi_host_to_card(): Error: payload=%p, nb=%d\n",
+               payload, nb);
+    }
+	
+
+    do {
+        /* Transfer data to card */
+        ret =
+            sbi_write_iomem(priv, priv->wlan_dev.ioport,
+                             buf_block_len, blksz,
+                             priv->adapter->TmpTxBuf);
+        if (ret < 0) {
+            i++;
+            PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+                   ret);
+            if (sbi_write_ioreg
+                (priv, CONFIGURATION_REG, 0x04) < 0) {
+                PRINTM(ERROR, "write ioreg failed (FN1 CFG)\n");
+            }
+            ret = WLAN_STATUS_FAILURE;
+            if (i > MAX_WRITE_IOMEM_RETRY)
+                goto exit;
+        } else {
+            DBG_HEXDUMP(IF_D, "SDIO Blk Wr", priv->adapter->TmpTxBuf,
+                        blksz * buf_block_len);
+        }
+    } while (ret == WLAN_STATUS_FAILURE);
+
+    if (type == MVSD_DAT)
+        priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
+    else
+        priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
+
+  exit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function reads CIS informaion.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_get_cis_info(wlan_private * priv)
+{
+	wlan_adapter *Adapter = priv->adapter;
+	u8 tupledata[255];
+	int i;
+	u32 ret = WLAN_STATUS_SUCCESS;
+#define CIS_8686_PTR 0x8000	
+	u32 cis_addr = CIS_8686_PTR;
+	struct sdio_func *func = (struct sdio_func *)(priv->wlan_dev.card);
+	
+
+	/* Read the Tuple Data */
+	for (i = 0; i < sizeof(tupledata); i++) {
+		ret = sdio_card_readb(func, cis_addr + i,
+	                      &tupledata[i]);
+		if (ret) {
+			PRINTM(WARN, "get_cis_info error:%d\n", ret);
+			return WLAN_STATUS_FAILURE;
+		}
+	}
+
+	/* Copy the CIS Table to Adapter */
+	memset(Adapter->CisInfoBuf, 0x0, sizeof(Adapter->CisInfoBuf));
+	memcpy(Adapter->CisInfoBuf, tupledata, sizeof(tupledata));
+	Adapter->CisInfoLen = sizeof(tupledata);
+
+	LEAVE();
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+/** 
+ *  @brief This function probes the card.
+ *  
+ *  @param card_p  A pointer to the card
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_probe_card(void *card_p)
+{
+	return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function calls sbi_download_wlan_fw_image to download
+ *  firmware image to the card.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_prog_firmware_w_helper(wlan_private * priv)
+{
+    if (priv->firmware) {
+        return sbi_download_wlan_fw_image(priv,
+                                          priv->firmware->data,
+                                          priv->firmware->size);
+    } else {
+        PRINTM(MSG, "No hotplug firmware image\n");
+        return WLAN_STATUS_FAILURE;
+    }
+}
+
+/** 
+ *  @brief This function programs helper image.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_prog_helper(wlan_private * priv)
+{
+    if (priv->fw_helper) {
+        return sbi_prog_firmware_image(priv,
+                                       priv->fw_helper->data,
+                                       priv->fw_helper->size);
+    } else {
+        PRINTM(MSG, "No hotplug helper image\n");
+        return WLAN_STATUS_FAILURE;
+    }
+}
+
+/** 
+ *  @brief This function checks if the firmware is ready to accept
+ *  command or not.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_verify_fw_download(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 firmwarestat;
+    int tries;
+
+    /* Wait for firmware initialization event */
+    for (tries = 0; tries < MAX_FIRMWARE_POLL_TRIES; tries++) {
+        if ((ret = mv_sdio_read_scratch(priv, &firmwarestat)) < 0)
+            continue;
+
+        if (firmwarestat == FIRMWARE_READY) {
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        } else {
+            mdelay(10);
+            ret = WLAN_STATUS_FAILURE;
+        }
+    }
+
+    if (ret < 0) {
+        PRINTM(MSG, "Timeout waiting for FW to become active\n");
+        goto done;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    return ret;
+}
+
+int
+sd_set_clock(wlan_private * priv, u32 slotFreq)
+{
+    //sdio_SetClockSpeed(((mmc_card_t) (priv->wlan_dev.card))->ctrlr, slotFreq);
+    return WLAN_STATUS_SUCCESS;
+}
+
+                                                                                                                                                                        /*--- mmoser 12/19/2006 ---*/
+int
+sd_stop_clock(wlan_private * priv)
+{
+    //sdio_SetClock(((mmc_card_t) (priv->wlan_dev.card))->ctrlr, 0);
+    return WLAN_STATUS_SUCCESS;
+}
+
+int
+sd_start_clock(wlan_private * priv)
+{
+    //sdio_SetClock(((mmc_card_t) (priv->wlan_dev.card))->ctrlr, 1);
+    return WLAN_STATUS_SUCCESS;
+}
+
+int
+sd_set_bus_width(wlan_private * priv, u8 width)
+{
+    //sdio_SetBusWidth(((mmc_card_t) (priv->wlan_dev.card))->ctrlr, width);
+    return WLAN_STATUS_SUCCESS;
+}
+
+int
+sd_set_gpo(wlan_private * priv, u8 on)
+{
+    //sdio_SetGPO(((mmc_card_t) (priv->wlan_dev.card))->ctrlr, on);
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function set bus clock on/off
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param option    TRUE--on , FALSE--off
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_set_bus_clock(wlan_private * priv, u8 option)
+{
+
+    if (option == TRUE)
+        sd_start_clock(priv);
+    else
+        sd_stop_clock(priv);
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function makes firmware exiting from deep sleep.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_exit_deep_sleep(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    sbi_set_bus_clock(priv, TRUE);
+
+    if (priv->adapter->fwWakeupMethod == WAKEUP_FW_THRU_GPIO) {
+        GPIO_PORT_TO_LOW();
+    } else
+        ret = sbi_write_ioreg(priv, CONFIGURATION_REG,
+                               HOST_POWER_UP);
+
+    return ret;
+}
+
+/** 
+ *  @brief This function resets the setting of deep sleep.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_reset_deepsleep_wakeup(wlan_private * priv)
+{
+
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (priv->adapter->fwWakeupMethod == WAKEUP_FW_THRU_GPIO) {
+        GPIO_PORT_TO_HIGH();
+    } else
+        ret =
+            sbi_write_ioreg(priv, CONFIGURATION_REG, 0);
+
+    LEAVE();
+
+    return ret;
+}
+
+#ifdef ENABLE_PM
+/** 
+ *  @brief This function suspends the device.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_suspend(wlan_private * priv)
+{
+    return sdio_suspend(priv->wlan_dev.card);
+}
+
+/** 
+ *  @brief This function resumes the device from sleep
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+*/
+int
+sbi_resume(wlan_private * priv)
+{
+    return sdio_resume(priv->wlan_dev.card);
+}
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/if/if_sdio/if_sdio.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,117 @@
+/** @file if_sdio.h
+ *  @brief This file contains SDIO IF (interface) module
+ *  related macros, enum, and structure.
+ * 
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+	10/12/05: add Doxygen format comments 
+****************************************************/
+
+#ifndef	_IF_SDIO_H_
+#define	_IF_SDIO_H_
+
+#include	<include.h>
+#include	<linux/mmc/sdio.h>
+#include	<linux/mmc/sdio_ids.h>
+#include	<linux/mmc/sdio_func.h>
+#include	<linux/mmc/card.h>
+#include	<linux/mmc/host.h>
+
+
+#define SD_BUS_WIDTH_1			0x00
+#define SD_BUS_WIDTH_4			0x02
+#define SD_BUS_WIDTH_MASK		0x03
+#define ASYNC_INT_MODE			0x20
+
+/* Host Control Registers */
+#define IO_PORT_0_REG			0x00
+#define IO_PORT_1_REG			0x01
+#define IO_PORT_2_REG			0x02
+#define CONFIGURATION_REG		0x03
+#define HOST_WO_CMD53_FINISH_HOST	(0x1U << 2)
+#define HOST_POWER_UP			(0x1U << 1)
+#define HOST_POWER_DOWN			(0x1U << 0)
+#define HOST_INT_MASK_REG		0x04
+#define UP_LD_HOST_INT_MASK		(0x1U)
+#define DN_LD_HOST_INT_MASK		(0x2U)
+#define HOST_INTSTATUS_REG		0x05
+#define UP_LD_HOST_INT_STATUS		(0x1U)
+#define DN_LD_HOST_INT_STATUS		(0x2U)
+#define HOST_INT_RSR_REG		0x06
+#define UP_LD_HOST_INT_RSR		(0x1U)
+#define HOST_INT_STATUS_REG		0x07
+#define UP_LD_CRC_ERR			(0x1U << 2)
+#define UP_LD_RESTART              	(0x1U << 1)
+#define DN_LD_RESTART              	(0x1U << 0)
+
+/* Card Control Registers */
+#define SQ_READ_BASE_ADDRESS_A0_REG  	0x10
+#define SQ_READ_BASE_ADDRESS_A1_REG  	0x11
+#define SQ_READ_BASE_ADDRESS_A2_REG  	0x12
+#define SQ_READ_BASE_ADDRESS_A3_REG  	0x13
+#define SQ_READ_BASE_ADDRESS_B0_REG  	0x14
+#define SQ_READ_BASE_ADDRESS_B1_REG  	0x15
+#define SQ_READ_BASE_ADDRESS_B2_REG  	0x16
+#define SQ_READ_BASE_ADDRESS_B3_REG  	0x17
+#define CARD_STATUS_REG              	0x20
+#define CARD_IO_READY              	(0x1U << 3)
+#define CIS_CARD_RDY                 	(0x1U << 2)
+#define UP_LD_CARD_RDY               	(0x1U << 1)
+#define DN_LD_CARD_RDY               	(0x1U << 0)
+#define HOST_INTERRUPT_MASK_REG      	0x24
+#define HOST_POWER_INT_MASK          	(0x1U << 3)
+#define ABORT_CARD_INT_MASK          	(0x1U << 2)
+#define UP_LD_CARD_INT_MASK          	(0x1U << 1)
+#define DN_LD_CARD_INT_MASK          	(0x1U << 0)
+#define CARD_INTERRUPT_STATUS_REG    	0x28
+#define POWER_UP_INT                 	(0x1U << 4)
+#define POWER_DOWN_INT               	(0x1U << 3)
+#define CARD_INTERRUPT_RSR_REG       	0x2c
+#define POWER_UP_RSR                 	(0x1U << 4)
+#define POWER_DOWN_RSR               	(0x1U << 3)
+#define DEBUG_0_REG                  	0x30
+#define SD_TESTBUS0                  	(0x1U)
+#define DEBUG_1_REG                  	0x31
+#define SD_TESTBUS1                  	(0x1U)
+#define DEBUG_2_REG                  	0x32
+#define SD_TESTBUS2                  	(0x1U)
+#define DEBUG_3_REG                  	0x33
+#define SD_TESTBUS3                  	(0x1U)
+#define CARD_OCR_0_REG               	0x34
+#define CARD_OCR_1_REG               	0x35
+#define CARD_OCR_3_REG               	0x36
+#define CARD_CONFIG_REG              	0x38
+#define CARD_REVISION_REG            	0x3c
+#define CMD53_FINISH_GBUS            	(0x1U << 1)
+#define SD_NEG_EDGE                  	(0x1U << 0)
+
+/* Special registers in function 0 of the SDxx card */
+#define	SCRATCH_0_REG			0x80fe
+#define	SCRATCH_1_REG			0x80ff
+#define HOST_F1_RD_BASE_0		0x0010
+#define HOST_F1_RD_BASE_1		0x0011
+#define HOST_F1_CARD_RDY		0x0020
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+//extern int sdio_get_vendor_id(mmc_card_t card);
+
+#endif /* _IF_SDIO_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/Makefile linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/Makefile
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/Makefile	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,86 @@
+CONFIG_DEBUG=0
+
+# Proc in /proc/net/wlan
+CONFIG_PROC_DEBUG=y
+
+# Linux Power Management
+CONFIG_ENABLE_PM=n
+
+# Re-association in driver
+CONFIG_REASSOCIATION=y
+
+# Manufacturing firmware support
+CONFIG_MFG_CMD_SUPPORT=y
+
+ifeq ($(CONFIG_DEBUG),1)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+endif
+
+ifeq ($(CONFIG_DEBUG),2)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+	EXTRA_CFLAGS += -DDEBUG_LEVEL2
+	DBG=	-dbg
+endif
+
+ifeq ($(CONFIG_DEBUG),3)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+	EXTRA_CFLAGS += -DDEBUG_LEVEL2
+	EXTRA_CFLAGS += -DDEBUG_LEVEL3
+	DBG=	-dbg
+endif
+
+ifeq ($(CONFIG_DEBUG),4)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+	EXTRA_CFLAGS += -DDEBUG_LEVEL2
+	EXTRA_CFLAGS += -DDEBUG_LEVEL3
+	EXTRA_CFLAGS += -DDEBUG_LEVEL4
+	DBG=	-dbg
+endif
+
+ifeq ($(CONFIG_PROC_DEBUG),y)
+	EXTRA_CFLAGS += -DPROC_DEBUG
+	export CONFIG_PROC_DEBUG
+endif
+
+ifeq ($(CONFIG_ENABLE_PM),y)
+	EXTRA_CFLAGS += -DENABLE_PM
+endif
+
+ifeq ($(CONFIG_REASSOCIATION),y)
+	EXTRA_CFLAGS += -DREASSOCIATION
+endif
+
+ifeq ($(CONFIG_MFG_CMD_SUPPORT),y)
+	EXTRA_CFLAGS += -DMFG_CMD_SUPPORT
+endif
+
+8686_v9-objs =	wlan/wlan_main.o wlan/wlan_fw.o wlan/wlan_wext.o \
+		wlan/wlan_rx.o wlan/wlan_tx.o \
+		wlan/wlan_cmd.o wlan/wlan_cmdresp.o \
+		wlan/wlan_proc.o wlan/wlan_scan.o wlan/wlan_join.o \
+		wlan/wlan_wmm.o wlan/wlan_11d.o \
+		if/if_sdio/if_sdio.o
+
+ifeq ($(CONFIG_PROC_DEBUG), y)
+8686_v9-objs += wlan/wlan_debug.o
+endif
+
+obj-$(CONFIG_MMC_SD8686) += 8686_v9.o
+
+	EXTRA_CFLAGS += -DFPNUM='"13"'
+	EXTRA_CFLAGS += -DFB
+
+ifdef CONFIG_MMC_SD8686
+	EXTRA_CFLAGS += -Idrivers/net/wireless/8686_v9/os/linux -Idrivers/net/wireless/8686_v9/wlan
+
+
+ifdef CONFIG_MMC_DEBUG
+#	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+#	EXTRA_CFLAGS += -DDEBUG_LEVEL2
+#	EXTRA_CFLAGS += -DDEBUG_LEVEL3
+#	EXTRA_CFLAGS += -DDEBUG_LEVEL4
+#	DBG=    -dbg
+endif
+
+endif
+
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_defs.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_defs.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_defs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_defs.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,57 @@
+/*
+ *  
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _OS_HEADER1_
+#define _OS_HEADER1_
+
+typedef char CHAR;
+typedef char *PCHAR;
+typedef u8 *PUCHAR;
+typedef u16 *PUSHORT;
+typedef long *PLONG;
+typedef PLONG LONG_PTR;
+typedef u32 *ULONG_PTR;
+typedef u32 *Pu32;
+typedef unsigned int UINT;
+typedef UINT *PUINT;
+typedef void VOID;
+typedef VOID *PVOID;
+typedef int WLAN_STATUS;
+typedef u8 BOOLEAN;
+typedef BOOLEAN *PBOOLEAN;
+typedef PVOID PDRIVER_OBJECT;
+typedef PUCHAR PUNICODE_STRING;
+typedef long long LONGLONG;
+typedef LONGLONG *PLONGLONG;
+typedef unsigned long long *PULONGLONG;
+typedef PUCHAR ANSI_STRING;
+typedef ANSI_STRING *PANSI_STRING;
+typedef unsigned short WCHAR;
+typedef WCHAR *PWCHAR;
+typedef WCHAR *LPWCH, *PWCH;
+typedef WCHAR *NWPSTR;
+typedef WCHAR *LPWSTR, *PWSTR;
+typedef struct semaphore SEMAPHORE;
+
+#ifdef __KERNEL__
+typedef irqreturn_t IRQ_RET_TYPE;
+#define IRQ_RET		return IRQ_HANDLED
+#endif /* __KERNEL__ */
+
+#endif /* _OS_HEADER1 */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_headers.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_headers.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_headers.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_headers.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,85 @@
+/*
+ *  
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef _OS_HEADERS_H
+#define _OS_HEADERS_H
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+
+/* Linux header files */
+#include        <linux/kernel.h>
+#include        <linux/module.h>
+#include        <linux/init.h>
+#include        <linux/version.h>
+#include        <linux/param.h>
+#include        <linux/delay.h>
+#include        <linux/slab.h>
+#include        <linux/mm.h>
+#include        <linux/types.h>
+#include        <linux/sched.h>
+#include        <linux/timer.h>
+#include        <linux/types.h>
+#include        <linux/ioport.h>
+#include        <linux/pci.h>
+#include        <linux/ctype.h>
+#include        <linux/proc_fs.h>
+#include	<linux/ptrace.h>
+#include	<linux/string.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include	<linux/config.h>
+#endif
+
+#include	<linux/ioport.h>
+
+/* New Code to synchronize between IEEE Power save and PM*/
+#ifdef ENABLE_PM
+#include <linux/pm.h>
+#endif
+
+/* ASM files */
+#include        <asm/semaphore.h>
+#include        <asm/byteorder.h>
+#include        <asm/irq.h>
+#include        <asm/uaccess.h>
+#include        <asm/io.h>
+#include	<asm/system.h>
+
+/* Net header files */
+#include        <linux/wireless.h>
+#include        <linux/netdevice.h>
+#include        <linux/net.h>
+#include        <linux/ip.h>
+#include        <linux/skbuff.h>
+#include        <linux/if_arp.h>
+#include        <linux/if_ether.h>
+#include        <linux/etherdevice.h>
+#include        <net/arp.h>
+#include        <linux/rtnetlink.h>
+
+/* Wireless header */
+#include        <net/iw_handler.h>
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_macros.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_macros.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_macros.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_macros.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,207 @@
+/*
+ *  
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+#ifndef	_OS_MACROS_H
+#define _OS_MACROS_H
+
+#define os_time_get()	jiffies
+
+extern spinlock_t driver_lock;
+extern unsigned long driver_flags;
+#define OS_INT_DISABLE	spin_lock_irqsave(&driver_lock, driver_flags)
+#define	OS_INT_RESTORE	spin_unlock_irqrestore(&driver_lock, driver_flags); \
+			driver_lock = SPIN_LOCK_UNLOCKED
+
+#define UpdateTransStart(dev) { \
+	dev->trans_start = jiffies; \
+}
+
+#define OS_SET_THREAD_STATE(x)		set_current_state(x)
+
+#define MODULE_GET	if(try_module_get(THIS_MODULE)==0) return WLAN_STATUS_FAILURE;
+#define MODULE_PUT	module_put(THIS_MODULE)
+
+#define OS_INIT_SEMAPHORE(x)    	init_MUTEX(x)
+#define OS_ACQ_SEMAPHORE_BLOCK(x)	down_interruptible(x)
+#define OS_ACQ_SEMAPHORE_NOBLOCK(x)	down_trylock(x)
+#define OS_REL_SEMAPHORE(x) 		up(x)
+
+/* Definitions below are needed for other OS like threadx */
+#define	TX_DISABLE
+#define TX_RESTORE
+#define	ConfigureThreadPriority()
+#define OS_INTERRUPT_SAVE_AREA
+#define OS_FREE_LOCK(x)
+#define TX_EVENT_FLAGS_SET(x, y, z)
+
+#define os_wait_interruptible_timeout(waitq, cond, timeout) \
+	wait_event_interruptible_timeout(waitq, cond, timeout)
+
+static inline void
+os_sched_timeout(u32 millisec)
+{
+    set_current_state(TASK_INTERRUPTIBLE);
+
+    schedule_timeout((millisec * HZ) / 1000);
+}
+
+static inline void
+os_schedule(u32 millisec)
+{
+    schedule_timeout((millisec * HZ) / 1000);
+}
+
+static inline int
+CopyMulticastAddrs(wlan_adapter * Adapter, struct net_device *dev)
+{
+    int i = 0;
+    struct dev_mc_list *mcptr = dev->mc_list;
+
+    for (i = 0; i < dev->mc_count; i++) {
+        memcpy(&Adapter->MulticastList[i], mcptr->dmi_addr, ETH_ALEN);
+        mcptr = mcptr->next;
+    }
+
+    return i;
+}
+
+static inline u32
+get_utimeofday(void)
+{
+    struct timeval t;
+    u32 ut;
+
+    do_gettimeofday(&t);
+    ut = (u32) t.tv_sec * 1000000 + ((u32) t.tv_usec);
+    return ut;
+}
+
+static inline int
+os_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+
+#define IPFIELD_ALIGN_OFFSET	2
+
+    skb->dev = priv->wlan_dev.netdev;
+    skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
+    skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+    netif_rx(skb);
+
+    return 0;
+}
+
+static inline void
+os_free_tx_packet(wlan_private * priv)
+{
+    ulong flags;
+
+    if (priv->adapter->CurrentTxSkb) {
+        kfree_skb(priv->adapter->CurrentTxSkb);
+        spin_lock_irqsave(&priv->adapter->CurrentTxLock, flags);
+        priv->adapter->CurrentTxSkb = NULL;
+        spin_unlock_irqrestore(&priv->adapter->CurrentTxLock, flags);
+    }
+}
+
+/*
+ *  netif carrier_on/off and start(wake)/stop_queue handling
+ *
+ *           carrier_on      carrier_off     start_queue     stop_queue
+ * open           x(connect)      x(disconnect)   x
+ * close                          x                               x
+ * assoc          x                               x
+ * deauth                         x                               x
+ * adhoc-start
+ * adhoc-join
+ * adhoc-link     x                               x
+ * adhoc-bcnlost                  x                               x
+ * scan-begin                     x                               x
+ * scan-end       x                               x
+ * ds-enter                       x                               x
+ * ds-exit        x                               x
+ * xmit                                                           x
+ * xmit-done                                      x
+ * tx-timeout
+ */
+static inline void
+os_carrier_on(wlan_private * priv)
+{
+    if (!netif_carrier_ok(priv->wlan_dev.netdev) &&
+        (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) &&
+        ((priv->adapter->InfrastructureMode != Wlan802_11IBSS) ||
+         (priv->adapter->AdhocLinkSensed))) {
+        netif_carrier_on(priv->wlan_dev.netdev);
+    }
+}
+
+static inline void
+os_carrier_off(wlan_private * priv)
+{
+    if (netif_carrier_ok(priv->wlan_dev.netdev)) {
+        netif_carrier_off(priv->wlan_dev.netdev);
+    }
+}
+
+static inline void
+os_start_queue(wlan_private * priv)
+{
+    if (netif_queue_stopped(priv->wlan_dev.netdev) &&
+        (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) &&
+        ((priv->adapter->InfrastructureMode != Wlan802_11IBSS) ||
+         (priv->adapter->AdhocLinkSensed))) {
+        netif_wake_queue(priv->wlan_dev.netdev);
+    }
+}
+
+static inline void
+os_stop_queue(wlan_private * priv)
+{
+    if (!netif_queue_stopped(priv->wlan_dev.netdev)) {
+        netif_stop_queue(priv->wlan_dev.netdev);
+    }
+}
+
+
+/* feng add for temply use */
+//#define DBG_2621 1
+
+#ifdef DBG_2621
+
+#ifdef DBG_DELAY
+#define umd_dbg(f, x...) \
+	do { \
+		printk(KERN_ALERT "[%s()]: " f "\n", __func__,## x); \
+		mdelay(3000); \
+	} while(0)
+#else
+#define umd_dbg(f, x...) \
+	printk(KERN_ALERT "[%s()]: " f "\n", __func__,## x)
+#endif	/* end of DBG_DELAY */
+
+#define umd_enter() \
+	printk(KERN_ERR "[%s()]: enter\n", __func__)
+#define umd_exit() \
+	printk(KERN_ERR "[%s()]: exit\n", __func__)
+#else
+#define umd_dbg(f, x...)  do{} while(0)
+#define umd_enter()  do{} while(0)
+#define umd_exit()  do{} while(0)
+#endif	/* end of DBG_2621 */
+
+#endif /* _OS_MACROS_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_timers.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_timers.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/os_timers.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/os_timers.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,98 @@
+/*
+ *  
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef	_OS_TIMERS_H
+#define _OS_TIMERS_H
+
+typedef struct __WLAN_DRV_TIMER
+{
+    struct timer_list tl;
+    void (*timer_function) (void *context);
+    void *function_context;
+    UINT time_period;
+    BOOLEAN timer_is_periodic;
+    BOOLEAN timer_is_canceled;
+} __ATTRIB_PACK__ WLAN_DRV_TIMER, *PWLAN_DRV_TIMER;
+
+static inline void
+TimerHandler(unsigned long fcontext)
+{
+    PWLAN_DRV_TIMER timer = (PWLAN_DRV_TIMER) fcontext;
+
+    timer->timer_function(timer->function_context);
+
+    if (timer->timer_is_periodic == TRUE) {
+        mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000));
+    }
+}
+
+static inline void
+InitializeTimer(PWLAN_DRV_TIMER timer,
+                void (*TimerFunction) (void *context), void *FunctionContext)
+{
+    // first, setup the timer to trigger the WlanTimerHandler proxy
+    init_timer(&timer->tl);
+    timer->tl.function = TimerHandler;
+    timer->tl.data = (u32) timer;
+
+    // then tell the proxy which function to call and what to pass it       
+    timer->timer_function = TimerFunction;
+    timer->function_context = FunctionContext;
+    timer->timer_is_canceled = FALSE;
+}
+
+static inline void
+SetTimer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
+{
+    timer->time_period = MillisecondPeriod;
+    timer->timer_is_periodic = FALSE;
+    timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000;
+    add_timer(&timer->tl);
+    timer->timer_is_canceled = FALSE;
+}
+
+static inline void
+ModTimer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
+{
+    timer->time_period = MillisecondPeriod;
+    timer->timer_is_periodic = FALSE;
+    mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000);
+    timer->timer_is_canceled = FALSE;
+}
+
+static inline void
+SetPeriodicTimer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
+{
+    timer->time_period = MillisecondPeriod;
+    timer->timer_is_periodic = TRUE;
+    timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000;
+    add_timer(&timer->tl);
+    timer->timer_is_canceled = FALSE;
+}
+
+#define	FreeTimer(x)	do {} while (0)
+
+static inline void
+CancelTimer(WLAN_DRV_TIMER * timer)
+{
+    del_timer(&timer->tl);
+    timer->timer_is_canceled = TRUE;
+}
+
+#endif /* _OS_TIMERS_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/wlan_thread.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/wlan_thread.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/os/linux/wlan_thread.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/os/linux/wlan_thread.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,73 @@
+/*
+ *  
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+
+#ifndef	__WLAN_THREAD_H_
+#define	__WLAN_THREAD_H_
+
+#include	<linux/kthread.h>
+
+typedef struct
+{
+    struct task_struct *task;
+    wait_queue_head_t waitQ;
+    pid_t pid;
+    void *priv;
+} wlan_thread;
+
+static inline void
+wlan_activate_thread(wlan_thread * thr)
+{
+        /** Record the thread pid */
+    thr->pid = current->pid;
+
+        /** Initialize the wait queue */
+    init_waitqueue_head(&thr->waitQ);
+}
+
+static inline void
+wlan_deactivate_thread(wlan_thread * thr)
+{
+    ENTER();
+
+    LEAVE();
+}
+
+static inline void
+wlan_create_thread(int (*wlanfunc) (void *), wlan_thread * thr, char *name)
+{
+    thr->task = kthread_run(wlanfunc, thr, "%s", name);
+}
+
+static inline int
+wlan_terminate_thread(wlan_thread * thr)
+{
+    ENTER();
+
+    /* Check if the thread is active or not */
+    if (!thr->pid) {
+        PRINTM(INFO, "Thread does not exist\n");
+        return -1;
+    }
+    kthread_stop(thr->task);
+
+    LEAVE();
+    return 0;
+}
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/README linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/README
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/README	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/README	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,1569 @@
+===============================================================================
+			U S E R  M A N U A L
+
+ (c) Copyright © 2003-2007, Marvell International Ltd. 
+
+ This software file (the "File") is distributed by Marvell International 
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ (the "License").  You may use, redistribute and/or modify this File in 
+ accordance with the terms and conditions of the License, a copy of which 
+ is available along with the File in the gpl.txt file or by writing to 
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ this warranty disclaimer.
+
+===============================================================================
+
+1) FOR DRIVER BUILD
+
+	Goto source code directory src_xxxx. 
+		make [clean] build	
+	The driver and utility binaries can be found in ../bin_xxxx directory.
+
+2) FOR DRIVER INSTALL
+
+	a) Copy helper_sd.bin and sd8686.bin | sd8388v.bin | ... to /lib/firmware/mrvl/ directory,
+	   create the directory if it doesn't exist. 
+	b) Install sdio bus driver and WLAN driver:
+		./load sd8686 | sd8388v | ...
+	c) Uninstall WLAN driver and sdio bus driver:
+		./unload
+
+3) FOR DRIVER PROC & DEBUG
+
+	The following info are provided in /proc/net/wlan/info,
+
+	driver_name = "wlan"
+	driver_version = <chip id, firmware version and driver version>
+	InterfaceName = "ethX"
+	Mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
+	State = "Disconnected" | "Connected"
+	MACAddress = <6-byte adapter MAC address>
+	MCCount = <multicast address count>
+	ESSID = <current SSID>
+	Channel = <current channel>
+	region_code = <current region code>
+	MCAddr[n] = <multicast address>
+	num_tx_bytes = <number of bytes sent to device>
+	num_rx_bytes = <number of bytes received from device and sent to kernel>
+	num_tx_pkts = <number of packets sent to device>
+	num_rx_pkts = <number of packets received from device and sent to kernel>
+	num_tx_pkts_dropped = <number of tx packets dropped by driver>
+	num_rx_pkts_dropped = <number of rx packets dropped by driver>
+	num_tx_pkts_err = <number of tx packets failed to send to device>
+	num_rx_pkts_err = <number of rx packets failed to receive from device>
+	carrier "on" | "off"
+	tx queue "stopped" | "started"
+	CurCmd "NULL" | <current command id and action>
+
+	The following debug info are provided in /proc/net/wlan/debug,
+
+	IntCounter = <interrupt count, cleared when interrupt handled>
+	ConnectStatus = <0/1, disconnected/connected>
+	wmmQStp = <0/1, WMM queue started/stopped>
+	wmmPkts = <number of tx packets in WMM queues>
+	wmmAcVo = <number of packets sent to device from WMM AcVo queue>
+	wmmAcVi = <number of packets sent to device from WMM AcVi queue>
+	wmmAcBE = <number of packets sent to device from WMM AcBE queue>
+	wmmAcBK = <number of packets sent to device from WMM AcBK queue>
+	PSMode = <0/1, CAM mode/PS mode>
+	PSState = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
+	IsDeepSleep = <0/1, not deep sleep state/deep sleep state>
+	IsAutoDeepSleepEnabled = <0/1, not auto deep sleep mode/auto deep sleep mode>
+	WakeupDevReq = <0/1, wakeup device not required/required>
+	WakeupTries = <wakeup device count, cleared when device awake>
+	HS_Configured = <0/1, host sleep not configured/configured>
+	HS_Activated = <0/1, extended host sleep not activated/activated>
+	num_tx_timeout = <number of tx timeout>
+	num_cmd_timeout = <number of timeout commands>
+	TimeoutCmdId = <command id of the last timeout command>
+	TimeoutCmdAct = <command action of the last timeout command>
+	LastCmdId = <command id of the last several commands sent to device>
+	LastCmdAct = <command action of the last several commands sent to device>
+	LastCmdIndex = <0 based last command index>
+	LastCmdRespId = <command id of the last several command responses received from device>
+	LastCmdRespIndex = <0 based last command response index>
+	LastEvent = <event id of the last several events received from device>
+	LastEventIndex = <0 based last event index>
+	num_cmd_h2c_fail = <number of commands failed to send to device>
+	num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
+	num_tx_h2c_fail = <number of data packets failed to send to device>
+	num_evt_deauth = <number of deauthenticated events received from device>
+	num_evt_disassoc = <number of disassociated events received from device>
+	num_evt_link_lost = <number of link lost events received from device>
+	num_cmd_deauth = <number of deauthenticate commands sent to device>
+	num_cmd_assoc_ok = <number of associate commands with success return>
+	num_cmd_assoc_fail = <number of associate commands with failure return>
+	dnld_sent = <0/1/2, send resources available/sending data to device/sending command to device>
+
+	Use dmesg or cat /var/log/debug to check driver debug messages.
+	To log driver debug messages to file,
+	a) Edit /etc/syslog.conf, add one line "*.debug		/var/log/debug"
+	b) touch /var/log/debug (if the file doesn't exist)
+	c) service syslog restart
+
+	Update /proc/sys/kernel/printk to change message log levels.
+	For example,
+	echo 6 > /proc/sys/kernel/printk    (messages with a higher priority than 6 
+	                                     will be printed to the console)
+	echo 15 > /proc/sys/kernel/printk   (all messages will be printed to console)
+
+4) FOR IWPRIV COMMAND
+
+NAME
+	This manual describes the usage of private commands used in Marvell WLAN
+	Linux Driver. All the commands available in Wlanconfig will not be available 
+	in the iwpriv.
+
+	To use parameters as hex format, a'0x' must precede it for the parameters to 
+	be parsed properly. 
+
+SYNOPSIS
+	iwpriv <ethX> <command> [sub-command] ...
+
+	iwpriv ethX version
+	iwpriv ethX verext
+	iwpriv ethX scantype [sub-command]
+	iwpriv ethX getSNR <n>
+	iwpriv ethX getNF <n>
+	iwpriv ethX getRSSI <n>
+	iwpriv ethX setrxant <n>
+	iwpriv ethX getrxant
+	iwpriv ethX settxant <n>
+	iwpriv ethX gettxant
+	iwpriv ethX authalgs <n>
+	iwpriv ethX encryptionmode <n>
+	iwpriv ethX setregioncode <n>
+	iwpriv ethX getregioncode 
+	iwpriv ethX setbcnavg <n>
+	iwpriv ethX getbcnavg
+	iwpriv ethX setdataavg <n>
+	iwpriv ethX getdataavg
+	iwpriv ethX setlisteninter <n>
+	iwpriv ethX getlisteninter
+	iwpriv ethX setmultipledtim <n>
+	iwpriv ethX getmultipledtim
+	iwpriv ethX atimwindow <n>
+	iwpriv ethX deepsleep <n>
+	iwpriv ethX autodeepsleep <n>
+	iwpriv ethX hscfg <n>
+	iwpriv ethX hssetpara <n>
+	iwpriv ethX deauth
+	iwpriv ethX adhocstop
+	iwpriv ethX radioon
+	iwpriv ethX radiooff
+	iwpriv ethX reasso-on
+	iwpriv ethX reasso-off
+	iwpriv ethX scanmode  [sub-command]
+	iwpriv ethX setwpaie <n>
+	iwpriv ethX setaeskey <n>
+	iwpriv ethX getaeskey 
+	iwpriv ethX rmaeskey
+	iwpriv ethX getcis
+	iwpriv ethX getlog
+	iwpriv ethX getadhocstatus
+	iwpriv ethX adhocgrate <n>
+
+Version 4 Command:
+	iwpriv ethX inactvityto <n>
+	iwpriv ethX sleeppd <n>
+	iwpriv ethX enable11d <n>
+	iwpriv ethX bgscan <n>
+	iwpriv ethX wmm <n>
+	iwpriv ethX tpccfg <n>
+	iwpriv ethX sdioclock <n>
+
+Version 5 Command:
+	iwpriv ethX ledgpio <n>
+	iwpriv ethX wmm_qosinfo <n>
+	iwpriv ethX scanprobes <n>
+	iwpriv ethX lolisteninter <n>
+ 	iwpriv ethX rateadapt <n> <m> <l> <k>
+	iwpriv ethX fwwakeupmethod <n>
+	iwpriv ethX txcontrol <n>
+	iwpriv ethX uapsdnullgen <n>
+	iwpriv ethX psnullinterval <n>
+	iwpriv ethX getrxinfo
+	iwpriv ethX gettxrate
+	iwpriv ethX bcninterval [n]
+	iwpriv ethX setcoalescing <n>
+	iwpriv ethX bcnmisto <n>
+	iwpriv ethX adhocawakepd <n>
+	iwpriv ethX sdiopullctrl <m> <n>
+	iwpriv ethX scantime [s] [a] [p]
+	iwpriv ethX ldocfg [n]
+	iwpriv ethX dataevtcfg [a] [b] [c] [d] [e] [f] [g] [h] [i]
+	iwpriv ethX drvdbg [n] [m]
+	iwpriv ethX adhocgprot [n]
+	iwpriv ethX getrate 
+	iwpriv ethX associate <n>
+
+DESCRIPTION
+	Those commands are used to send additional commands to the Marvell WLAN
+	card via the Linux device driver.
+
+	The ethX parameter specifies the network device that is to be used to 
+		perform this command on. it could be eth0, eth1 etc.
+
+version	
+	This is used to get the current version of the driver and the firmware.
+
+verext
+    Retrieve and display an extended version string from the firmware
+
+	Usage:
+		iwpriv ethX verext [#]
+
+     where [#] is an optional argument to retrieve a specific version string,
+        omission of the argument retrieves the 0 indexed string
+
+scantype	
+	This command is used to set the scan type to be used by the driver in 
+	the scan command. This setting will not be used while performing a scan
+	for a specific SSID, as it is always done with scan type being active. 
+	
+	where the sub-commands are: - 
+			active 	-- to set the scan type to active
+			passive -- to set the scan type to passive
+			get 	-- to get the scan type set in the driver
+
+getSNR  
+	This command gets the average and non average value of Signal to Noise 
+	Ratio of Beacon and Data.
+	
+	where value is:
+			0 	-- Beacon non-average.
+	        	1 	-- Beacon average.
+	        	2 	-- Data non-average.
+	        	3 	-- Data average.
+
+	If no value is given, all four values are returned in the order mentioned
+	above.
+
+	Note: This command is available only when STA is connected.
+
+getRSSI	
+	This command gets the average and non average value os Receive Signal 
+	Strength of Beacon and Data.
+	
+	where value is:
+			0 	-- Beacon non-average.
+	        	1 	-- Beacon average.
+	        	2 	-- Data non-average.
+	        	3 	-- Data average.
+
+	Note: This command is available only when STA is connected.
+
+getNF   
+	This command gets the average and non average value of Noise Floor of 
+	Beacon and Data.
+	
+	where value is:
+			0 	-- Beacon non-average.
+	        	1 	-- Beacon average.
+	        	2 	-- Data non-average.
+	        	3 	-- Data average.
+
+	Note: This command is available only when STA is connected.
+
+setrxant	
+	This command is used to set the mode for Rx antenna. 
+	
+	The options that can be sent are:- 
+			1 	-- Antenna 1. 
+			2 	-- Antenna 2.
+			0xFFFF 	-- Diversity.
+
+	Usage:
+		iwpriv ethX setrxant 0x01: select Antenna 1.
+
+getrxant                    
+	This command is used to get the mode for Rx antenna.
+
+settxant	
+	This command is used to set the mode for Tx antenna.
+		The options that can be sent are:- 
+			1 	-- Antenna 1. 
+			2 	-- Antenna 2.
+			0xFFFF 	-- Diversity.
+	Usage:
+		iwpriv ethX settxant 0x01: select Antenna 1.
+
+gettxant                    
+	This command is used to get the mode for Tx antenna.
+
+authalgs	
+	This command is used by the WPA supplicant to set the authentication 
+	algorithms in the station.
+
+encryptionmode
+	This command is used by the WPA supplicant to set the encryption algorithm.
+		
+	where values can be:-
+			0 	-- NONE
+			1 	-- WEP40
+			2 	-- TKIP
+			3 	-- CCMP
+			4 	-- WEP104
+
+setregioncode           
+	This command is used to set the region code in the station.
+	where value is 'region code' for various regions like
+	USA FCC, Canada IC, France, Europe ETSI, Japan ...
+
+	Usage:
+		iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
+
+getregioncode           
+	This command is used to get the region code information set in the 
+	station. 
+
+setbcnavg
+	Set the weighting factor for calculating beacon average RSSI and SNR.
+	where value can be:
+			0 	-- default beacon averaging factor (8)
+			1-8 	-- beacon averaging factor
+	Usage:
+		iwpriv ethX setbcnavg 0
+		iwpriv ethX setbcnavg 8
+
+getbcnavg
+	Get the weighting factor for calculating beacon average RSSI and SNR.
+	Usage:
+		iwpriv ethX getbcnavg
+
+setdataavg
+	Set the weighting factor for calculating data average RSSI and SNR.
+	where value can be:
+			0 	-- default data averaging factor (8)
+			1-8 	-- data averaging factor
+	Usage:
+		iwpriv ethX setdataavg 0
+		iwpriv ethX setdataavg 8
+
+getdataavg
+	Get the weighting factor for calculating data average RSSI and SNR.
+	Usage:
+		iwpriv ethX getdataavg
+
+setlisteninter             
+	This command is used to set the listen interval in the 
+	station.
+	
+	where the value ranges between 1 - 255
+
+getlisteninter            
+	This command is used to get the listen interval value set in the 
+	station.
+
+setmultipledtim         
+	This command is used to set the multiple dtim value in the 
+	station.
+		where the value is 1,2,3,4,5,0xfffe
+		65534 (0xfffe) means that the dtim will be ignored in firmware,
+		listen interval or local listen interval will be used.
+
+getmultipledtim        
+	This command is used to get the multiple dtim value set in the station.
+
+atimwindow         
+	This command is used to set atim value in the station when an argument is given, 
+        return the atim value set by the user and the current atim value if adapter is in connected state. 
+        The valid atimwindow is between 0 - 50.
+
+	Usage:
+		iwpriv ethX atimwindow 0  (set atimwindow to 0)
+		
+		not connected:
+		iwpriv ethX atimwindow    (get atimwindow value set by user)
+		
+		connected:
+		iwpriv ethX atimwindow     (get atimwindow set by user previously
+                                                         and current atimwindow)
+
+deauth                      
+	This command is used to send the de-authentication to the AP with which 
+	the station is associated. This command is valid only when 
+	station is in Infrastructure mode.
+
+	Note: This command is available only when STA is connected.
+
+reasso-on                  
+	This command is used to enable re-association function in dirver.
+
+reasso-off                  
+	This command is used to disable re-association function in driver
+
+adhocstop                 
+	This command is used to stop beacon transmission from the station and 
+	go into idle state in ad-hoc mode.
+	
+	Note: This command is available only when STA is connected.
+
+radioon                     
+	This command is used to turn on the RF antenna.
+
+radiooff                    
+	This command is sued to turn off the RF antenna.   
+
+scanmode                 
+	This command is used to set the station to scan for either IBSS 
+	networks or BSS networks or both BSS and IBSS networks. This 
+	command can be used with sub commands,
+
+	where the value for 
+			bss 	-- Scan All the BSS networks.
+			ibss 	-- Scan All the IBSS networks.
+			any 	-- Scan both BSS and IBSS networks.
+			
+deepsleep                    
+	This command is used to configure the station in deepsleep mode.
+
+	where the option is:
+			1 	-- Enable deepsleep mode
+			0 	-- Disable deepsleep mode
+			2 	-- Display deepsleep setting 
+	Usage:
+	iwpriv ethX deepsleep 1
+			Enable deepsleep mode
+	iwpriv ethX deepsleep 0
+			Disable deepsleep mode
+	iwpriv ethX deepsleep 2
+			Display deepsleep setting
+
+autodeepsleep                    
+	This command is used to configure the station in auto deepsleep mode.
+
+	where the option is:
+			1 	-- Enable auto deepsleep mode
+			0 	-- Disable auto deepsleep mode
+	Usage:
+	iwpriv ethX autodeepsleep
+			Read the current auto deepsleep setting
+	iwpriv ethX autodeepsleep 1
+			Enable auto deepsleep mode
+	iwpriv ethX autodeepsleep 0
+			Disable auto deepsleep mode
+
+hscfg	
+	This command is used to configure the host sleep parameters.
+
+		iwpriv ethX hscfg Condition [GPIO# [Gap]]
+
+	Note:
+
+	1) This command takes one (Condition) or two (Condition and GPIO#) or three (Condition, GPIO# and gap)
+	parameters.
+
+		where Condition is:
+			bit 0 = 1 	-- broadcast data
+			bit 1 = 1 	-- unicast data
+			bit 2 = 1 	-- mac event
+			bit 3 = 1 	-- multicast packet
+
+		where GPIO is the pin number of GPIO used to wakeup the host. It could be any valid
+		GPIO pin# (e.g. 0-7) or 0xff (Interface, e.g. SDIO will be used instead).
+		
+		where Gap is the gap in milli seconds between wakeup signal and wakeup event
+		or 0xff for special setting.
+
+	2) the Host Sleep mode will be cancelled if condition is set to -1.
+	
+	3) Usage:
+		iwpriv eth1 hscfg -1			# cancel host sleep mode
+
+		iwpriv eth1 hscfg 3			# broadcast and unicast data
+							# use GPIO and GAP set previously
+	
+		iwpriv eth1 hscfg 2 0x3			# unicast data
+							# use GPIO 3
+							# use GAP set previously
+
+		iwpriv eth1 hscfg 2 1 0xa0		# unicast data
+							# use GPIO 1
+							# gap: 160 ms
+
+		iwpriv eth1 hscfg 2 0xff		# unicast data
+							# use Interface (e.g. SDIO)
+							# use GAP set previously
+
+                iwpriv eth1 hscfg 0x2 0x3 0xff		# unicast data
+							# use GPIO 3
+							# special host sleep mode
+
+		iwpriv eth1 hscfg 0x2 0xff 0xff		# unicast data
+							# use Interface (e.g. SDIO)
+							# special host sleep mode
+
+hssetpara
+	This command is used to set host sleep parameters.
+
+		iwpriv ethX hssetpara Condition [GPIO# [Gap]]
+
+	Note:
+	1) The usages of parameters are the same as "hscfg" command.
+	2) The parameters will be saved in the driver and be usded when host suspends.
+
+setwpaie                      
+	This command is used by WPA supplicant to send the WPA-IE to the driver. 
+
+setaeskey
+	This command is used to set the AES key, when the station is in Ad-hoc
+	mode.
+
+	where value can be any 16 byte value.
+
+	Usage:
+		iwpriv ethX setaeskey 12345678901234567890123456789012
+
+getaeskey
+	This command is used to get the AES key, when the station is in Ad-hoc
+	mode.
+
+rmaeskey
+	This command is used to remove the Ad-Hoc AES key that is previously set.
+	It will disable ad-hoc AES as well.
+
+getcis
+	This command is used to read the Card Info Structure Table.
+	
+getlog
+	This command is used to get the 802.11 statistics available in the 
+		station.
+	
+	Note: This command is available only when STA is connected.
+
+getadhocstatus
+	This command is used to get the ad-hoc Network Status.
+
+	The various status codes are:
+		AdhocStarted
+		AdhocJoined
+		AdhocIdle
+		InfraMode
+		AutoUnknownMode
+
+	Note: This command is available only when STA is connected.
+
+adhocgrate
+	This command is used to enable(1) g_rate, Disable(0) g_rate 
+	and request(2) the status which g_rate is disabled/enabled,
+	for Ad-hoc creator.
+
+	where value is:
+		0	-- Disable
+		1	-- Enable
+		2	-- Get
+
+ledgpio
+	This command is used to set/get LED settings.
+
+	iwpriv ethX ledgpio <LEDs>
+		will set the corresponding LED for the GPIO Line.
+
+	iwpriv ethX ledgpio
+		will get the current LEDs settings.
+
+	Usage:
+		iwpriv eth1 ledgpio 1 0 2 1 3 16
+			LED 1 -> GPIO 0
+			LED 2 -> GPIO 1
+			LED 3 -> disable
+
+		iwpriv eth1 ledgpio 
+			shows LED information in the format as mentioned above.
+
+	Note: LED 0 is invalid
+	      Maximum Number of LEDs are 3.
+	
+inactivityto
+	This command is used by the host to set/get the inactivity timeout value, 
+	which specifies when WLAN device is put to sleep.
+	
+	Usage:
+		iwpriv ethX inactivityto [<timeout>]
+
+	where the parameter are:
+		timeout: timeout value in milliseconds.
+
+	Example:
+		iwpriv eth1 inactivityto
+			"get the timeout value"
+
+		iwpriv eth1 inactivityto X 
+			"set timeout value to X ms"
+
+sleeppd
+	This command is used to configure the sleep period of the WLAN device.
+
+	Usage:
+		iwpriv ethX sleeppd [<sleep period>]
+
+	where the parameter are:
+		Period: sleep period in milliseconds. Range 10~60.
+
+	Example:
+		iwpriv eth1 sleeppd 10 
+			"set period as 10 ms"
+		iwpriv eth1 sleeppd
+			"get the sleep period configuration"
+
+enable11d
+	This command is used to control 11d
+	where value is:
+		1	-- Enable
+		0	-- Disable
+		2	-- Get
+
+wmm
+	This command is used to control WMM
+
+	where value is:
+		0	-- Disable
+		1	-- Enable
+		2	-- Get
+
+	
+bgscan
+	Enables or disables the Background scan.
+
+	The configuration for bg scan must be set using wlanconfig
+
+	Usage:
+		wlanconfig ethX bgscanconfig bg_scan_config.conf
+		iwpriv ethX bgscan 0 (disable)
+		iwpriv ethX bgscan 1 (enable)
+		iwpriv ethX bgscan 2 (display enable or disable)
+
+tpccfg
+	Enables or disables automatic transmit power control.
+
+	The first parameter turns this feature on (1) or off (0).  When turning 
+	on, the user must also supply four more parameters in the following 
+	order:
+		-UseSNR (Use SNR (in addition to PER) for TPC algorithm),
+		-P0 (P0 power level for TPC),
+		-P1 (P1 power level for TPC),
+		-P2 (P2 power level for TPC).
+
+	Usage:
+		iwpriv ethX tpccfg: Get current configuration
+		iwpriv ethX tpccfg 0: disable auto TPC
+		iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
+							     P0=0x05; P1=0x0a; P2=0x0d;
+		iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
+							     P0=0x05; P1=0x0a; P2=0x0d.
+
+sdioclock
+	Turn On(1) or Off(0) the SDIO clock.
+
+	Usage:
+		iwpriv ethX sdioclock 1 (on)
+		iwpriv ethX sdioclock 0 (off)
+
+wmm_qosinfo
+	This command sets WMM IE QOS info when an argument is given, and gets current WMM
+	IE QOS info when no argument is given.
+
+	Usage:
+		iwpriv ethX wmm_qosinfo 0x0f (set WMM IE QOS info to 0x0f)
+		iwpriv ethX wmm_qosinfo      (get WMM IE QOS info)
+
+scanprobes
+	This command sets number of probe requests per channel.
+
+	Usage:
+		iwpriv ethX scanprobes 3 (set scan probes to 3)
+		iwpriv ethX scanprobes   (get scan probes)
+
+lolisteninter
+	This command sets the value of listen interval.
+
+	Usage:
+	iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
+	iwpriv ethX lolisteninter     (get the lolisteninter value)
+
+rateadapt
+	This command sets the data rates bitmap.
+	Where <n>
+ 		0: no HW rate drop
+		1: HW table rate drop
+		2: HW single rate drop
+	      <m>
+		 data rate bitmap
+			Bit	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			12-15	Reserved
+		<l> Threshold, Number of same rate retries before switch to Final rate.
+		    Used only if HW single rate drop is selected. Typical values are from 3 to 6.
+
+		<k> Final Rate, This value is used only if HW single rate drop is selected.
+			value	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			13-15	Reserved
+	Usage:
+	iwpriv ethX rateadapt
+			read the currect data rate setting
+	iwpriv ethX rateadapt 1 0x07
+			enable hardware auto data rate adapt and 
+			data rates are 1Mbps, 2Mbsp and 5.5Mbps
+	iwpriv ethX rateadapt 2 0x0f 6 2
+			use HW single rate drop, data rates are 1Mbps, 2Mbsp and 5.5Mbps, 11Mbps
+			Threshold is 6, Final Rate is 5.5 Mbps
+
+fwwakeupmethod
+	This command is used to set the firmware wakeup method.
+
+	where value <n> is:
+		0	-- Leave the current method to wakeup firmware unchanged
+		1	-- Firmware wakeup through the interface command interrupt
+			-- (default setting for SDIO/GSPI)
+		2	-- Firmware wakeup through the GPIO pin
+			-- (default setting for CF)
+
+	Usage:
+	iwpriv ethX fwwakeupmethod
+			Read the current firmware wakeup method setting
+	iwpriv ethX fwwakeupmethod 0
+			Leave the current method to wakeup firmware unchanged
+	iwpriv ethX fwwakeupmethod 1
+			Firmware wakeup through the interface command interrupt
+	iwpriv ethX fwwakeupmethod 2
+			Firmware wakeup through the GPIO pin
+
+txcontrol [DefaultFlags (if no UP setting)] [UserPriority] [UserPriorityFlags]
+    This command is used to set/get the TX rate, WMM ack policy, and 
+       retry limit for all packets, or selectively the packets with a specific
+       user priority.
+
+    The DefaultFlags setting is ignored for any command with 2 or more 
+       arguments.
+
+    The value of the u32 txcontrol flags returned and input for 
+       DefaultFlags or UserPriorityFlags specific settings is given by the
+       following bitmap:
+
+    bit[4:0], if bit[4] == 1:
+      bit[3:0]        -- 0  1  2    3   4   5  6  7   8   9   10  11  12  13-16
+      Data Rate(Mbps) -- 1  2  5.5  11  Rsv 6  9  12  18  24  36  48  54  Rsv
+
+    bit[12:8] 
+      if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
+
+    bit[14:13] specifies per packet ack policy:
+      if bit[14] == 1, bit[13] == 1 specifies No Ack Policy
+
+    All unused and reserved bits should be set to zero for the entire 
+      u32 field.
+
+    Usage:
+      Number of arguments given:
+
+      0: Return the default setting for the txcontrol flags
+         > iwpriv eth1 txcontrol
+
+      1: Set the default value for the txcontrol flags
+         > iwpriv eth1 txcontrol 0x6013  - No ACK, 11Mbps
+         > iwpriv eth1 txcontrol 0x151A  - 5 retries, 36Mbps
+
+      2: Return a specific User Priority setting.  If the UP setting is zero,
+         the default value will be used and returned:
+         > iwpriv eth1 txcontrol 0 7  - Return UP 7 txcontrol value (UP7 = VO)
+
+      3: Set a User Priority specific value for the txcontrol flags.  A value
+         of zero will revert to the default setting:
+         > iwpriv eth1 txcontrol 0 5 0x6013 - (UP5 = VI), No ACK 11Mbps.
+
+uapsdnullgen
+	This command is used to enable(1) UAPSD null package generation, 
+	Disable(0) UAPSD null package generation, and request(2) the status 
+	which null package generation is disabled/enabled,
+	for Ad-hoc creator.
+
+	where value is:
+		0	-- Disable
+		1	-- Enable
+		2	-- Get
+
+psnullinterval
+	This command is used to set/request NULL package interval for Power Save
+	under infrastructure mode.
+
+	where value is:
+		-1	-- Disable
+		n>0	-- Set interval as n (seconds)
+
+getrxinfo
+	This command gets non average value of Signal to Noise Ratio of Data and rate index.
+
+	The following table shows RateIndex and Rate
+
+		     RateIndex	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			13-15	Reserved
+
+gettxrate	 
+	This command gets current Tx rate index of the first packet associated with Rate Adaptation.
+
+	The following table shows RateIndex and Rate
+
+		     RateIndex	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			13-15	Reserved
+
+bcninterval 
+	This command is used to set beacon interval in adhoc mode when an argument is given, 
+	return the value set by the user and the current adhoc beacon interval if adapter is in connected state. 
+        The valid beacon interval is between 20 - 1000, default beacon interval is 100.
+
+	Usage:
+		iwpriv ethX bcninterval 100  (set adhoc beacon interval to 100)
+		
+		not connected:
+		iwpriv ethX bcninterval      (get adhoc beacon interval set by user)
+		
+		connected:
+		iwpriv ethX bcninterval      (get adhoc beacon interval set by user previously
+                                              and current beacon interval)
+                 
+setcoalescing
+	This command is used to disable/enable IBSS coalescing function, and get IBSS coalescing status.
+
+	where value is:
+		0	-- Disable IBSS coalescing function
+		1	-- Enable IBSS coalescing function
+		2	-- Get current IBSS coalescing status
+
+bcnmisto 
+	This command is used to set/get beacon miss timeout for Power Save
+	under infrastructure mode.
+
+	where value is:
+		0xffff -- Disabled
+		0 -- no change
+		1--50  (miliseconds)
+
+adhocawakepd 
+	This command is used to set/get adhoc awake period for Power Save Mode.
+
+	where value is:
+		0xff -- firmware will go to sleep after send out beacon
+		0--no change 
+		1--31 (beacon interval) 
+
+sdiopullctrl
+	This command is used to set/get seting of pulling up and pulling down of SDIO lines, 
+        The PullUp is the delay before pulling SDIO lines up. The PullDown is the 
+        delay before pull SDIO lines down. the unit is us for both PullUp and PullDown.
+     
+        where <m> PullUp
+              0--no delay is needed
+              0xffff--no pulling up is needed
+
+	      <n> PullDown
+	      0--no delay is needed
+              0xffff--no pulling up is needed	
+
+	Usage:
+	iwpriv ethX sdiopullctrl
+			Read the currect firmware SDIO PullUp and PullDown settings	     	
+        iwpriv ethX sdiopullctrl 5  5
+			Set SDIO PullUp/PullDown to 5 us 
+	iwpriv ethX sdiopullctrl 0xffff 0xffff
+			Disable SDIO PullUp and PullDown
+
+scantime
+	This command is used to set/get scan time per channel in milliseconds.
+	The current setting will be returned every time.
+
+	Usage:
+		iwpriv ethX scantime [s] [a] [p]
+	
+	where the parameters are,
+		[s]: specific SSID/BSSID scan time, default 100 ms, max 500 ms
+		[a]: active scan time, default 100 ms, max 500 ms
+		[p]: passive scan time, default 100 ms, max 2000 ms
+		No change if the parameter is 0 or the parameter is not provided.
+
+	For example:
+		iwpriv ethX scantime 30         (set specific scan time to 30 ms)
+		iwpriv ethX scantime 0 100      (set active scan time to 100 ms)
+		iwpriv ethX scantime 30 80 200  (set specific scan time to 30 ms,
+		                                 set active scan time to 80 ms,
+		                                 set passive scan time to 200 ms)
+
+ldocfg
+	This command is used to set/get internal/external core power voltage source.
+	By default firmware uses internal LDO for 1.2V core power supply.
+	The current setting will be returned if no parameter provided.
+
+	Usage:
+		iwpriv ethX ldocfg [n]
+	
+	where the parameter is,
+		0	-- internal
+		1	-- external
+
+dataevtcfg 
+	This command is used to set/get the subscription of low RSSI, low SNR, high RSSI and 
+	high SNR events in data packet. 
+
+	Where value <a> is:
+	 	    Events bitmap
+			Bit	
+			0	RSSI_LOW 	RSSI_LOW event is generated when avg data RSSI is below threshold
+			1	SNR_LOW  	SNR_LOW event is generated when avg data SNR is below threshold
+			2	RSSI_HIGH	RSSI_HIGH event is generated when avg data RSSI go above threshold
+			3	SNR_HIGH 	SNR_HIGH event is generated when avg data SNR go above threshold
+
+	Where value <b> is:				
+			RSSI_LOW threshold (Absolute value, the actual value should be negative)
+	Where value <c> is:
+			RSSI_LOW reporting frequency. if set to 0, event will only report once. 
+			if set to 1, event will be reported every time it occur. 
+			if set to N, event will be reported only when the condition happens N consecutive times.
+
+	Where value <d> is:				
+			SNR_LOW threshold
+	Where value <e> is:
+			SNR_LOW reporting frequency. if set to 0, event will only report once. 
+			if set to 1, event will be reported every time it occur. 
+			if set to N, event will be reported only when the condition happens N consecutive times.
+
+	Where value <e> is:				
+			RSSI_HIGH threshold (Absolute value, the actual value should be negative)
+	Where value <f> is:
+			RSSI_HIGH reporting frequency. if set to 0, event will only report once. 
+			if set to 1, event will be reported every time it occur. 
+			if set to N, event will be reported only when the condition happens N consecutive times.
+
+	Where value <g> is:				
+			SNR_HIGH threshold
+	Where value <h> is:
+			SNR_HIGH reporting frequency. if set to 0, event will only report once. 
+			if set to 1, event will be reported every time it occur. 
+			if set to N, event will be reported only when the condition happens N consecutive times.
+
+	Usage:
+		iwpriv ethX dataevtcfg		(get current data subscribe event settings)
+		iwpriv ethX dataevtcfg 15 70 1 56 0 40 5 86 0
+		                      		(set current data subscribe event, 
+		                      		 when avg data RSSI below -70, such as -80,
+		                      		 RSSI_LOW event will be generated every time;
+		                      		 when avg data RSSI above -40 happens 5 consecutive times, 
+						 such as -30,-32,-34,-29,-33, RSSI_HIGH event will be generated 1 times; 
+		                      		 when avg data SNR below 56 or above 86, 
+		                      		 SNR_LOW or SNR_HIGHT event will be generated once)
+
+drvdbg
+	This command is used to set/get the bit masks of driver debug message control.
+
+	Usage:
+		iwpriv ethX drvdbg [n] [m]
+
+	Where the parameter <n> is the generic debug message control bit mask.
+	The following types of driver debug messages can be dynamically enabled or 
+	disabled by setting or clearing the corresponding bits, 
+		bit 0:  MSG  		PRINTM(MSG,...)
+		bit 1:  FATAL		PRINTM(FATAL,...)
+		bit 2:  ERROR		PRINTM(ERROR,...)
+		bit 3:  DATA 		PRINTM(DATA,...)
+		bit 4:  CMND 		PRINTM(CMND,...)
+		bit 5:  EVENT		PRINTM(EVENT,...)
+		bit 6:  INTR 		PRINTM(INTR,...)
+		...
+		bit 16: DAT_D		PRINTM(DAT_D,...), DBG_HEXDUMP(DAT_D,...)
+		bit 17: CMD_D		PRINTM(CMD_D,...), DBG_HEXDUMP(CMD_D,...)
+		bit 18: FW_D		PRINTM(FW_D,...)
+		...
+		bit 28: ENTRY		PRINTM(ENTRY,...), ENTER(), LEAVE()
+		bit 29: WARN 		PRINTM(WARN,...)
+		bit 30: INFO 		PRINTM(INFO,...)
+
+	Where the parameter <m> is the extended interface module debug message control 
+	bit mask. The following types of debug messages can be controlled.
+
+		bit 0:  IF_D 		PRINTM(IF_D,...),  DBG_HEXDUMP(IF_D,...)
+
+	If CONFIG_DEBUG=2, all kinds of debug messages can be configured. 
+	By default all debug messages are enabled except for EVENT and IF_D.
+
+	If CONFIG_DEBUG=1, all kinds of debug messages can be configured except 
+	for ENTRY, WARN and INFO. By default MSG and FATAL are enabled.
+
+	Some special debug messages,
+		'*'		// WLAN driver ISR is called (bit 6 INTR enabled)
+		'|'		// PS awake event is received (bit 5 EVENT enabled)
+		'_'		// PS sleep event is received (bit 5 EVENT enabled)
+		'+'		// PS sleep confirm is sent (bit 5 EVENT enabled)
+
+	For example:
+		iwpriv ethX drvdbg          (get the current driver debug masks)
+		iwpriv ethX drvdbg 0 0      (disable all the debug messages)
+		iwpriv ethX drvdbg 7        (enable MSG, FATAL and ERROR messages,
+		                             no change for if debug control)
+		iwpriv ethX drvdbg 3 1      (enable MSG and FATAL messages,
+		                             enable IF_D message)
+		iwpriv ethX drvdbg -1 -1    (enable all the debug messages)
+
+adhocgprot 
+	This command is used to set/get 802.11g ad-hoc protection state.
+
+	where value is:
+		0	-- Disable
+		1	-- Enable
+		2	-- Get
+	Usage:
+		iwpriv ethX adhocgprot 0        (disable 802.11g ad-hoc g protection)
+		iwpriv ethX adhocgprot 1        (enable 802.11g ad-hoc g protection)
+		iwpriv ethX adhocgprot 2        (get 802.11g ad-hoc g protection state)
+
+getrate 
+	This command is used to get the supported rates. Returned rates are in 0.5M unit.
+
+associate <scan table index>
+    Associate to a specific BSS entry in the scan table.  The enumeration
+       of the entries in the scan table is determined by the 
+       getscantable API or from the iwlist scan results.  A re-scan is not
+       performed before the association attempt is made.
+
+
+===============================================================================
+
+		U S E R  M A N U A L  F O R  W L A N _ C O N F I G 
+
+NAME
+wlanconfig - configure the additional parameters available for the Marvell 
+		WLAN Linux Driver.
+
+SYNOPSIS
+wlanconfig -v
+wlanconfig <ethX> <command> [parameters] ...
+
+wlanconfig ethX version
+wlanconfig ethX <rdmac|rdbbp|rdrf> <offset>
+wlanconfig ethX <wrmac|wrbbp|wrrf> <offset> <n>
+wlanconfig ethX sdcmd52r  <FN no.>  <address>
+wlanconfig ethX sdcmd52w  <FN no.>  <address> <data>
+wlanconfig ethX caldataext <filename>
+wlanconfig ethX rdeeprom <offset> <length>
+wlanconfig ethX sleepparams <config values>
+wlanconfig ethX bca-ts <config values>
+wlanconfig ethX extscan <ssid>
+wlanconfig ethX getscanlist
+
+Version 4 Command:
+wlanconfig ethX bgscanconfig <filename>
+
+Version 5 Command:
+wlanconfig ethX hostcmd <hostcmd.conf> <subevent_get>
+wlanconfig ethX hostcmd <hostcmd.conf> <subevent_set>
+
+Version 6 Command:
+wlanconfig ethX setuserscan [ARGS]
+wlanconfig ethX getscantable
+wlanconfig ethX getassocrsp
+
+Version 8
+wlanconfig ethX addts <filename.conf> <section# of tspec> <timeout in ms>
+wlanconfig ethX delts <filename.conf> <section# of tspec>
+wlanconfig ethX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
+wlanconfig ethX qconfig get [Queue Id: 0-3]
+wlanconfig ethX qconfig def [Queue Id: 0-3]
+wlanconfig ethX qstats on  [Queue Id: 0-3]
+wlanconfig ethX qstats off [Queue Id: 0-3]
+wlanconfig ethX qstats get [Queue Id: 0-3]
+wlanconfig ethX hostcmd <hostcmd.conf> <pa_cfg_ext_get>
+wlanconfig ethX hostcmd <hostcmd.conf> <pa_cfg_ext_set>
+wlanconfig ethX hostcmd <hostcmd.conf> <arp_filter>
+wlanconfig ethX hostcmd <hostcmd.conf> <auto_tx_get>
+wlanconfig ethX hostcmd <hostcmd.conf> <NatKeepAlive>
+wlanconfig ethX hostcmd <hostcmd.conf> <auto_tx_unreg>
+wlanconfig ethX hostcmd <hostcmd.conf> <ledctrl_get>
+wlanconfig ethX hstest
+wlanconfig ethX getcfptable [region]
+
+Version 9
+wlanconfig ethX gettsf
+wlanconfig ethX arpfilter <arpfilter.conf>
+wlanconfig ethX txpktstats
+
+DESCRIPTION
+
+those commands are used in Marvell specic applicaion called wlanconfig.
+
+===========
+-v
+	This command is used to display the version of wlanconfig utility.
+	Usage:	
+		wlanconfig -v
+ 
+rdmac 
+rdbbp
+rdrf	
+	These commands are used to read the MAC, BBP and RF registers from the 
+	card.  These commands take one parameter that specifies the offset 
+	location that is to be read.  This parameter can be specified either in 
+	decimal or in hexadecimal (by preceding the number with a "0x").
+		
+	Usage:	
+		wlanconfig ethX rdmac 0xa123
+		wlanconfig ethX rdbbp 0x0123
+		wlanconfig ethX rdrf 0x0123
+
+wrmac 
+wrbbp
+wrrf	
+	These commands are used to write the MAC, BBP and RF registers in the 
+	card.  These commands take two parameters that specify the offset 
+	location and the value that is to be written. This parameters can be 
+	specified either in decimal or in hexadecimal (by preceding the number 
+	with a "0x").
+	
+	Usage:
+		wlanconfig ethX wrmac 0xa123 0xaa
+		wlanconfig ethX wrbbp 0x0123 0xaa
+		wlanconfig ethX wrrf 0x0123 0xaa
+
+sdcmd52r  
+	This command is used to read a controller register in 
+	Secure Digital I/O Interfaces.
+	
+	wlanconfig eth1 sdcmd52r <function number> <register address> 
+
+	Usage:
+		wlanconfig eth1 sdcmd52r 0x00 0x07
+
+sdcmd52w
+	This command is used to write to a controller register in 
+	Secure Digital I/O Interfaces. 
+	
+	wlanconfig eth1 sdcmd52w <function number> <register address> <value>
+
+	Usage:
+		wlanconfig eth1 sdcmd52w 0x00 0x02 0x0a
+
+caldataext
+	In order to overcome the situation without EEPROM in the WLAN module, 
+	we send the extension calibration command to modify the existing 
+	hardware-spec command. This command takes one parameter that specifies 
+	the file name of the configuration file.
+
+	Usage:
+	wlanconfig eth1 caldataext <cal_data_ext_set_<version>.conf>
+		cal_data_ext_set_<version>.conf is a configuration file to the 
+		wlanconfig to set the calibration values. The 3 existing 
+		versions are v5, vA and v7. 
+		Example:
+		  wlanconfig eth1 caldataext cal_data_ext_set_v5.conf
+		Edit this file for changing calibration values.			
+
+rdeeprom
+	To read the EEPROM contents of the card.
+	
+	Usage:
+	wlanconfig ethX rdeeprom 0x00 0x10
+	
+sleepparams       
+	This command is used to set the sleepclock configurations
+	
+	Usage:
+		wlanconfig ethX sleepparams get: reads the current sleepclock configuration
+	
+		wlanconfig ethX sleepparams set p1 p2 p3 p4 p5 p6: writes the sleepclock configuration.
+			
+		where:
+			p1 is Sleep clock error in ppm (0-65535)
+			p2 is Wakeup offset in usec (0-65535)
+			p3 is Clock stabilization time in usec (0-65535)
+			p4 is Control periodic calibration (0-2)
+			p5 is Control the use of external sleep clock (0-2)
+			p6 is reserved for debug (0-65535)
+
+bca-ts
+	This command is used to set/get the BCA timeshare parameters.
+ 
+	This command only works after BCA been enabled. 
+	
+	Usage:
+		wlanconfig ethX bca-ts <Traffic Type> <TimeShareInterval> <BTTime>
+
+		where:
+			Traffic Type 0 - Wlan and bluetooth are low priority.
+				     1 - Wlan and bluetooth are high priority.
+ 	
+			TimeShareInterval value is not multiple of 10 then floor value 
+			is taken and the valid range is < 20 ... 60,000 > in milliseconds.
+
+			BTTime value is  not multiple of 10 then floor value is
+			taken and the valid range is < 0 ... TimeShareInterval value >
+			in milliseconds.
+
+	Example:
+		wlanconfig ethX bca-ts get 1  
+				get the BCA timeshare settings when wlan and bluetooth are set to high priority.  
+
+		wlanconfig ethX bca-ts set 1 30 20
+				set wlan and bluetooth to high priority, wlan TimeShareInterval to 30ms, BTTime to 20ms.
+				
+
+bgscanconfig
+	This will configure the various parameters for background scan.
+
+	wlanconfig ethX bgscanconfig bg_scan_config.conf
+	
+	bg_scan_config.conf is the configuration file to wlanconfig
+	
+	Edit this file for changing bg scan values.
+
+hostcmd <hostcmd.conf> <subevent_get>
+hostcmd <hostcmd.conf> <subevent_set>
+	This command is used to set the configurations for 
+		event descriptor interface command.
+	hostcmd.conf is a generic configuration file containing multiple configuration enties
+		for subscrive event API
+	subsvent_get: get subscribed event parameters
+	subsvent_set: set subscribed event parameters
+
+	Usage:
+		wlanconfig ethX hostcmd hostcmd.conf subevent_get
+		wlanconfig ethX hostcmd hostcmd.conf subevent_set
+
+extscan
+	This command is used to do a specific scan.
+	
+	Usage: wlanconfig ethX extscan <SSID>
+
+	Example:
+		wlanconfig ethX extscan LINKSYS-AP
+
+	To see the results of use getscanlist command.
+
+getscanlist
+	This command is used to get the scan results.
+
+	Usage: wlanconfig ethX getscanlist
+		
+	Example:
+		wlanconfig ethX getscanlist
+
+setuserscan
+    Initiate a customized scan and retrieve the results
+
+    Usage:
+       wlanconfig ethX setuserscan [ARGS]
+
+         where [ARGS]: 
+
+      chan=[chan#][band][mode] where band is [a,b,g] and mode is 
+                               blank for active or 'p' for passive
+      bssid=xx:xx:xx:xx:xx:xx  specify a BSSID filter for the scan
+      ssid="[SSID]"            specify a SSID filter for the scan
+      wc="[WILDCARD SSID]"     specify a UNIX pattern matching filter (using *
+                               and ?) for SSIDs found in a broadcast probe 
+      keep=[0 or 1]            keep the previous scan results (1), discard (0)
+      dur=[scan time]          time to scan for each channel in milliseconds
+      probes=[#]               number of probe requests to send on each chan
+                               for each broadcast probe required and each SSID
+                               specific probe required
+      type=[1,2,3]             BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+ 
+    Any combination of the above arguments can be supplied on the command line.
+      If the chan token is absent, a full channel scan will be completed by 
+      the driver.  If the dur or probes tokens are absent, the driver default
+      setting will be used.  The bssid and ssid fields, if blank, 
+      will produce an unfiltered scan. The type field will default to 3 (Any)
+      and the keep field will default to 0 (Discard).
+
+    Examples:
+    1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+            setuserscan chan=1g,6g,11g
+
+    2) Perform a passive scan on channel 11 for 20 ms:
+            setuserscan chan=11gp dur=20
+
+    3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+       channel 36 in the 'a' band:
+            setuserscan chan=1g,6g,11g,36ap
+
+    4) Perform an active scan on channel 6 and 36 for a specific SSID:
+            setuserscan chan=6g,36a ssid="TestAP"
+
+    5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+       the current scan table intact, update existing or append new scan data:
+            setuserscan bssid=00:50:43:20:12:82 keep=1
+
+    6) Scan channel 6, for all infrastructure networks, sending two probe 
+       requests.  Keep the previous scan table intact. Update any duplicate
+       BSSID/SSID matches with the new scan data:
+            setuserscan chan=6g type=1 probes=2 keep=1
+
+    7) Scan channel 1 and 6, for all networks matching the Mrvl*AP
+       or AP*Mrvl? patterns and for MrvlTst SSID.  Generate 3 broadcast
+       probes for the patterns and 3 SSID specific probes for MrvlTst on
+       both channel 1 and channel 6.
+            chan=1g,6g probes=3 wc="Mrvl*AP" wc="AP*Mrvl?" ssid="MrvlTst"
+
+    All entries in the scan table (not just the new scan data when keep=1) 
+    will be displayed upon completion by use of the getscantable ioctl.
+
+getscantable
+    Display the current contents of the driver scan table
+
+    Usage:
+       wlanconfig ethX getscantable
+       wlanconfig ethX getscantable [#]
+       wlanconfig ethX getscantable tsf
+       wlanconfig ethX getscantable help
+
+    1) Without argument, the entire scantable is displayed.
+    2) Specifying a # will display detailed information about a specific scan
+       table entry.  '0' displays driver cached information regarding the 
+       current association (if any).
+    3) The tsf argument will display the entire scan table with the recorded
+       TSF timestamp for the entry.
+    4) The help argument will display the legend for the capability field
+
+getassocrsp
+    Display the contents of the driver association response buffer.  The 
+       driver buffer is cleared after the response is returned to prevent
+       state response buffer returns.
+
+    Usage:
+       wlanconfig ethX getassocrsp
+
+setmrvltlv
+    Setup a test Marvell TLV for the driver to insert in the next 
+       association command to the firmware.  
+
+    wlanconfig will provision a test TLV that can be verified in the assoc.
+       response to the AP.  Used to test the IOCTL functionality.
+
+    Usage:
+       wlanconfig ethX setmrvltlv
+
+addts
+    Send an ADDTS command to the associated AP.
+
+    Process a given conf file for a specific TSPEC data block.  Send the
+      TSPEC along with any other IEs to the driver/firmware for transmission
+      in an ADDTS request to the associated AP.  
+ 
+    Return the execution status of the command as well as the ADDTS response
+      from the AP if any.
+   
+    Usage:
+       wlanconfig ethX addts <filename.conf> <section# of tspec> <timeout(ms)>
+
+delts
+    Send a DELTS command to the associated AP.
+
+    Process a given conf file for a specific TSPEC data block.  Send the
+      TSPEC along with any other IEs to the driver/firmware for transmission
+      in a DELTS request to the associated AP.  
+ 
+    Return the execution status of the command.  There is no response to a
+      DELTS from the AP.
+   
+    Usage:
+       wlanconfig ethX delts <filename.conf> <section# of tspec>
+
+qconfig
+    Send a WMM AC Queue configuration command to get/set/default params
+ 
+    Configure or get the parameters of a WMM AC queue. The command takes
+      an optional Queue Id as a last parameter.  Without the queue id, all
+      queues will be acted upon.
+ 
+    Usage:  
+       wlanconfig ethX qconfig set msdu <lifetime in TUs> [Queue Id: 0-3]
+       wlanconfig ethX qconfig get [Queue Id: 0-3]
+       wlanconfig ethX qconfig def [Queue Id: 0-3]
+
+qstats
+    Turn on/off or retrieve and clear the queue statistics for an AC
+
+    Turn the queue statistics collection on/off for a given AC or retrieve the
+      current accumulated stats and clear them from the firmware.  The command
+      takes an optional Queue Id as a last parameter.  Without the queue id,
+      all queues will be acted upon.
+ 
+    Usage:
+       wlanconfig ethX qstats on  [Queue Id: 0-3]
+       wlanconfig ethX qstats off [Queue Id: 0-3]
+       wlanconfig ethX qstats get [Queue Id: 0-3]
+
+hostcmd <hostcmd.conf> <pa_cfg_ext_get>
+hostcmd <hostcmd.conf> <pa_cfg_ext_set>
+    This configures the power adaptation paramemters
+
+    Usage:
+	wlanconfig ethX hostcmd hostcmd.conf pa_cfg_ext_get
+	wlanconfig ethX hostcmd hostcmd.conf pa_cfg_ext_set
+	
+	hostcmd.conf is a generic configuration file containing multiple configuration enties
+		for power adapation
+	pa_cfg_ext_get: get pa_cfg_ext parameters
+	pa_cfg_ext_set: set pa_cfg_ext parameters
+	
+	The following table shows the bitmap of the rates (bit 0 is the least significant bit):
+
+		        Bit	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			13-15	Reserved
+
+	Up to 5 power level groups are supported.
+
+	The default power adaptation groups:
+
+		Power Level	Rate Bitmap (Mbps)
+		13 dbm		0x1800 (54, 48)
+		15 dbm		0x07e0 (36, 24, 18, 12, 9, 6)
+		18 dbm		0x000f (11, 5.5, 2, 1)
+
+	Edit the hostcmd.conf file to change the settings
+
+hostcmd <hostcmd.conf> <arp_filter>
+	This is an extended host_sleep_cfg command to configure the ARP filtering parameters.
+
+	Usage:
+		wlanconfig ethX hostcmd hostcmd.conf arp_filter
+
+	Edit the arp_filter section in hostcmd.conf file to change the settings
+
+hostcmd <hostcmd.conf> <auto_tx_get>
+hostcmd <hostcmd.conf> <NatKeepAlive>
+hostcmd <hostcmd.conf> <auto_tx_unreg>
+    This configures the Frame Auto Transmission paramemters
+
+    Usage:
+	wlanconfig ethX hostcmd hostcmd.conf auto_tx_get
+	wlanconfig ethX hostcmd hostcmd.conf NatKeepAlive
+	wlanconfig ethX hostcmd hostcmd.conf auto_tx_unreg
+	
+	hostcmd.conf is a generic configuration file containing multiple configuration enties
+		for Frame Auto Transmission
+	auto_tx_get: get auto_tx parameters
+	NatKeepAlive: register to firmware for sending NAT Keep Alive packet
+	auto_tx_unreg: unregister to firmware auto_tx
+	
+	Edit the auto_tx section in hostcmd.conf file to change the settings
+
+hostcmd <hostcmd.conf> <ledctrl_get>
+	This command is used to set/get LED control.
+
+	Usage:
+		wlanconfig ethX hostcmd hostcmd.conf ledctrl_get
+		wlanconfig ethX hostcmd hostcmd.conf ledctrl_set
+
+	hostcmd.conf is a generic configuration file containing multiple configuration enties
+		for LED Ctrl
+	led_ctrl_get: get auto_tx parameters
+	led_ctrl_set: set auto_tx parameters
+	
+	Edit the ledctrl section in hostcmd.conf file to change the settings
+	
+hstest
+    This command runs in the background to handle GPIO/SDIO interrupt events
+    in HOST SLEEP mode.
+
+    Usage:
+	wlanconfig ethX hstest &
+
+getcfptable
+	This command is used to get Channel-Freq-MaxTxPower table based on the region code.
+	If no parameter provided, the CFP table for current region code will be returned.
+
+	Usage:
+		wlanconfig ethX getcfptable [region]
+
+gettsf
+    Display the current MAC TSF value.
+
+arpfilter <arpfilter.conf>
+	This command is used to configure the ARP filtering parameters.
+
+	Usage:
+		wlanconfig ethX arpfilter arpfilter.conf
+
+	Edit arpfilter.conf file to change the settings
+
+txpktstats
+    Retrieve and clear transmit packet statistics collected by the firmware:
+
+    The API displays the following statistics for each rate:
+       - Number of packets initially queued using the rate
+       - Number of total attempts for the packets queued using this initial
+         rate.  This includes attempts at other rates in case of hardware or
+         single rate drop modes.
+       - Number of retry exhaustion failures for packets queued using this
+         initial rate.
+       - Number of MSDU lifetime expiry failures for packets queued using 
+         this initial rate.
+       - Number of packets successfully completed at this rate
+
+==============================================================================
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/release_version.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/release_version.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/release_version.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/release_version.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,19 @@
+/**
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+
+#define DRIVER_RELEASE_VERSION		"26409.p39"
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/hostcmd.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/hostcmd.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/hostcmd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/hostcmd.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,1057 @@
+/** @file hostcmd.h
+ * 
+ * @brief This file contains the function prototypes, data structure 
+ * and defines for all the host/station commands
+ *  
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	10/11/05: Add Doxygen format comments
+	01/11/06: Update association struct to reflect IEEE passthrough response
+	          Conditionalize new scan/join structures
+	04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	05/03/06: Add auto_tx hostcmd
+	05/04/06: Add IBSS coalescing related new hostcmd
+	08/28/06: Add LED_CTRL hostcmd
+	08/29/06: Add ledgpio private command
+********************************************************/
+
+#ifndef __HOSTCMD__H
+#define __HOSTCMD__H
+
+/*  802.11-related definitions */
+
+/** TxPD descriptor */
+typedef struct _TxPD
+{
+    /** Current Tx packet status */
+    u32 TxStatus;
+    /** Tx Control */
+    u32 TxControl;
+    u32 TxPacketLocation;
+    /** Tx packet length */
+    u16 TxPacketLength;
+        /**Destination MAC address */
+    u8 TxDestAddr[MRVDRV_ETH_ADDR_LEN];
+    /** Pkt Priority */
+    u8 Priority;
+    /** Trasnit Pkt Flags*/
+    u8 Flags;
+    /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+    u8 PktDelay_2ms;
+    /** Reserved */
+    u8 Reserved1;
+
+} __ATTRIB_PACK__ TxPD, *PTxPD;
+
+/** RxPD Descriptor */
+typedef struct _RxPD
+{
+        /** Current Rx packet status */
+    u16 RxStatus;
+
+        /** SNR */
+    u8 SNR;
+
+        /** Tx Control */
+    u8 RxControl;
+
+        /** Pkt Length */
+    u16 PktLen;
+
+        /** Noise Floor */
+    u8 NF;
+
+        /** Rx Packet Rate */
+    u8 RxRate;
+
+        /** Pkt offset */
+    u32 PktOffset;
+    u8 RxPacketType;
+    u8 Reserved_1[3];
+        /** Pkt Priority */
+    u8 Priority;
+    u8 Reserved[3];
+
+} __ATTRIB_PACK__ RxPD, *PRxPD;
+
+#if defined(__KERNEL__)
+
+/** CmdCtrlNode */
+typedef struct _CmdCtrlNode
+{
+    /* CMD link list */
+    struct list_head list;
+
+    u32 Status;
+
+    /* CMD ID */
+    WLAN_OID cmd_oid;
+
+    /*CMD wait option: wait for finish or no wait */
+    u16 wait_option;
+
+    /* command parameter */
+    void *pdata_buf;
+
+    /*command data */
+    u8 *BufVirtualAddr;
+
+    u16 CmdFlags;
+
+    /* wait queue */
+    u16 CmdWaitQWoken;
+    wait_queue_head_t cmdwait_q __ATTRIB_ALIGN__;
+} __ATTRIB_PACK__ CmdCtrlNode, *PCmdCtrlNode;
+
+#endif
+
+/** MRVL_WEP_KEY */
+typedef struct _MRVL_WEP_KEY
+{
+    u32 Length;
+    u32 KeyIndex;
+    u32 KeyLength;
+    u8 KeyMaterial[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
+} __ATTRIB_PACK__ MRVL_WEP_KEY, *PMRVL_WEP_KEY;
+
+typedef ULONGLONG WLAN_802_11_KEY_RSC;
+
+/** WLAN_802_11_KEY */
+typedef struct _WLAN_802_11_KEY
+{
+    u32 Length;
+    u32 KeyIndex;
+    u32 KeyLength;
+    WLAN_802_11_MAC_ADDRESS BSSID;
+    WLAN_802_11_KEY_RSC KeyRSC;
+    u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+} __ATTRIB_PACK__ WLAN_802_11_KEY;
+
+/** MRVL_WPA_KEY */
+typedef struct _MRVL_WPA_KEY
+{
+    u32 KeyIndex;
+    u32 KeyLength;
+    u32 KeyRSC;
+    u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+} MRVL_WPA_KEY, *PMRVL_WPA_KEY;
+
+/** MRVL_WLAN_WPA_KEY */
+typedef struct _MRVL_WLAN_WPA_KEY
+{
+    u8 EncryptionKey[16];
+    u8 MICKey1[8];
+    u8 MICKey2[8];
+} MRVL_WLAN_WPA_KEY, *PMRVL_WLAN_WPA_KEY;
+
+/* Received Signal Strength Indication  in dBm*/
+typedef LONG WLAN_802_11_RSSI;
+
+/** WLAN_802_11_WEP */
+typedef struct _WLAN_802_11_WEP
+{
+    /* Length of this structure */
+    u32 Length;
+
+    /* 0 is the per-client key, 1-N are the global keys */
+    u32 KeyIndex;
+
+    /* length of key in bytes */
+    u32 KeyLength;
+
+    /* variable length depending on above field */
+    u8 KeyMaterial[1];
+} __ATTRIB_PACK__ WLAN_802_11_WEP;
+
+/** WLAN_802_11_SSID */
+typedef struct _WLAN_802_11_SSID
+{
+    /* SSID Length */
+    u32 SsidLength;
+
+    /* SSID information field */
+    u8 Ssid[WLAN_MAX_SSID_LENGTH];
+} __ATTRIB_PACK__ WLAN_802_11_SSID;
+
+typedef u32 WLAN_802_11_FRAGMENTATION_THRESHOLD;
+typedef u32 WLAN_802_11_RTS_THRESHOLD;
+typedef u32 WLAN_802_11_ANTENNA;
+
+/** wlan_offset_value */
+typedef struct _wlan_offset_value
+{
+    u32 offset;
+    u32 value;
+} wlan_offset_value;
+
+/** WLAN_802_11_FIXED_IEs */
+typedef struct _WLAN_802_11_FIXED_IEs
+{
+    u8 Timestamp[8];
+    u16 BeaconInterval;
+    u16 Capabilities;
+} WLAN_802_11_FIXED_IEs;
+
+/** WLAN_802_11_VARIABLE_IEs */
+typedef struct _WLAN_802_11_VARIABLE_IEs
+{
+    u8 ElementID;
+    u8 Length;
+    u8 data[1];
+} WLAN_802_11_VARIABLE_IEs;
+
+/** WLAN_802_11_AI_RESFI */
+typedef struct _WLAN_802_11_AI_RESFI
+{
+    u16 Capabilities;
+    u16 StatusCode;
+    u16 AssociationId;
+} WLAN_802_11_AI_RESFI;
+
+/** WLAN_802_11_AI_REQFI */
+typedef struct _WLAN_802_11_AI_REQFI
+{
+    u16 Capabilities;
+    u16 ListenInterval;
+    WLAN_802_11_MAC_ADDRESS CurrentAPAddress;
+} WLAN_802_11_AI_REQFI;
+
+/* Define general data structure */
+/** HostCmd_DS_GEN */
+typedef struct _HostCmd_DS_GEN
+{
+    u16 Command;
+    u16 Size;
+    u16 SeqNum;
+    u16 Result;
+} __ATTRIB_PACK__ HostCmd_DS_GEN, HostCmd_DS_802_11_DEEP_SLEEP;
+
+#define S_DS_GEN    sizeof(HostCmd_DS_GEN)
+/*
+ * Define data structure for HostCmd_CMD_GET_HW_SPEC
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+/** HostCmd_DS_GET_HW_SPEC */
+typedef struct _HostCmd_DS_GET_HW_SPEC
+{
+    /* HW Interface version number */
+    u16 HWIfVersion;
+
+    /* HW version number */
+    u16 Version;
+
+    /* Max number of TxPD FW can handle */
+    u16 NumOfTxPD;
+
+    /* Max no of Multicast address  */
+    u16 NumOfMCastAdr;
+
+    /* MAC address */
+    u8 PermanentAddr[6];
+
+    /* Region Code */
+    u16 RegionCode;
+
+    /* Number of antenna used */
+    u16 NumberOfAntenna;
+
+    /* FW release number, example 0x1234=1.2.3.4 */
+    u32 FWReleaseNumber;
+
+    u32 Reserved_1;
+
+    u32 Reserved_2;
+
+    u32 Reserved_3;
+
+    /*FW/HW Capability */
+    u32 fwCapInfo;
+} __ATTRIB_PACK__ HostCmd_DS_GET_HW_SPEC;
+
+typedef struct _HostCmd_DS_802_11_SUBSCRIBE_EVENT
+{
+    u16 Action;
+    u16 Events;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SUBSCRIBE_EVENT;
+
+/* 
+ * This scan handle Country Information IE(802.11d compliant) 
+ * Define data structure for HostCmd_CMD_802_11_SCAN 
+ */
+/** HostCmd_DS_802_11_SCAN */
+typedef struct _HostCmd_DS_802_11_SCAN
+{
+    u8 BSSType;
+    u8 BSSID[ETH_ALEN];
+    u8 TlvBuffer[1];
+    /* MrvlIEtypes_SsIdParamSet_t   SsIdParamSet; 
+     * MrvlIEtypes_ChanListParamSet_t       ChanListParamSet;
+     * MrvlIEtypes_RatesParamSet_t  OpRateSet; 
+     * */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SCAN;
+
+typedef struct _HostCmd_DS_802_11_SCAN_RSP
+{
+    u16 BSSDescriptSize;
+    u8 NumberOfSets;
+    u8 BssDescAndTlvBuffer[1];
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SCAN_RSP;
+
+/** HostCmd_CMD_802_11_GET_LOG */
+typedef struct _HostCmd_DS_802_11_GET_LOG
+{
+    u32 mcasttxframe;
+    u32 failed;
+    u32 retry;
+    u32 multiretry;
+    u32 framedup;
+    u32 rtssuccess;
+    u32 rtsfailure;
+    u32 ackfailure;
+    u32 rxfrag;
+    u32 mcastrxframe;
+    u32 fcserror;
+    u32 txframe;
+    u32 reserved;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_GET_LOG;
+
+/**  HostCmd_CMD_MAC_CONTROL */
+typedef struct _HostCmd_DS_MAC_CONTROL
+{
+    u16 Action;
+    u16 Reserved;
+} __ATTRIB_PACK__ HostCmd_DS_MAC_CONTROL;
+
+/**  HostCmd_CMD_MAC_MULTICAST_ADR */
+typedef struct _HostCmd_DS_MAC_MULTICAST_ADR
+{
+    u16 Action;
+    u16 NumOfAdrs;
+    u8 MACList[MRVDRV_ETH_ADDR_LEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+} __ATTRIB_PACK__ HostCmd_DS_MAC_MULTICAST_ADR;
+
+/**  HostCmd_CMD_802_11_DEAUTHENTICATE */
+typedef struct _HostCmd_DS_802_11_DEAUTHENTICATE
+{
+    u8 MacAddr[6];
+    u16 ReasonCode;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_DEAUTHENTICATE;
+
+/** HostCmd_DS_802_11_ASSOCIATE */
+typedef struct _HostCmd_DS_802_11_ASSOCIATE
+{
+    u8 PeerStaAddr[6];
+    IEEEtypes_CapInfo_t CapInfo;
+    u16 ListenInterval;
+    u8 Reserved1[3];
+
+    /*
+     *  MrvlIEtypes_SsIdParamSet_t  SsIdParamSet;
+     *  MrvlIEtypes_PhyParamSet_t   PhyParamSet;
+     *  MrvlIEtypes_SsParamSet_t    SsParamSet;
+     *  MrvlIEtypes_RatesParamSet_t RatesParamSet;
+     */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_ASSOCIATE;
+
+/** HostCmd_RET_802_11_ASSOCIATE */
+typedef struct
+{
+    IEEEtypes_AssocRsp_t assocRsp;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_ASSOCIATE_RSP;
+
+/**  HostCmd_RET_802_11_AD_HOC_JOIN */
+typedef struct _HostCmd_DS_802_11_AD_HOC_RESULT
+{
+    u8 PAD[3];
+    u8 BSSID[MRVDRV_ETH_ADDR_LEN];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_RESULT;
+
+/**  HostCmd_CMD_802_11_SET_WEP */
+typedef struct _HostCmd_DS_802_11_SET_WEP
+{
+    /* ACT_ADD, ACT_REMOVE or ACT_ENABLE  */
+    u16 Action;
+
+    /* Key Index selected for Tx */
+    u16 KeyIndex;
+
+    /* 40, 128bit or TXWEP */
+    u8 WEPTypeForKey1;
+
+    u8 WEPTypeForKey2;
+    u8 WEPTypeForKey3;
+    u8 WEPTypeForKey4;
+    u8 WEP1[16];
+    u8 WEP2[16];
+    u8 WEP3[16];
+    u8 WEP4[16];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SET_WEP;
+
+/** HostCmd_DS_802_11_AD_HOC_STOP */
+typedef struct _HostCmd_DS_802_11_AD_HOC_STOP
+{
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_STOP;
+
+/**  HostCmd_CMD_802_11_SNMP_MIB */
+typedef struct _HostCmd_DS_802_11_SNMP_MIB
+{
+    u16 QueryType;
+    u16 OID;
+    u16 BufSize;
+    u8 Value[128];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SNMP_MIB;
+
+/** HostCmd_CMD_MAC_REG_ACCESS */
+typedef struct _HostCmd_DS_MAC_REG_ACCESS
+{
+    u16 Action;
+    u16 Offset;
+    u32 Value;
+} __ATTRIB_PACK__ HostCmd_DS_MAC_REG_ACCESS;
+
+/** HostCmd_CMD_BBP_REG_ACCESS */
+typedef struct _HostCmd_DS_BBP_REG_ACCESS
+{
+    u16 Action;
+    u16 Offset;
+    u8 Value;
+    u8 Reserved[3];
+} __ATTRIB_PACK__ HostCmd_DS_BBP_REG_ACCESS;
+
+/**  HostCmd_CMD_RF_REG_ACCESS */
+typedef struct _HostCmd_DS_RF_REG_ACCESS
+{
+    u16 Action;
+    u16 Offset;
+    u8 Value;
+    u8 Reserved[3];
+} __ATTRIB_PACK__ HostCmd_DS_RF_REG_ACCESS;
+
+/** HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef struct _HostCmd_DS_802_11_RADIO_CONTROL
+{
+    u16 Action;
+    u16 Control;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RADIO_CONTROL;
+
+/* HostCmd_DS_802_11_SLEEP_PARAMS */
+typedef struct _HostCmd_DS_802_11_SLEEP_PARAMS
+{
+    /* ACT_GET/ACT_SET */
+    u16 Action;
+
+    /* Sleep clock error in ppm */
+    u16 Error;
+
+    /* Wakeup offset in usec */
+    u16 Offset;
+
+    /* Clock stabilization time in usec */
+    u16 StableTime;
+
+    /* Control periodic calibration */
+    u8 CalControl;
+
+    /* Control the use of external sleep clock */
+    u8 ExternalSleepClk;
+
+    /* Reserved field, should be set to zero */
+    u16 Reserved;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SLEEP_PARAMS;
+
+/* HostCmd_DS_802_11_SLEEP_PERIOD */
+typedef struct _HostCmd_DS_802_11_SLEEP_PERIOD
+{
+    /* ACT_GET/ACT_SET */
+    u16 Action;
+
+    /* Sleep Period in msec */
+    u16 Period;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SLEEP_PERIOD;
+
+/* HostCmd_DS_802_11_BCA_TIMESHARE */
+typedef struct _HostCmd_DS_802_11_BCA_TIMESHARE
+{
+    /* ACT_GET/ACT_SET */
+    u16 Action;
+
+    /* Type: WLAN, BT */
+    u16 TrafficType;
+
+    /* 20msec - 60000msec */
+    u32 TimeShareInterval;
+
+    /* PTA arbiter time in msec */
+    u32 BTTime;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BCA_TIMESHARE;
+
+/* HostCmd_DS_802_11_INACTIVITY_TIMEOUT */
+typedef struct _HostCmd_DS_802_11_INACTIVITY_TIMEOUT
+{
+    /* ACT_GET/ACT_SET */
+    u16 Action;
+
+    /* Inactivity timeout in msec */
+    u16 Timeout;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_INACTIVITY_TIMEOUT;
+
+/** HostCmd_CMD_802_11_RF_CHANNEL */
+typedef struct _HostCmd_DS_802_11_RF_CHANNEL
+{
+    u16 Action;
+    u16 CurrentChannel;
+    u16 RFType;
+    u16 Reserved;
+    u8 ChannelList[32];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_CHANNEL;
+
+/**  HostCmd_CMD_802_11_RSSI */
+typedef struct _HostCmd_DS_802_11_RSSI
+{
+    /* weighting factor */
+    u16 N;
+
+    u16 Reserved_0;
+    u16 Reserved_1;
+    u16 Reserved_2;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RSSI;
+
+/** HostCmd_DS_802_11_RSSI_RSP */
+typedef struct _HostCmd_DS_802_11_RSSI_RSP
+{
+    u16 SNR;
+    u16 NoiseFloor;
+    u16 AvgSNR;
+    u16 AvgNoiseFloor;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RSSI_RSP;
+
+/** HostCmd_DS_802_11_MAC_ADDRESS */
+typedef struct _HostCmd_DS_802_11_MAC_ADDRESS
+{
+    u16 Action;
+    u8 MacAdd[ETH_ALEN];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_MAC_ADDRESS;
+
+/** HostCmd_CMD_802_11_RF_TX_POWER */
+typedef struct _HostCmd_DS_802_11_RF_TX_POWER
+{
+    u16 Action;
+    u16 CurrentLevel;
+    u8 MaxPower;
+    u8 MinPower;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_TX_POWER;
+
+/** HostCmd_CMD_802_11_RF_ANTENNA */
+typedef struct _HostCmd_DS_802_11_RF_ANTENNA
+{
+    u16 Action;
+
+    /*  Number of antennas or 0xffff(diversity) */
+    u16 AntennaMode;
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_ANTENNA;
+
+/** HostCmd_CMD_802_11_PS_MODE */
+typedef struct _HostCmd_DS_802_11_PS_MODE
+{
+    u16 Action;
+    u16 NullPktInterval;
+    u16 MultipleDtim;
+    u16 BCNMissTimeOut;
+    u16 LocalListenInterval;
+    u16 AdhocAwakePeriod;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_PS_MODE;
+
+/** PS_CMD_ConfirmSleep */
+typedef struct _PS_CMD_ConfirmSleep
+{
+    u16 Command;
+    u16 Size;
+    u16 SeqNum;
+    u16 Result;
+
+    u16 Action;
+    u16 Reserved1;
+    u16 MultipleDtim;
+    u16 Reserved;
+    u16 LocalListenInterval;
+} __ATTRIB_PACK__ PS_CMD_ConfirmSleep, *PPS_CMD_ConfirmSleep;
+
+/** HostCmd_CMD_802_11_FW_WAKE_METHOD */
+typedef struct _HostCmd_DS_802_11_FW_WAKEUP_METHOD
+{
+    u16 Action;
+    u16 Method;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_FW_WAKEUP_METHOD;
+
+/** HostCmd_DS_802_11_RATE_ADAPT_RATESET */
+typedef struct _HostCmd_DS_802_11_RATE_ADAPT_RATESET
+{
+    u16 Action;
+    u16 HWRateDropMode;
+    u16 Bitmap;
+    u16 Threshold;
+    u16 FinalRate;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RATE_ADAPT_RATESET;
+
+/** HostCmd_DS_802_11_AD_HOC_START*/
+typedef struct _HostCmd_DS_802_11_AD_HOC_START
+{
+    u8 SSID[MRVDRV_MAX_SSID_LENGTH];
+    u8 BSSType;
+    u16 BeaconPeriod;
+    u8 DTIMPeriod;
+    IEEEtypes_SsParamSet_t SsParamSet;
+    IEEEtypes_PhyParamSet_t PhyParamSet;
+    u16 Reserved1;
+    IEEEtypes_CapInfo_t Cap;
+    u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_START;
+
+/** AdHoc_BssDesc_t */
+typedef struct _AdHoc_BssDesc_t
+{
+    u8 BSSID[6];
+    u8 SSID[32];
+    u8 BSSType;
+    u16 BeaconPeriod;
+    u8 DTIMPeriod;
+    u8 TimeStamp[8];
+    u8 LocalTime[8];
+    IEEEtypes_PhyParamSet_t PhyParamSet;
+    IEEEtypes_SsParamSet_t SsParamSet;
+    IEEEtypes_CapInfo_t Cap;
+    u8 DataRates[HOSTCMD_SUPPORTED_RATES];
+
+    /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE.      It is used below in the
+     *      Adhoc join command and will cause a binary layout mismatch with 
+     *      the firmware 
+     */
+} __ATTRIB_PACK__ AdHoc_BssDesc_t;
+
+/** HostCmd_DS_802_11_AD_HOC_JOIN */
+typedef struct _HostCmd_DS_802_11_AD_HOC_JOIN
+{
+    AdHoc_BssDesc_t BssDescriptor;
+    u16 Reserved1;
+    u16 Reserved2;
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_JOIN;
+
+typedef union _KeyInfo_WEP_t
+{
+    u8 Reserved;
+
+    /* bits 1-4: Specifies the index of key */
+    u8 WepKeyIndex;
+
+    /* bit 0: Specifies that this key is 
+     * to be used as the default for TX data packets 
+     * */
+    u8 isWepDefaultKey;
+} __ATTRIB_PACK__ KeyInfo_WEP_t;
+
+typedef union _KeyInfo_TKIP_t
+{
+    u8 Reserved;
+
+    /* bit 2: Specifies that this key is 
+     * enabled and valid to use */
+    u8 isKeyEnabled;
+
+    /* bit 1: Specifies that this key is
+     * to be used as the unicast key */
+    u8 isUnicastKey;
+
+    /* bit 0: Specifies that this key is 
+     * to be used as the multicast key */
+    u8 isMulticastKey;
+} __ATTRIB_PACK__ KeyInfo_TKIP_t;
+
+typedef union _KeyInfo_AES_t
+{
+    u8 Reserved;
+
+    /* bit 2: Specifies that this key is
+     * enabled and valid to use */
+    u8 isKeyEnabled;
+
+    /* bit 1: Specifies that this key is
+     * to be used as the unicast key */
+    u8 isUnicastKey;
+
+    /* bit 0: Specifies that this key is 
+     * to be used as the multicast key */
+    u8 isMulticastKey;
+} __ATTRIB_PACK__ KeyInfo_AES_t;
+
+/** KeyMaterial_TKIP_t */
+typedef struct _KeyMaterial_TKIP_t
+{
+    /* TKIP encryption/decryption key */
+    u8 TkipKey[16];
+
+    /* TKIP TX MIC Key */
+    u8 TkipTxMicKey[16];
+
+    /* TKIP RX MIC Key */
+    u8 TkipRxMicKey[16];
+} __ATTRIB_PACK__ KeyMaterial_TKIP_t, *PKeyMaterial_TKIP_t;
+
+/** KeyMaterial_AES_t */
+typedef struct _KeyMaterial_AES_t
+{
+    /* AES encryption/decryption key */
+    u8 AesKey[16];
+} __ATTRIB_PACK__ KeyMaterial_AES_t, *PKeyMaterial_AES_t;
+
+/** MrvlIEtype_KeyParamSet_t */
+typedef struct _MrvlIEtype_KeyParamSet_t
+{
+    /* Type ID */
+    u16 Type;
+
+    /* Length of Payload */
+    u16 Length;
+
+    /* Type of Key: WEP=0, TKIP=1, AES=2 */
+    u16 KeyTypeId;
+
+    /* Key Control Info specific to a KeyTypeId */
+    u16 KeyInfo;
+
+    /* Length of key */
+    u16 KeyLen;
+
+    /* Key material of size KeyLen */
+    u8 Key[32];
+} __ATTRIB_PACK__ MrvlIEtype_KeyParamSet_t, *PMrvlIEtype_KeyParamSet_t;
+
+/** HostCmd_DS_802_11_KEY_MATERIAL */
+typedef struct _HostCmd_DS_802_11_KEY_MATERIAL
+{
+    u16 Action;
+
+    MrvlIEtype_KeyParamSet_t KeyParamSet;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_KEY_MATERIAL;
+
+/** HostCmd_DS_802_11_HOST_SLEEP_CFG */
+typedef struct _HostCmd_DS_HOST_802_11_HOST_SLEEP_CFG
+{
+    /* bit0=1: non-unicast data
+     * bit1=1: unicast data
+     * bit2=1: mac events
+     * bit3=1: magic packet 
+     */
+    u32 conditions;
+
+    u8 gpio;
+
+    /* in milliseconds */
+    u8 gap;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_HOST_SLEEP_CFG;
+
+#define CAL_DATA_HEADER_LEN	6       /* sizeof(HostCmd_DS_802_11_CAL_DATA_EXT)-sizeof(CalData) */
+
+/** HostCmd_DS_802_11_CAL_DATA_EXT */
+typedef struct _HostCmd_DS_802_11_CAL_DATA_EXT
+{
+    u16 Action;
+    u16 Revision;
+    u16 CalDataLen;
+    u8 CalData[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CAL_DATA_EXT;
+
+/** HostCmd_DS_802_11_EEPROM_ACCESS */
+typedef struct _HostCmd_DS_802_11_EEPROM_ACCESS
+{
+    u16 Action;
+
+    /* multiple 4 */
+    u16 Offset;
+    u16 ByteCount;
+    u8 Value;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_EEPROM_ACCESS;
+
+/** HostCmd_DS_802_11_BG_SCAN_CONFIG */
+typedef struct _HostCmd_DS_802_11_BG_SCAN_CONFIG
+{
+    /** Action */
+    u16 Action;
+
+    /** 
+     *  Enable/Disable
+     *  0 - Disable
+     *  1 - Enable 
+     */
+    u8 Enable;
+
+    /**
+     *  bssType
+     *  1 - Infrastructure
+     *  2 - IBSS
+     *  3 - any 
+     */
+    u8 BssType;
+
+    /** 
+     * ChannelsPerScan 
+     *   Number of channels to scan during a single scanning opportunity
+     */
+    u8 ChannelsPerScan;
+
+    u8 Reserved1[3];
+
+    /** ScanInterval */
+    u32 ScanInterval;
+
+    /**
+     * StoreCondition
+     * - SSID Match
+     * - SSID Match & Exceed SNR Threshold 
+     */
+    u32 StoreCondition;
+
+    /** 
+     * ReportConditions
+     * - SSID Match
+     * - SSID Match & Exceed SNR Threshold
+     */
+    u32 ReportConditions;
+
+    u16 Reserved2;
+
+    /*  Attach TLV based parameters as needed:
+     *
+     *  MrvlIEtypes_SsIdParamSet_t          Set specific SSID filter
+     *  MrvlIEtypes_ChanListParamSet_t      Set the channels & channel params
+     *  MrvlIEtypes_NumProbes_t             Number of probes per SSID/broadcast
+     *  MrvlIEtypes_WildCardSsIdParamSet_t  Wildcard SSID matching patterns
+     *  MrvlIEtypes_SnrThreshold_t          SNR Threshold for match/report  
+     */
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_CONFIG;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY */
+typedef struct _HostCmd_DS_802_11_BG_SCAN_QUERY
+{
+    u8 Flush;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_QUERY;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
+typedef struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
+{
+    u32 ReportCondition;
+    HostCmd_DS_802_11_SCAN_RSP scanresp;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+
+/** HostCmd_DS_802_11_TPC_CFG */
+typedef struct _HostCmd_DS_802_11_TPC_CFG
+{
+    u16 Action;
+    u8 Enable;
+    s8 P0;
+    s8 P1;
+    s8 P2;
+    u8 UseSNR;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_TPC_CFG;
+
+/** HostCmd_DS_802_11_LED_CTRL */
+typedef struct _HostCmd_DS_802_11_LED_CTRL
+{
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    u16 LedNums;                /* Numbers of LEDs supported */
+    MrvlIEtypes_LedGpio_t LedGpio;
+    MrvlIEtypes_LedBehavior_t LedBehavior[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_LED_CTRL;
+
+/** HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT */
+typedef struct _HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT
+{
+        /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    u16 EnablePA;               /* 0 = disable; 1 = enable; */
+    MrvlIEtypes_PowerAdapt_Group_t PowerAdaptGroup;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT;
+
+typedef struct _HostCmd_DS_SDIO_PULL_CTRL
+{
+    u16 Action;                 /* 0: get; 1: set */
+    u16 PullUp;                 /* the delay of pulling up in us */
+    u16 PullDown;               /* the delay of pulling down in us */
+} __ATTRIB_PACK__ HostCmd_DS_SDIO_PULL_CTRL;
+typedef struct _HostCmd_DS_802_11_IBSS_Status
+{
+    u16 Action;
+    u16 Enable;
+    u8 BSSID[ETH_ALEN];
+    u16 BeaconInterval;
+    u16 ATIMWindow;
+    u16 UseGRateProtection;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_IBSS_Status;
+
+typedef struct _HostCmd_TX_RATE_QUERY
+{
+    u16 TxRate;
+} __ATTRIB_PACK__ HostCmd_TX_RATE_QUERY;
+
+/** HostCmd_DS_802_11_AUTO_TX */
+typedef struct _HostCmd_DS_802_11_AUTO_TX
+{
+        /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    MrvlIEtypes_AutoTx_t AutoTx;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTO_TX;
+
+/** HostCmd_MEM_ACCESS */
+typedef struct _HostCmd_DS_MEM_ACCESS
+{
+        /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    u16 Reserved;
+    u32 Addr;
+    u32 Value;
+} __ATTRIB_PACK__ HostCmd_DS_MEM_ACCESS;
+
+typedef struct
+{
+    u64 TsfValue;
+} __ATTRIB_PACK__ HostCmd_DS_GET_TSF;
+
+#define	LDO_INTERNAL	0
+#define LDO_EXTERNAL	1
+
+typedef struct _HostCmd_DS_802_11_LDO_CONFIG
+{
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    u16 PMSource;               /* 0 = LDO_INTERNAL; 1 = LDO_EXTERNAL */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_LDO_CONFIG;
+
+typedef struct _HostCmd_DS_VERSION_EXT
+{
+    u8 versionStrSel;
+    char versionStr[128];
+} __ATTRIB_PACK__ HostCmd_DS_VERSION_EXT;
+
+/** Define data structure for HostCmd_CMD_802_11D_DOMAIN_INFO */
+typedef struct _HostCmd_DS_802_11D_DOMAIN_INFO
+{
+    u16 Action;
+    MrvlIEtypes_DomainParamSet_t Domain;
+} __ATTRIB_PACK__ HostCmd_DS_802_11D_DOMAIN_INFO;
+
+/** Define data structure for HostCmd_RET_802_11D_DOMAIN_INFO */
+typedef struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+{
+    u16 Action;
+    MrvlIEtypes_DomainParamSet_t Domain;
+} __ATTRIB_PACK__ HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
+
+typedef struct
+{
+    u32 PktInitCnt;
+    u32 PktSuccessCnt;
+    u32 TxAttempts;
+    u32 RetryFailure;
+    u32 ExpiryFailure;
+} __ATTRIB_PACK__ HostCmd_DS_TX_PKT_STAT_Entry;
+
+typedef struct
+{
+    HostCmd_DS_TX_PKT_STAT_Entry StatEntry[HOSTCMD_SUPPORTED_RATES];
+} __ATTRIB_PACK__ HostCmd_DS_TX_PKT_STATS;
+
+/** _HostCmd_DS_COMMAND*/
+struct _HostCmd_DS_COMMAND
+{
+
+    /** Command Header */
+    u16 Command;
+    u16 Size;
+    u16 SeqNum;
+    u16 Result;
+
+    /** Command Body */
+    union
+    {
+        HostCmd_DS_GET_HW_SPEC hwspec;
+        HostCmd_DS_802_11_PS_MODE psmode;
+        HostCmd_DS_802_11_SCAN scan;
+        HostCmd_DS_802_11_SCAN_RSP scanresp;
+        HostCmd_DS_MAC_CONTROL macctrl;
+        HostCmd_DS_802_11_ASSOCIATE associate;
+        HostCmd_DS_802_11_ASSOCIATE_RSP associatersp;
+        HostCmd_DS_802_11_DEAUTHENTICATE deauth;
+        HostCmd_DS_802_11_SET_WEP wep;
+        HostCmd_DS_802_11_AD_HOC_START ads;
+        HostCmd_DS_802_11_AD_HOC_RESULT result;
+        HostCmd_DS_802_11_GET_LOG glog;
+        HostCmd_DS_802_11_SNMP_MIB smib;
+        HostCmd_DS_802_11_RF_TX_POWER txp;
+        HostCmd_DS_802_11_RF_ANTENNA rant;
+        HostCmd_DS_802_11_RATE_ADAPT_RATESET rateset;
+        HostCmd_DS_MAC_MULTICAST_ADR madr;
+        HostCmd_DS_802_11_AD_HOC_JOIN adj;
+        HostCmd_DS_802_11_RADIO_CONTROL radio;
+        HostCmd_DS_802_11_RF_CHANNEL rfchannel;
+        HostCmd_DS_802_11_RSSI rssi;
+        HostCmd_DS_802_11_RSSI_RSP rssirsp;
+        HostCmd_DS_802_11_AD_HOC_STOP adhoc_stop;
+        HostCmd_DS_802_11_MAC_ADDRESS macadd;
+        HostCmd_DS_802_11_KEY_MATERIAL keymaterial;
+        HostCmd_DS_MAC_REG_ACCESS macreg;
+        HostCmd_DS_BBP_REG_ACCESS bbpreg;
+        HostCmd_DS_RF_REG_ACCESS rfreg;
+        HostCmd_DS_802_11_CAL_DATA_EXT caldataext;
+        HostCmd_DS_802_11_HOST_SLEEP_CFG hostsleepcfg;
+        HostCmd_DS_802_11_EEPROM_ACCESS rdeeprom;
+
+        HostCmd_DS_802_11D_DOMAIN_INFO domaininfo;
+        HostCmd_DS_802_11D_DOMAIN_INFO_RSP domaininforesp;
+        HostCmd_DS_802_11_BG_SCAN_CONFIG bgscancfg;
+        HostCmd_DS_802_11_BG_SCAN_QUERY bgscanquery;
+        HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bgscanqueryresp;
+        HostCmd_DS_WMM_GET_STATUS getWmmStatus;
+        HostCmd_DS_WMM_ADDTS_REQ addTsReq;
+        HostCmd_DS_WMM_DELTS_REQ delTsReq;
+        HostCmd_DS_WMM_QUEUE_CONFIG queueConfig;
+        HostCmd_DS_WMM_QUEUE_STATS queueStats;
+        HostCmd_DS_TX_PKT_STATS txPktStats;
+        HostCmd_DS_802_11_SLEEP_PARAMS sleep_params;
+        HostCmd_DS_802_11_BCA_TIMESHARE bca_timeshare;
+        HostCmd_DS_802_11_INACTIVITY_TIMEOUT inactivity_timeout;
+        HostCmd_DS_802_11_SLEEP_PERIOD ps_sleeppd;
+        HostCmd_DS_802_11_TPC_CFG tpccfg;
+        HostCmd_DS_802_11_LED_CTRL ledgpio;
+        HostCmd_DS_802_11_FW_WAKEUP_METHOD fwwakeupmethod;
+
+        HostCmd_TX_RATE_QUERY txrate;
+        HostCmd_DS_GET_TSF gettsf;
+        HostCmd_DS_802_11_IBSS_Status ibssCoalescing;
+        HostCmd_DS_SDIO_PULL_CTRL sdiopullctl;
+        HostCmd_DS_802_11_LDO_CONFIG ldocfg;
+        HostCmd_DS_VERSION_EXT verext;
+    } params;
+} __ATTRIB_PACK__;
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/host.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/host.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/host.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/host.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,354 @@
+/** @file host.h
+ * 
+ * @brief This file contains definitions of WLAN commands.
+ *  
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+    10/11/05: Add Doxygen format comments
+    01/11/06: Remove assoc response codes; full IEEE assoc resp now returned
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+    04/10/06: Add power_adapt_cfg_ext command
+    04/18/06: Remove old Subscrive Event and add new Subscribe Event
+              implementation through generic hostcmd API
+    05/03/06: Add auto_tx hostcmd
+    05/04/06: Add IBSS coalescing related new hostcmd and event
+    08/28/06: Add LED_CTRL hostcmd
+********************************************************/
+
+#ifndef _HOST_H_
+#define _HOST_H_
+
+/** PUBLIC DEFINITIONS */
+#define DEFAULT_AD_HOC_CHANNEL       6
+#define DEFAULT_AD_HOC_CHANNEL_A    36
+
+/** IEEE 802.11 OIDs */
+#define OID_802_11_INFRASTRUCTURE_MODE        0x00008001
+#define OID_802_11_FRAGMENTATION_THRESHOLD    0x00008002
+#define OID_802_11_RTS_THRESHOLD              0x00008003
+#define OID_802_11_ADD_WEP                    0x00008004
+#define OID_802_11_REMOVE_WEP                 0x00008005
+#define OID_802_11_TX_RETRYCOUNT              0x00008006
+#define OID_802_11D_ENABLE                    0x00008007
+
+#define HostCmd_OPTION_WAITFORRSP             0x0002
+
+/** Host Command ID */
+#define HostCmd_CMD_GET_HW_SPEC               0x0003
+#define HostCmd_CMD_802_11_RESET              0x0005
+#define HostCmd_CMD_802_11_SCAN               0x0006
+#define HostCmd_CMD_802_11_GET_LOG            0x000b
+#define HostCmd_CMD_MAC_MULTICAST_ADR         0x0010
+#define HostCmd_CMD_802_11_EEPROM_ACCESS      0x0059
+#define HostCmd_CMD_802_11_ASSOCIATE          0x0012
+#define HostCmd_CMD_802_11_SET_WEP            0x0013
+#define HostCmd_CMD_802_11_SNMP_MIB           0x0016
+#define HostCmd_CMD_MAC_REG_ACCESS            0x0019
+#define HostCmd_CMD_BBP_REG_ACCESS            0x001a
+#define HostCmd_CMD_RF_REG_ACCESS             0x001b
+#define HostCmd_CMD_802_11_RADIO_CONTROL      0x001c
+#define HostCmd_CMD_802_11_RF_CHANNEL         0x001d
+#define HostCmd_CMD_802_11_RF_TX_POWER        0x001e
+#define HostCmd_CMD_802_11_RSSI               0x001f
+#define HostCmd_CMD_802_11_RF_ANTENNA         0x0020
+
+#define HostCmd_CMD_802_11_PS_MODE	      0x0021
+
+#define HostCmd_CMD_802_11_DEAUTHENTICATE     0x0024
+#define HostCmd_CMD_MAC_CONTROL               0x0028
+#define HostCmd_CMD_802_11_AD_HOC_START       0x002b
+#define HostCmd_CMD_802_11_AD_HOC_JOIN        0x002c
+
+#define HostCmd_CMD_802_11_KEY_MATERIAL       0x005e
+
+#define HostCmd_CMD_802_11_DEEP_SLEEP         0x003e
+
+#define HostCmd_CMD_802_11_AD_HOC_STOP        0x0040
+
+#define HostCmd_CMD_802_11_HOST_SLEEP_CFG     0x0043
+#define HostCmd_CMD_802_11_WAKEUP_CONFIRM     0x0044
+#define HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE	0x0045
+
+#define HostCmd_CMD_802_11_MAC_ADDRESS        0x004D
+#define HostCmd_CMD_802_11_EEPROM_ACCESS      0x0059
+
+#define HostCmd_CMD_802_11_BAND_CONFIG        0x0058
+
+#define HostCmd_CMD_802_11D_DOMAIN_INFO       0x005b
+
+#define HostCmd_CMD_802_11_SLEEP_PARAMS          0x0066
+
+#define HostCmd_CMD_802_11_INACTIVITY_TIMEOUT    0x0067
+
+#define HostCmd_CMD_802_11_SLEEP_PERIOD          0x0068
+#define HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE  0x0069
+
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG        0x006b
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY         0x006c
+
+#define HostCmd_CMD_802_11_CAL_DATA_EXT          0x006d
+
+#define HostCmd_CMD_WMM_ADDTS_REQ                0x006E
+#define HostCmd_CMD_WMM_DELTS_REQ                0x006F
+#define HostCmd_CMD_WMM_QUEUE_CONFIG             0x0070
+#define HostCmd_CMD_WMM_GET_STATUS               0x0071
+
+#define HostCmd_CMD_802_11_TPC_CFG               0x0072
+
+#define HostCmd_CMD_802_11_FW_WAKE_METHOD        0x0074
+
+#define HostCmd_CMD_802_11_LED_CONTROL           0x004e
+
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT       0x0075
+
+#define HostCmd_CMD_802_11_RATE_ADAPT_RATESET    0x0076
+
+#define HostCmd_CMD_802_11_TX_RATE_QUERY	0x007f
+
+#define HostCmd_CMD_802_11_POWER_ADAPT_CFG_EXT	0x007e
+
+#define HostCmd_CMD_GET_TSF                      0x0080
+
+#define HostCmd_CMD_WMM_QUEUE_STATS              0x0081
+
+#define HostCmd_CMD_802_11_AUTO_TX		0x0082
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+
+#define HostCmd_CMD_MEM_ACCESS			0x0086
+
+#ifdef MFG_CMD_SUPPORT
+#define HostCmd_CMD_MFG_COMMAND               0x0089
+#define HostCmd_RET_MFG_COMMAND               0x8089
+#endif
+
+#define HostCmd_CMD_TX_PKT_STATS              0x008d
+
+#define HostCmd_CMD_SDIO_PULL_CTRL		      0x0093
+
+#define HostCmd_CMD_802_11_LDO_CONFIG         0x0096
+
+#define HostCmd_CMD_VERSION_EXT               0x0097
+
+/* For the IEEE Power Save */
+#define HostCmd_SubCmd_Enter_PS               0x0030
+#define HostCmd_SubCmd_Exit_PS                0x0031
+#define HostCmd_SubCmd_Sleep_Confirmed        0x0034
+#define HostCmd_SubCmd_Full_PowerDown         0x0035
+#define HostCmd_SubCmd_Full_PowerUp           0x0036
+
+/* Command RET code, MSB is set to 1 */
+#define HostCmd_RET_HW_SPEC_INFO              0x8003
+#define HostCmd_RET_802_11_RESET              0x8005
+#define HostCmd_RET_802_11_SCAN               0x8006
+#define HostCmd_RET_802_11_GET_LOG            0x800b
+#define HostCmd_RET_MAC_CONTROL               0x8028
+#define HostCmd_RET_MAC_MULTICAST_ADR         0x8010
+#define HostCmd_RET_802_11_DEAUTHENTICATE     0x8024
+#define HostCmd_RET_802_11_ASSOCIATE          0x8012
+#define HostCmd_RET_802_11_SET_WEP            0x8013
+#define HostCmd_RET_802_3_STAT                0x8015
+#define HostCmd_RET_802_11_SNMP_MIB           0x8016
+#define HostCmd_RET_MAC_REG_ACCESS            0x8019
+#define HostCmd_RET_BBP_REG_ACCESS            0x801a
+#define HostCmd_RET_RF_REG_ACCESS             0x801b
+#define HostCmd_RET_802_11_RADIO_CONTROL      0x801c
+#define HostCmd_RET_802_11_RF_CHANNEL         0x801d
+#define HostCmd_RET_802_11_RSSI               0x801f
+#define HostCmd_RET_802_11_RF_TX_POWER        0x801e
+#define HostCmd_RET_802_11_RF_ANTENNA         0x8020
+#define HostCmd_RET_802_11_PS_MODE            0x8021
+
+#define HostCmd_RET_802_11_AD_HOC_START       0x802B
+#define HostCmd_RET_802_11_AD_HOC_JOIN        0x802C
+
+#define HostCmd_RET_802_11_KEY_MATERIAL       0x805e
+
+#define HostCmd_ACT_SET                       0x0001
+#define HostCmd_ACT_GET                       0x0000
+
+#define HostCmd_RET_802_11_AD_HOC_STOP        0x8040
+
+#define HostCmd_RET_802_11_HOST_SLEEP_CFG     0x8043
+#define HostCmd_RET_802_11_WAKEUP_CONFIRM     0x8044
+#define HostCmd_RET_802_11_HOST_SLEEP_ACTIVATE	0x8045
+
+#define HostCmd_RET_802_11_MAC_ADDRESS        0x804D
+#define HostCmd_RET_802_11_EEPROM_ACCESS      0x8059
+
+#define HostCmd_RET_802_11_BAND_CONFIG        0x8058
+
+#define HostCmd_RET_802_11_SLEEP_PARAMS          0x8066
+
+#define HostCmd_RET_802_11_INACTIVITY_TIMEOUT    0x8067
+
+#define HostCmd_RET_802_11_SLEEP_PERIOD          0x8068
+#define HostCmd_RET_802_11_BCA_CONFIG_TIMESHARE  0x8069
+
+#define HostCmd_RET_802_11D_DOMAIN_INFO          0x805B
+
+#define HostCmd_RET_802_11_BG_SCAN_CONFIG    0x806b
+#define HostCmd_RET_802_11_BG_SCAN_QUERY     0x806c
+
+#define HostCmd_RET_802_11_CAL_DATA_EXT      0x806d
+
+#define HostCmd_RET_WMM_ADDTS_REQ            0x806E
+#define HostCmd_RET_WMM_DELTS_REQ            0x806F
+#define HostCmd_RET_WMM_QUEUE_CONFIG         0x8070
+#define HostCmd_RET_WMM_GET_STATUS           0x8071
+
+#define HostCmd_RET_802_11_TPC_CFG           0x8072
+
+#define HostCmd_RET_802_11_LED_CONTROL       0x804e
+
+#define HostCmd_RET_802_11_FW_WAKE_METHOD    0x8074
+
+#define HostCmd_RET_802_11_SUBSCRIBE_EVENT   0x8075
+
+#define HostCmd_RET_802_11_RATE_ADAPT_RATESET	0x8076
+
+#define HostCmd_RTE_802_11_TX_RATE_QUERY 	0x807f
+
+#define HostCmd_RET_GET_TSF             	0x8080
+
+#define HostCmd_RET_WMM_QUEUE_STATS     	0x8081
+
+#define HostCmd_RET_802_11_POWER_ADAPT_CFG_EXT	0x807e
+
+#define HostCmd_RET_802_11_AUTO_TX		0x8082
+
+#define HostCmd_RET_802_11_IBSS_COALESCING_STATUS	0x8083
+
+#define HostCmd_RET_MEM_ACCESS		      0x8086
+
+#define HostCmd_RET_TX_PKT_STATS              0x808d
+
+#define HostCmd_RET_SDIO_PULL_CTRL		0x8093
+
+#define HostCmd_RET_802_11_LDO_CONFIG         0x8096
+
+#define HostCmd_RET_VERSION_EXT               0x8097
+
+/** General Result Code*/
+/* OK */
+#define HostCmd_RESULT_OK                    0x0000
+/* Genenral error */
+#define HostCmd_RESULT_ERROR                 0x0001
+/* Command is not valid */
+#define HostCmd_RESULT_NOT_SUPPORT           0x0002
+/* Command is pending */
+#define HostCmd_RESULT_PENDING               0x0003
+/* System is busy (command ignored) */
+#define HostCmd_RESULT_BUSY                  0x0004
+/* Data buffer is not big enough */
+#define HostCmd_RESULT_PARTIAL_DATA          0x0005
+
+/* Definition of action or option for each command */
+
+/* Define general purpose action */
+#define HostCmd_ACT_GEN_READ                    0x0000
+#define HostCmd_ACT_GEN_WRITE                   0x0001
+#define HostCmd_ACT_GEN_GET                     0x0000
+#define HostCmd_ACT_GEN_SET                     0x0001
+#define HostCmd_ACT_GEN_REMOVE                  0x0002
+#define HostCmd_ACT_GEN_OFF                     0x0000
+#define HostCmd_ACT_GEN_ON                      0x0001
+
+/* Define action or option for HostCmd_CMD_802_11_SET_WEP */
+#define HostCmd_ACT_ADD                         0x0002
+#define HostCmd_ACT_REMOVE                      0x0004
+
+#define HostCmd_TYPE_WEP_40_BIT                 0x0001
+#define HostCmd_TYPE_WEP_104_BIT                0x0002
+
+#define HostCmd_WEP_KEY_INDEX_MASK              0x3fff
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+#define HostCmd_BSS_TYPE_BSS                    0x0001
+#define HostCmd_BSS_TYPE_IBSS                   0x0002
+#define HostCmd_BSS_TYPE_ANY                    0x0003
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+#define HostCmd_SCAN_TYPE_ACTIVE                0x0000
+#define HostCmd_SCAN_TYPE_PASSIVE               0x0001
+
+/* Radio type definitions for the channel TLV */
+#define HostCmd_SCAN_RADIO_TYPE_BG		0
+#define HostCmd_SCAN_RADIO_TYPE_A		1
+
+/* Define action or option for HostCmd_CMD_MAC_CONTROL */
+#define HostCmd_ACT_MAC_RX_ON                   0x0001
+#define HostCmd_ACT_MAC_TX_ON                   0x0002
+#define HostCmd_ACT_MAC_LOOPBACK_ON             0x0004
+#define HostCmd_ACT_MAC_WEP_ENABLE              0x0008
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE       0x0010
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE      0x0080
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE    0x0100
+#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE  0x0400
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON	  0x2000
+
+/* Define action or option or constant for HostCmd_CMD_MAC_MULTICAST_ADR */
+#define HostCmd_SIZE_MAC_ADR                    6
+#define HostCmd_MAX_MCAST_ADRS                  32
+
+#define RADIO_ON                                0x01
+#define RADIO_OFF                               0x00
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define HostCmd_OPT_802_11_RF_CHANNEL_GET       0x00
+#define HostCmd_OPT_802_11_RF_CHANNEL_SET       0x01
+
+#define HostCmd_ACT_SET_RX                      0x0001
+#define HostCmd_ACT_SET_TX                      0x0002
+#define HostCmd_ACT_SET_BOTH                    0x0003
+#define HostCmd_ACT_GET_RX                      0x0004
+#define HostCmd_ACT_GET_TX                      0x0008
+#define HostCmd_ACT_GET_BOTH                    0x000c
+
+/** Card Event definition */
+#define MACREG_INT_CODE_DUMMY_HOST_WAKEUP_SIGNAL       0x00000001
+#define MACREG_INT_CODE_LINK_LOST_WITH_SCAN     0x00000002
+#define MACREG_INT_CODE_LINK_LOST       	0x00000003
+#define MACREG_INT_CODE_LINK_SENSED             0x00000004
+#define MACREG_INT_CODE_MIB_CHANGED             0x00000006
+#define MACREG_INT_CODE_INIT_DONE               0x00000007
+#define MACREG_INT_CODE_DEAUTHENTICATED         0x00000008
+#define MACREG_INT_CODE_DISASSOCIATED           0x00000009
+#define MACREG_INT_CODE_PS_AWAKE                0x0000000a
+#define MACREG_INT_CODE_PS_SLEEP                0x0000000b
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST       0x0000000d
+#define MACREG_INT_CODE_MIC_ERR_UNICAST         0x0000000e
+#define MACREG_INT_CODE_WM_AWAKE                0x0000000f
+#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE        0x00000010
+#define MACREG_INT_CODE_ADHOC_BCN_LOST          0x00000011
+#define MACREG_INT_CODE_HOST_SLEEP_AWAKE        0x00000012
+#define MACREG_INT_CODE_WMM_STATUS_CHANGE	0x00000017
+#define MACREG_INT_CODE_BG_SCAN_REPORT		0x00000018
+#define MACREG_INT_CODE_RSSI_LOW		0x00000019
+#define MACREG_INT_CODE_SNR_LOW			0x0000001a
+#define MACREG_INT_CODE_MAX_FAIL		0x0000001b
+#define MACREG_INT_CODE_RSSI_HIGH		0x0000001c
+#define MACREG_INT_CODE_SNR_HIGH		0x0000001d
+#define MACREG_INT_CODE_IBSS_COALESCED		0x0000001e
+
+/* Define bitmap conditions for HOST_SLEEP_CFG */
+#define HOST_SLEEP_CFG_CANCEL			0xffffffff
+#define HOST_SLEEP_CFG_WAKEUP_THRU_INTERFACE	0xff
+#define HOST_SLEEP_CFG_GAP_FF			0xff
+
+#endif /* _HOST_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/include.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/include.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/include.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/include.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,57 @@
+/** @file include.h
+ * 
+ * @brief This file contains all the necessary include file.
+ *
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	10/11/05: Add Doxygen format comments
+	01/11/06: Conditional include file removal/addition
+	01/30/06: Add kernel 2.6 support
+	
+********************************************************/
+
+#ifndef _INCLUDE_H_
+#define _INCLUDE_H_
+
+#include    "os_headers.h"
+#include    "wlan_types.h"
+#include    "wlan_defs.h"
+#include    "wlan_thread.h"
+
+#include    "wlan_wmm.h"
+#include    "wlan_11d.h"
+
+#include    "os_timers.h"
+
+#include    "host.h"
+#include    "hostcmd.h"
+
+#include    "wlan_scan.h"
+#include    "wlan_join.h"
+
+#include    "wlan_dev.h"
+#include    "os_macros.h"
+#include    "sbi.h"
+
+/* masked by feng */
+//#include    <sdio.h>
+
+#include    "wlan_wext.h"
+#include    "wlan_decl.h"
+#endif /* _INCLUDE_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/sbi.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/sbi.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/sbi.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/sbi.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,128 @@
+/** @file sbi.h
+ * 
+ * @brief This file contains IF layer definitions.
+ *
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	10/11/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	
+********************************************************/
+
+#ifndef	_SBI_H_
+#define	_SBI_H_
+
+/**Bit Definition*/
+#define B_BIT_0		0x01
+#define B_BIT_1		0x02
+#define B_BIT_2		0x04
+#define B_BIT_3		0x08
+#define B_BIT_4		0x10
+#define B_BIT_5		0x20
+#define B_BIT_6		0x40
+#define B_BIT_7		0x80
+#define B_BIT_8		0x100
+#define B_BIT_9		0X200
+#define B_BIT_10	0x400
+
+/** INT Status Bit Definition*/
+#define HIS_RxUpLdRdy			B_BIT_0
+#define HIS_TxDnLdRdy			B_BIT_1
+#define HIS_CmdDnLdRdy			B_BIT_2
+#define HIS_CardEvent			B_BIT_3
+#define HIS_CmdUpLdRdy			B_BIT_4
+#define HIS_WrFifoOvrflow		B_BIT_5
+#define HIS_RdFifoUndrflow		B_BIT_6
+#define HIS_WlanReady			B_BIT_7
+
+#define	HIM_DISABLE			0xff
+#define HIM_ENABLE			0x03
+
+#define FIRMWARE_READY			0xfedc
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN			32
+#endif
+#define MAXKEYLEN			13
+
+/* The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES			100
+
+/* The number of times to try when waiting for downloaded firmware to 
+     become active. (polling the scratch register). */
+
+#define MAX_FIRMWARE_POLL_TRIES		100
+
+#define FIRMWARE_TRANSFER_NBLOCK	2
+#define SBI_EVENT_CAUSE_SHIFT		3
+
+typedef enum _mv_sd_type
+{
+    MVSD_DAT = 0,
+    MVSD_CMD = 1,
+    MVSD_EVENT = 3
+} mv_sd_type;
+
+/** Function Prototype Declaration */
+typedef wlan_private *(*wlan_notifier_fn_add) (void *dev_id);
+typedef int (*wlan_notifier_fn_remove) (void *dev_id);
+
+typedef IRQ_RET_TYPE(*isr_notifier_fn_t) (s32 irq, void *dev_id,
+                                          struct pt_regs * reg);
+typedef IRQ_RET_TYPE(*handler_fn_t) (s32 irq, void *dev_id, struct pt_regs *);
+
+/* Probe and Check if the card is present*/
+int sbi_probe_card(void *card);
+int *sbi_register(wlan_notifier_fn_add, wlan_notifier_fn_remove, void *);
+int sbi_register_dev(wlan_private * priv);
+int sbi_unregister_dev(wlan_private *);
+int sbi_disable_host_int(wlan_private * priv);
+int sbi_get_int_status(wlan_private * priv, u8 *);
+void sbi_unregister(void);
+int sbi_prog_firmware(wlan_private *);
+int sbi_verify_fw_download(wlan_private *);
+
+int sbi_prog_helper(wlan_private *);
+int sbi_prog_firmware_w_helper(wlan_private *);
+
+int sbi_read_event_cause(wlan_private *);
+int sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+int sbi_card_to_host(wlan_private * priv, u32 type, u32 * nb, u8 * payload,
+                     u16 npayload);
+int sbi_enable_host_int(wlan_private *);
+
+int sbi_exit_deep_sleep(wlan_private *);
+int sbi_reset_deepsleep_wakeup(wlan_private *);
+#ifdef ENABLE_PM
+int sbi_suspend(wlan_private *);
+int sbi_resume(wlan_private *);
+#endif
+
+//int sbi_read_ioreg(wlan_private * priv, u8 func, u32 reg, u8 * dat);
+int sbi_read_ioreg(wlan_private *priv, u32 reg, u8 * dat);
+//int sbi_write_ioreg(wlan_private *priv, u8 func, u32 reg, u8 dat);
+int sbi_write_ioreg(wlan_private *priv, u32 reg, u8 dat);
+int sbi_set_bus_clock(wlan_private * priv, u8 option);
+
+int sbi_get_cis_info(wlan_private * priv);
+
+/* add by feng for thread debug */
+extern int threadrunning;
+
+
+#endif /* _SBI_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_11d.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_11d.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_11d.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_11d.c	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,896 @@
+/** @file wlan_11d.c
+  * @brief This file contains functions for 802.11D.
+  *
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	
+********************************************************/
+#include	"include.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+#define TX_PWR_DEFAULT	10
+
+static region_code_mapping_t region_code_mapping[] = {
+    {"US ", 0x10},              /* US FCC      */
+    {"CA ", 0x20},              /* IC Canada   */
+    {"SG ", 0x10},              /* Singapore   */
+    {"EU ", 0x30},              /* ETSI        */
+    {"AU ", 0x30},              /* Australia   */
+    {"KR ", 0x30},              /* Republic Of Korea */
+    {"ES ", 0x31},              /* Spain       */
+    {"FR ", 0x32},              /* France      */
+    {"JP ", 0x40},              /* Japan       */
+    {"JP ", 0x41},              /* Japan       */
+};
+
+/********************************************************
+		Global Variables
+********************************************************/
+/* Following 2 structure defines the supported channels */
+CHANNEL_FREQ_POWER channel_freq_power_UN_BG[] = {
+    {1, 2412, TX_PWR_DEFAULT},
+    {2, 2417, TX_PWR_DEFAULT},
+    {3, 2422, TX_PWR_DEFAULT},
+    {4, 2427, TX_PWR_DEFAULT},
+    {5, 2432, TX_PWR_DEFAULT},
+    {6, 2437, TX_PWR_DEFAULT},
+    {7, 2442, TX_PWR_DEFAULT},
+    {8, 2447, TX_PWR_DEFAULT},
+    {9, 2452, TX_PWR_DEFAULT},
+    {10, 2457, TX_PWR_DEFAULT},
+    {11, 2462, TX_PWR_DEFAULT},
+    {12, 2467, TX_PWR_DEFAULT},
+    {13, 2472, TX_PWR_DEFAULT},
+    {14, 2484, TX_PWR_DEFAULT}
+};
+
+CHANNEL_FREQ_POWER channel_freq_power_UN_AJ[] = {
+    {8, 5040, TX_PWR_DEFAULT},
+    {12, 5060, TX_PWR_DEFAULT},
+    {16, 5080, TX_PWR_DEFAULT},
+    {34, 5170, TX_PWR_DEFAULT},
+    {38, 5190, TX_PWR_DEFAULT},
+    {42, 5210, TX_PWR_DEFAULT},
+    {46, 5230, TX_PWR_DEFAULT},
+    {36, 5180, TX_PWR_DEFAULT},
+    {40, 5200, TX_PWR_DEFAULT},
+    {44, 5220, TX_PWR_DEFAULT},
+    {48, 5240, TX_PWR_DEFAULT},
+    {52, 5260, TX_PWR_DEFAULT},
+    {56, 5280, TX_PWR_DEFAULT},
+    {60, 5300, TX_PWR_DEFAULT},
+    {64, 5320, TX_PWR_DEFAULT},
+    {100, 5500, TX_PWR_DEFAULT},
+    {104, 5520, TX_PWR_DEFAULT},
+    {108, 5540, TX_PWR_DEFAULT},
+    {112, 5560, TX_PWR_DEFAULT},
+    {116, 5580, TX_PWR_DEFAULT},
+    {120, 5600, TX_PWR_DEFAULT},
+    {124, 5620, TX_PWR_DEFAULT},
+    {128, 5640, TX_PWR_DEFAULT},
+    {132, 5660, TX_PWR_DEFAULT},
+    {136, 5680, TX_PWR_DEFAULT},
+    {140, 5700, TX_PWR_DEFAULT},
+    {149, 5745, TX_PWR_DEFAULT},
+    {153, 5765, TX_PWR_DEFAULT},
+    {157, 5785, TX_PWR_DEFAULT},
+    {161, 5805, TX_PWR_DEFAULT},
+    {165, 5825, TX_PWR_DEFAULT},
+/*	{240, 4920, TX_PWR_DEFAULT}, 
+	{244, 4940, TX_PWR_DEFAULT}, 
+	{248, 4960, TX_PWR_DEFAULT}, 
+	{252, 4980, TX_PWR_DEFAULT}, 
+channels for 11J JP 10M channel gap */
+};
+
+extern CHANNEL_FREQ_POWER *wlan_get_region_cfp_table(u8 region,
+                                                     u8 band, int *cfp_no);
+
+/********************************************************
+		Local Functions
+********************************************************/
+/** 
+ *  @brief This function convert Region string to code integer
+ *  @param region     region string
+ *  @return 	      region id
+*/
+static u8
+wlan_region_2_code(s8 * region)
+{
+    u8 i;
+    u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+    for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
+        region[i] = toupper(region[i]);
+
+    for (i = 0; i < size; i++) {
+        if (!memcmp(region, region_code_mapping[i].region, COUNTRY_CODE_LEN))
+            return (region_code_mapping[i].code);
+    }
+
+    /* default is US */
+    return (region_code_mapping[0].code);
+}
+
+/** 
+ *  @brief This function converts interger code to region string
+ *  @param code       region code
+ *  @return 	      region string
+*/
+static u8 *
+wlan_code_2_region(u8 code)
+{
+    u8 i;
+    u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+    for (i = 0; i < size; i++) {
+        if (region_code_mapping[i].code == code)
+            return (region_code_mapping[i].region);
+    }
+    /* default is US */
+    return (region_code_mapping[0].region);
+}
+
+/** 
+ *  @brief This function finds the NoOfChan-th chan after the firstChan
+ *  @param band       band
+ *  @param firstChan  first channel number
+ *  @param NoOfChan   number of channels
+ *  @return 	      the NoOfChan-th chan number
+*/
+static BOOLEAN
+wlan_get_chan_11d(u8 band, u8 firstChan, u8 NoOfChan, u8 * chan)
+/*find the NoOfChan-th chan after the firstChan*/
+{
+    u8 i;
+    CHANNEL_FREQ_POWER *cfp;
+    u8 cfp_no;
+
+    ENTER();
+
+    {
+        cfp = channel_freq_power_UN_BG;
+        cfp_no = sizeof(channel_freq_power_UN_BG) /
+            sizeof(CHANNEL_FREQ_POWER);
+    }
+
+    for (i = 0; i < cfp_no; i++) {
+        if ((cfp + i)->Channel == firstChan) {
+            PRINTM(INFO, "firstChan found\n");
+            break;
+        }
+    }
+
+    if (i < cfp_no) {
+        /*if beyond the boundary */
+        if (i + NoOfChan < cfp_no) {
+            *chan = (cfp + i + NoOfChan)->Channel;
+            return TRUE;
+        }
+    }
+
+    LEAVE();
+    return FALSE;
+}
+
+/** 
+ *  @brief This function Checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t     
+ *  @return 	                TRUE; FALSE
+*/
+BOOLEAN
+wlan_channel_known_11d(u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+    chan_power_11d_t *chanPwr = parsed_region_chan->chanPwr;
+    u8 NoOfChan = parsed_region_chan->NoOfChan;
+    u8 i = 0;
+
+    ENTER();
+    HEXDUMP("11D:parsed_region_chan:", (char *) chanPwr,
+            sizeof(chan_power_11d_t) * NoOfChan);
+
+    for (i = 0; i < NoOfChan; i++) {
+        if (chan == chanPwr[i].chan) {
+            PRINTM(INFO, "11D: Found Chan:%d\n", chan);
+            LEAVE();
+            return TRUE;
+        }
+    }
+
+    PRINTM(INFO, "11D: Not Find Chan:%d\n", chan);
+    LEAVE();
+    return FALSE;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function Converts chan to frequency
+ *  @param chan                 channel number
+ *  @param band                 band
+ *  @return 	                channel frequency
+*/
+u32
+chan_2_freq(u8 chan, u8 band)
+{
+    CHANNEL_FREQ_POWER *cf;
+    u16 cnt;
+    u16 i;
+    u32 freq = 0;
+
+    ENTER();
+
+    {
+        cf = channel_freq_power_UN_BG;
+        cnt = sizeof(channel_freq_power_UN_BG) / sizeof(CHANNEL_FREQ_POWER);
+    }
+
+    for (i = 0; i < cnt; i++) {
+        if (chan == cf[i].Channel)
+            freq = cf[i].Freq;
+    }
+
+    LEAVE();
+    return freq;
+}
+
+/** 
+ *  @brief This function generates domaininfo from parsed_region_chan
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t
+ *  @param domaininfo           pointer to wlan_802_11d_domain_reg_t
+ *  @return 	                WLAN_STATUS_SUCCESS
+*/
+int
+wlan_generate_domain_info_11d(parsed_region_chan_11d_t * parsed_region_chan,
+                              wlan_802_11d_domain_reg_t * domaininfo)
+{
+    u8 NoOfSubband = 0;
+
+    u8 NoOfChan = parsed_region_chan->NoOfChan;
+    u8 NoOfParsedChan = 0;
+
+    u8 firstChan = 0, nextChan = 0, maxPwr = 0;
+
+    u8 i, flag = 0;
+
+    ENTER();
+
+    memcpy(domaininfo->CountryCode, parsed_region_chan->CountryCode,
+           COUNTRY_CODE_LEN);
+
+    PRINTM(INFO, "11D:NoOfChan=%d\n", NoOfChan);
+    HEXDUMP("11D:parsed_region_chan:", (char *) parsed_region_chan,
+            sizeof(parsed_region_chan_11d_t));
+
+    for (i = 0; i < NoOfChan; i++) {
+        if (!flag) {
+            flag = 1;
+            nextChan = firstChan = parsed_region_chan->chanPwr[i].chan;
+            maxPwr = parsed_region_chan->chanPwr[i].pwr;
+            NoOfParsedChan = 1;
+            continue;
+        }
+
+        if (parsed_region_chan->chanPwr[i].chan == nextChan + 1 &&
+            parsed_region_chan->chanPwr[i].pwr == maxPwr) {
+            nextChan++;
+            NoOfParsedChan++;
+        } else {
+            domaininfo->Subband[NoOfSubband].FirstChan = firstChan;
+            domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan;
+            domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr;
+            NoOfSubband++;
+            NoOfParsedChan = 1;
+            nextChan = firstChan = parsed_region_chan->chanPwr[i].chan;
+            maxPwr = parsed_region_chan->chanPwr[i].pwr;
+        }
+    }
+
+    if (flag) {
+        domaininfo->Subband[NoOfSubband].FirstChan = firstChan;
+        domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan;
+        domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr;
+        NoOfSubband++;
+    }
+    domaininfo->NoOfSubband = NoOfSubband;
+
+    PRINTM(INFO, "NoOfSubband=%x\n", domaininfo->NoOfSubband);
+    HEXDUMP("11D:domaininfo:", (char *) domaininfo,
+            COUNTRY_CODE_LEN + 1 +
+            sizeof(IEEEtypes_SubbandSet_t) * NoOfSubband);
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region_chan          pointer to REGION_CHANNEL
+ *  @param *parsed_region_chan  pointer to parsed_region_chan_11d_t
+ *  @return 	                N/A
+*/
+void
+wlan_generate_parsed_region_chan_11d(REGION_CHANNEL * region_chan,
+                                     parsed_region_chan_11d_t *
+                                     parsed_region_chan)
+{
+    u8 i;
+    CHANNEL_FREQ_POWER *cfp;
+
+    ENTER();
+
+    if (region_chan == NULL) {
+        PRINTM(INFO, "11D: region_chan is NULL\n");
+        return;
+    }
+
+    cfp = region_chan->CFP;
+    if (cfp == NULL) {
+        PRINTM(INFO, "11D: cfp equal NULL \n");
+        return;
+    }
+
+    parsed_region_chan->band = region_chan->Band;
+    parsed_region_chan->region = region_chan->Region;
+    memcpy(parsed_region_chan->CountryCode,
+           wlan_code_2_region(region_chan->Region), COUNTRY_CODE_LEN);
+
+    PRINTM(INFO, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+           parsed_region_chan->band);
+
+    for (i = 0; i < region_chan->NrCFP; i++, cfp++) {
+        parsed_region_chan->chanPwr[i].chan = cfp->Channel;
+        parsed_region_chan->chanPwr[i].pwr = cfp->MaxTxPower;
+        PRINTM(INFO, "11D: Chan[%d] Pwr[%d]\n",
+               parsed_region_chan->chanPwr[i].chan,
+               parsed_region_chan->chanPwr[i].pwr);
+    }
+    parsed_region_chan->NoOfChan = region_chan->NrCFP;
+
+    PRINTM(INFO, "11D: NoOfChan[%d]\n", parsed_region_chan->NoOfChan);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region               region ID
+ *  @param band                 band
+ *  @param chan                 chan
+ *  @return 	                TRUE;FALSE
+*/
+BOOLEAN
+wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+{
+    CHANNEL_FREQ_POWER *cfp;
+    int cfp_no;
+    u8 idx;
+
+    ENTER();
+
+    if ((cfp = wlan_get_region_cfp_table(region, band, &cfp_no)) == NULL) {
+        return FALSE;
+    }
+
+    for (idx = 0; idx < cfp_no; idx++) {
+        if (chan == (cfp + idx)->Channel) {
+            /* If Mrvl Chip Supported? */
+            if ((cfp + idx)->Unsupported) {
+                return FALSE;
+            } else {
+                return TRUE;
+            }
+        }
+    }
+
+    /*chan is not in the region table */
+    LEAVE();
+    return FALSE;
+}
+
+/** 
+ *  @brief This function checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t     
+ *  @return 	                WLAN_STATUS_SUCCESS       
+*/
+int
+wlan_parse_domain_info_11d(IEEEtypes_CountryInfoFullSet_t * CountryInfo,
+                           u8 band,
+                           parsed_region_chan_11d_t * parsed_region_chan)
+{
+    u8 NoOfSubband, NoOfChan;
+    u8 lastChan, firstChan, curChan;
+    u8 region;
+
+    u8 idx = 0;                 /*chan index in parsed_region_chan */
+
+    u8 j, i;
+
+    ENTER();
+
+    /*Validation Rules:
+       1. Valid Region Code
+       2. First Chan increment
+       3. Channel range no overlap
+       4. Channel is valid?
+       5. Channel is supported by Region?
+       6. Others
+     */
+
+    HEXDUMP("CountryInfo:", (s8 *) CountryInfo, 30);
+
+    if ((*(CountryInfo->CountryCode)) == 0 ||
+        (CountryInfo->Len <= COUNTRY_CODE_LEN)) {
+        /* No region Info or Wrong region info: treat as No 11D info */
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /*Step1: check region_code */
+    parsed_region_chan->region = region =
+        wlan_region_2_code((s8 *) CountryInfo->CountryCode);
+
+    PRINTM(INFO, "regioncode=%x\n", (u8) parsed_region_chan->region);
+    HEXDUMP("CountryCode:", (char *) CountryInfo->CountryCode,
+            COUNTRY_CODE_LEN);
+
+    parsed_region_chan->band = band;
+
+    memcpy(parsed_region_chan->CountryCode, CountryInfo->CountryCode,
+           COUNTRY_CODE_LEN);
+
+    NoOfSubband = (CountryInfo->Len - COUNTRY_CODE_LEN) /
+        sizeof(IEEEtypes_SubbandSet_t);
+
+    for (j = 0, lastChan = 0; j < NoOfSubband; j++) {
+
+        if (CountryInfo->Subband[j].FirstChan <= lastChan) {
+            /*Step2&3. Check First Chan Num increment and no overlap */
+            PRINTM(INFO, "11D: Chan[%d>%d] Overlap\n",
+                   CountryInfo->Subband[j].FirstChan, lastChan);
+            continue;
+        }
+
+        firstChan = CountryInfo->Subband[j].FirstChan;
+        NoOfChan = CountryInfo->Subband[j].NoOfChan;
+
+        for (i = 0; idx < MAX_NO_OF_CHAN && i < NoOfChan; i++) {
+            /*step4: channel is supported? */
+
+            if (wlan_get_chan_11d(band, firstChan, i, &curChan)
+                == FALSE) {
+                /* Chan is not found in UN table */
+                PRINTM(INFO, "chan is not supported: %d \n", i);
+                break;
+            }
+
+            lastChan = curChan;
+
+            /*step5: We don't need to Check if curChan is supported by mrvl in region */
+            parsed_region_chan->chanPwr[idx].chan = curChan;
+            parsed_region_chan->chanPwr[idx].pwr =
+                CountryInfo->Subband[j].MaxTxPwr;
+            idx++;
+        }
+
+        /*Step6: Add other checking if any */
+
+    }
+
+    parsed_region_chan->NoOfChan = idx;
+
+    PRINTM(INFO, "NoOfChan=%x\n", parsed_region_chan->NoOfChan);
+    HEXDUMP("11D:parsed_region_chan:", (s8 *) parsed_region_chan,
+            2 + COUNTRY_CODE_LEN + sizeof(parsed_region_chan_11d_t) * idx);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function calculates the scan type for channels
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t     
+ *  @return 	                PASSIVE if chan is unknown; ACTIVE if chan is known
+*/
+u8
+wlan_get_scan_type_11d(u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+    u8 scan_type = HostCmd_SCAN_TYPE_PASSIVE;
+
+    ENTER();
+
+    if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+        PRINTM(INFO, "11D: Found and do Active Scan\n");
+        scan_type = HostCmd_SCAN_TYPE_ACTIVE;
+    } else {
+        PRINTM(INFO, "11D: Not Find and do Passive Scan\n");
+    }
+
+    LEAVE();
+    return scan_type;
+
+}
+
+/** 
+ *  @brief This function gets if 11D is enabled
+ *  @param priv       pointer to wlan_private
+ *  @return 	      ENABLE_11D;DISABLE_11D
+*/
+state_11d_t
+wlan_get_state_11d(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_802_11d_state_t *state = &Adapter->State11D;
+    return (state->Enable11D);
+}
+
+/** 
+ *  @brief initialize internal variable for 11D
+ *  @param priv       pointer to wlan_private
+ *  @return 	      N/A
+*/
+void
+wlan_init_11d(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_802_11d_state_t *state = &Adapter->State11D;
+
+    state->Enable11D = DISABLE_11D;
+
+    memset(&(priv->adapter->parsed_region_chan), 0,
+           sizeof(parsed_region_chan_11d_t));
+
+    return;
+}
+
+/** 
+ *  @brief This function enable/disable 11D
+ *  @param priv       pointer to wlan_private
+ *  @param flag       enable/disable flag
+ *  @return 	      WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+*/
+int
+wlan_enable_11d(wlan_private * priv, state_11d_t flag)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_802_11d_state_t *state = &Adapter->State11D;
+
+    ENTER();
+
+    state->Enable11D = flag;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sets DOMAIN INFO to FW
+ *  @param priv       pointer to wlan_private
+ *  @return 	      WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+*/
+int
+wlan_set_domain_info_11d(wlan_private * priv)
+{
+    int ret;
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+                                HostCmd_ACT_GEN_SET,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+    if (ret) {
+        PRINTM(INFO, "11D: Fail to dnld domain Info\n");
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function setups scan channels
+ *  @param priv       pointer to wlan_private
+ *  @param band       band
+ *  @return 	      WLAN_STATUS_SUCCESS
+*/
+int
+wlan_set_universaltable(wlan_private * priv, u8 band)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u16 size = sizeof(CHANNEL_FREQ_POWER);
+    u16 i = 0;
+
+    ENTER();
+
+    memset(Adapter->universal_channel, 0, sizeof(Adapter->universal_channel));
+
+    {
+        Adapter->universal_channel[i].NrCFP =
+            sizeof(channel_freq_power_UN_BG) / size;
+        PRINTM(INFO, "11D: BG-band NrCFP=%d\n",
+               Adapter->universal_channel[i].NrCFP);
+
+        Adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+        Adapter->universal_channel[i].Valid = TRUE;
+        Adapter->universal_channel[i].Region = UNIVERSAL_REGION_CODE;
+        Adapter->universal_channel[i].Band = band;
+        i++;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *  @param priv       pointer to wlan_private
+ *  @param cmd        pointer to cmd buffer
+ *  @param cmdno      cmd ID
+ *  @param CmdOption  cmd action 
+ *  @return 	      WLAN_STATUS_SUCCESS
+*/
+int
+wlan_cmd_802_11d_domain_info(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, u16 cmdno,
+                             u16 CmdOption)
+{
+    HostCmd_DS_802_11D_DOMAIN_INFO *pDomainInfo = &cmd->params.domaininfo;
+    MrvlIEtypes_DomainParamSet_t *domain = &pDomainInfo->Domain;
+    wlan_adapter *Adapter = priv->adapter;
+    u8 NoOfSubband = Adapter->DomainReg.NoOfSubband;
+
+    ENTER();
+
+    PRINTM(INFO, "NoOfSubband=%x\n", NoOfSubband);
+
+    cmd->Command = wlan_cpu_to_le16(cmdno);
+    pDomainInfo->Action = wlan_cpu_to_le16(CmdOption);
+    if (CmdOption == HostCmd_ACT_GET) {
+        cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN);
+        HEXDUMP("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, (int) (cmd->Size));
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    domain->Header.Type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
+    memcpy(domain->CountryCode, Adapter->DomainReg.CountryCode,
+           sizeof(domain->CountryCode));
+
+    domain->Header.Len =
+        wlan_cpu_to_le16(NoOfSubband * sizeof(IEEEtypes_SubbandSet_t) +
+                         sizeof(domain->CountryCode));
+
+    if (NoOfSubband) {
+        memcpy(domain->Subband, Adapter->DomainReg.Subband,
+               NoOfSubband * sizeof(IEEEtypes_SubbandSet_t));
+
+        cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) +
+                                     domain->Header.Len +
+                                     sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
+    } else {
+        cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN);
+    }
+
+    HEXDUMP("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int) (cmd->Size));
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function implements private cmd: enable/disable 11D
+ *  @param priv    pointer to wlan_private
+ *  @param wrq     pointer to user data 
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+    int data = 0;
+    int *val;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+    PRINTM(INFO, "Enable 11D: %s\n",
+           (data == CMD_ENABLED) ? "Enable" : "Disable");
+    switch (data) {
+    case CMD_ENABLED:
+        wlan_enable_11d(priv, ENABLE_11D);
+        break;
+    case CMD_DISABLED:
+        wlan_enable_11d(priv, DISABLE_11D);
+        break;
+    default:
+        break;
+    }
+
+    data =
+        (Adapter->State11D.Enable11D ==
+         ENABLE_11D) ? CMD_ENABLED : CMD_DISABLED;
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @param resp    pointer to command response buffer
+ *  @return 	   WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11d_domain_info(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+        * domaininfo = &resp->params.domaininforesp;
+    MrvlIEtypes_DomainParamSet_t * domain = &domaininfo->Domain;
+    u16 Action = wlan_le16_to_cpu(domaininfo->Action);
+    s16 ret = WLAN_STATUS_SUCCESS;
+    u8 NoOfSubband = 0;
+
+    ENTER();
+
+    HEXDUMP("11D DOMAIN Info Rsp Data:", (u8 *) resp, resp->Size);
+
+    NoOfSubband =
+        (wlan_le16_to_cpu(domain->Header.Len) -
+         3) / sizeof(IEEEtypes_SubbandSet_t);
+    /* countrycode 3 bytes */
+
+    PRINTM(INFO, "11D Domain Info Resp: NoOfSubband=%d\n", NoOfSubband);
+
+    if (NoOfSubband > MRVDRV_MAX_SUBBAND_802_11D) {
+        PRINTM(INFO, "Invalid Numrer of Subband returned!!\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    switch (Action) {
+    case HostCmd_ACT_SET:      /*Proc Set Action */
+        break;
+
+    case HostCmd_ACT_GET:
+        break;
+    default:
+        PRINTM(INFO, "Invalid Action:%d\n", domaininfo->Action);
+        ret = WLAN_STATUS_FAILURE;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        /* Skip new 11d download when roaming */
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    if (wlan_get_state_11d(priv) == ENABLE_11D) {
+
+        memset(&Adapter->parsed_region_chan, 0,
+               sizeof(parsed_region_chan_11d_t));
+
+        ret =
+            wlan_parse_domain_info_11d(&Adapter->pAttemptedBSSDesc->
+                                       CountryInfo, 0,
+                                       &Adapter->parsed_region_chan);
+
+        if (ret == WLAN_STATUS_FAILURE) {
+            PRINTM(INFO, "11D: No region info in the AP BssDesc..\n");
+            LEAVE();
+            return WLAN_STATUS_SUCCESS;
+        }
+
+        memset(&Adapter->DomainReg, 0, sizeof(wlan_802_11d_domain_reg_t));
+        wlan_generate_domain_info_11d(&Adapter->parsed_region_chan,
+                                      &Adapter->DomainReg);
+
+        ret = wlan_set_domain_info_11d(priv);
+
+        if (ret) {
+            PRINTM(INFO, "11D: Err set domainInfo to FW\n");
+            LEAVE();
+            return ret;
+        }
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function generates 11D info from user specified regioncode and download to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_create_dnld_countryinfo_11d(wlan_private * priv, u8 band)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    REGION_CHANNEL *region_chan;
+    u8 j;
+
+    ENTER();
+    PRINTM(INFO, "11D:Band[%d]\n", band);
+
+    /* update parsed_region_chan_11; dnld domaininf to FW */
+
+    for (j = 0; j < sizeof(Adapter->region_channel) /
+         sizeof(Adapter->region_channel[0]); j++) {
+        region_chan = &Adapter->region_channel[j];
+
+        PRINTM(INFO, "11D:[%d] region_chan->Band[%d]\n", j,
+               region_chan->Band);
+
+        if (!region_chan || !region_chan->Valid || !region_chan->CFP)
+            continue;
+        if (region_chan->Band != band)
+            continue;
+        break;
+    }
+
+    if (j >= sizeof(Adapter->region_channel) /
+        sizeof(Adapter->region_channel[0])) {
+        PRINTM(INFO, "11D:region_chan not found. Band[%d]\n", band);
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memset(&Adapter->parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t));
+    wlan_generate_parsed_region_chan_11d(region_chan,
+                                         &Adapter->parsed_region_chan);
+
+    memset(&Adapter->DomainReg, 0, sizeof(wlan_802_11d_domain_reg_t));
+    wlan_generate_domain_info_11d(&Adapter->parsed_region_chan,
+                                  &Adapter->DomainReg);
+
+    ret = wlan_set_domain_info_11d(priv);
+
+    if (ret) {
+        PRINTM(INFO, "11D: Err set domainInfo to FW\n");
+        LEAVE();
+        return ret;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_11d.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_11d.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_11d.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_11d.h	2008-09-28 11:33:15.000000000 +0200
@@ -0,0 +1,124 @@
+/** @file wlan_11d.h
+ *  @brief This header file contains data structures and 
+ *  function declarations of 802.11d  
+ *
+ * (c) Copyright © 2003-2006, Marvell International Ltd.  
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change log:
+	09/26/05: add Doxygen format comments 
+ ************************************************************/
+
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+#define MAX_CHAN_NUM				255
+
+#define UNIVERSAL_REGION_CODE			0xff
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) 
+ */
+#define MAX_NO_OF_CHAN 				40
+
+typedef struct _REGION_CHANNEL *PREGION_CHANNEL;
+
+typedef enum
+{
+    DISABLE_11D = 0,
+    ENABLE_11D = 1,
+} state_11d_t;
+
+/** domain regulatory information */
+typedef struct _wlan_802_11d_domain_reg
+{
+        /** country Code*/
+    u8 CountryCode[COUNTRY_CODE_LEN];
+        /** No. of subband*/
+    u8 NoOfSubband;
+    IEEEtypes_SubbandSet_t Subband[MRVDRV_MAX_SUBBAND_802_11D];
+} wlan_802_11d_domain_reg_t;
+
+typedef struct _chan_power_11d
+{
+    u8 chan;
+    u8 pwr;
+} __ATTRIB_PACK__ chan_power_11d_t;
+
+typedef struct _parsed_region_chan_11d
+{
+    u8 band;
+    u8 region;
+    s8 CountryCode[COUNTRY_CODE_LEN];
+    chan_power_11d_t chanPwr[MAX_NO_OF_CHAN];
+    u8 NoOfChan;
+} __ATTRIB_PACK__ parsed_region_chan_11d_t;
+
+/** Data for state machine */
+typedef struct _wlan_802_11d_state
+{
+        /** True for Enabling  11D*/
+    BOOLEAN Enable11D;
+} wlan_802_11d_state_t;
+
+typedef struct _region_code_mapping
+{
+    s8 region[COUNTRY_CODE_LEN];
+    u8 code;
+} region_code_mapping_t;
+
+/* function prototypes*/
+int wlan_generate_domain_info_11d(parsed_region_chan_11d_t *
+                                  parsed_region_chan,
+                                  wlan_802_11d_domain_reg_t * domaininfo);
+
+int wlan_parse_domain_info_11d(IEEEtypes_CountryInfoFullSet_t * CountryInfo,
+                               u8 band,
+                               parsed_region_chan_11d_t * parsed_region_chan);
+
+u8 wlan_get_scan_type_11d(u8 chan,
+                          parsed_region_chan_11d_t * parsed_region_chan);
+
+u32 chan_2_freq(u8 chan, u8 band);
+
+int wlan_set_domain_info_11d(wlan_private * priv);
+
+state_11d_t wlan_get_state_11d(wlan_private * priv);
+
+void wlan_init_11d(wlan_private * priv);
+
+int wlan_enable_11d(wlan_private * priv, state_11d_t flag);
+
+int wlan_set_universaltable(wlan_private * priv, u8 band);
+
+void wlan_generate_parsed_region_chan_11d(PREGION_CHANNEL region_chan,
+                                          parsed_region_chan_11d_t *
+                                          parsed_region_chan);
+
+int wlan_cmd_802_11d_domain_info(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * cmd, u16 cmdno,
+                                 u16 CmdOption);
+
+int wlan_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int wlan_ret_802_11d_domain_info(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * resp);
+
+int wlan_parse_dnld_countryinfo_11d(wlan_private * priv);
+
+int wlan_create_dnld_countryinfo_11d(wlan_private * priv, u8 band);
+
+#endif /* _WLAN_11D_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_cmd.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_cmd.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_cmd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_cmd.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,2489 @@
+/** @file wlan_cmd.c
+  *  
+  * @brief This file contains the handling of command.
+  * it prepares command and sends it to firmware when
+  * it is ready.
+  * 
+  * (c) Copyright © 2003-2007, Marvell International Ltd.  
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+    10/04/05: Add Doxygen format comments
+    01/05/06: Add kernel 2.6.x support  
+    01/11/06: Conditionalize new scan/join structures
+    01/31/06: Add support to selectively enabe the FW Scan channel filter
+    02/16/06: Clear scan in progress flag when scan command failed and dropped
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+    04/18/06: Remove old Subscrive Event and add new Subscribe Event
+              implementation through generic hostcmd API
+    05/04/06: Add IBSS coalescing related new hostcmd handling	      
+    08/29/06: Add ledgpio private command
+********************************************************/
+
+#include	"include.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+static u16 Commands_Allowed_In_PS[] = {
+    HostCmd_CMD_802_11_RSSI,
+    HostCmd_CMD_802_11_HOST_SLEEP_CFG,
+    HostCmd_CMD_802_11_WAKEUP_CONFIRM,
+};
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function checks if the commans is allowed
+ *  in PS mode not.
+ *  
+ *  @param Command the command ID
+ *  @return 	   TRUE or FALSE
+ */
+static BOOLEAN
+Is_Command_Allowed_In_PS(u16 Command)
+{
+    int count = sizeof(Commands_Allowed_In_PS)
+        / sizeof(Commands_Allowed_In_PS[0]);
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (Command == wlan_cpu_to_le16(Commands_Allowed_In_PS[i]))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/** 
+ *  @brief This function prepares command of get_hw_spec.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param cmd	   A pointer to HostCmd_DS_COMMAND structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_hw_spec(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    HostCmd_DS_GET_HW_SPEC *hwspec = &cmd->params.hwspec;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
+    memcpy(hwspec->PermanentAddr, priv->adapter->CurrentAddr, ETH_ALEN);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of ps_mode.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 	the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_ps_mode(wlan_private * priv,
+                        HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_802_11_PS_MODE *psm = &cmd->params.psmode;
+    u16 Action = cmd_action;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_PS_MODE) + S_DS_GEN);
+    psm->Action = wlan_cpu_to_le16(cmd_action);
+    psm->MultipleDtim = 0;
+    switch (Action) {
+    case HostCmd_SubCmd_Enter_PS:
+        PRINTM(INFO, "PS Command:" "SubCode- Enter PS\n");
+        PRINTM(INFO, "LocalListenInterval = %d\n",
+               Adapter->LocalListenInterval);
+
+        psm->LocalListenInterval =
+            wlan_cpu_to_le16(Adapter->LocalListenInterval);
+        psm->NullPktInterval = wlan_cpu_to_le16(Adapter->NullPktInterval);
+        psm->MultipleDtim = wlan_cpu_to_le16(priv->adapter->MultipleDtim);
+        psm->BCNMissTimeOut = wlan_cpu_to_le16(priv->adapter->BCNMissTimeOut);
+        if (priv->adapter->InfrastructureMode == Wlan802_11IBSS)
+            psm->AdhocAwakePeriod =
+                wlan_cpu_to_le16(priv->adapter->AdhocAwakePeriod);
+        break;
+
+    case HostCmd_SubCmd_Exit_PS:
+        PRINTM(INFO, "PS Command:" "SubCode- Exit PS\n");
+        break;
+
+    case HostCmd_SubCmd_Sleep_Confirmed:
+        PRINTM(INFO, "PS Command: SubCode- sleep confirm\n");
+        break;
+
+    default:
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of fw_wakeup_method.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 	the action: GET or SET
+ *  @param pdata_buf 	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_fw_wakeup_method(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * cmd,
+                                 int cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &cmd->params.fwwakeupmethod;
+    u16 action = (u16) cmd_action;
+    u16 method = *((u16 *) pdata_buf);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_FW_WAKE_METHOD);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_FW_WAKEUP_METHOD) +
+                         S_DS_GEN);
+    fwwm->Action = wlan_cpu_to_le16(action);
+    switch (action) {
+    case HostCmd_ACT_SET:
+        fwwm->Method = wlan_cpu_to_le16(method);
+        break;
+    case HostCmd_ACT_GET:
+    default:
+        fwwm->Method = 0;
+        break;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sends the HS_Activated event to the application
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_host_sleep_activated_event(wlan_private * priv)
+{
+    ENTER();
+
+    priv->adapter->HS_Activated = TRUE;
+    os_carrier_off(priv);
+    os_stop_queue(priv);
+    wmm_stop_queue(priv);
+
+#if WIRELESS_EXT > 14
+    send_iwevcustom_event(priv, CUS_EVT_HS_ACTIVATED);
+#endif /* WIRELESS_EXT */
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sends the HS_DeActivated event to the application
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_host_sleep_deactivated_event(wlan_private * priv)
+{
+    ENTER();
+
+    priv->adapter->HS_Activated = FALSE;
+
+#if WIRELESS_EXT > 14
+    send_iwevcustom_event(priv, CUS_EVT_HS_DEACTIVATED);
+#endif /* WIRELESS_EXT */
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sends the HS_GPIO_INT event to the application
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+int
+wlan_host_sleep_gpio_int_event(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->bHostSleepConfigured) {
+#if WIRELESS_EXT > 14
+        send_iwevcustom_event(priv, CUS_EVT_HS_GPIO_INT);
+#endif /* WIRELESS_EXT */
+    } else {
+        PRINTM(INFO, "hs_gpio_int: HS not configured !!!\n");
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of host_sleep_cfg.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf 	A pointer to HostCmd_DS_802_11_HOST_SLEEP_CFG structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_host_sleep_cfg(wlan_private * priv,
+                               HostCmd_DS_COMMAND * cmd,
+                               HostCmd_DS_802_11_HOST_SLEEP_CFG * pdata_buf)
+{
+    HostCmd_DS_802_11_HOST_SLEEP_CFG *phwuc = &cmd->params.hostsleepcfg;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HOST_SLEEP_CFG);
+    if ((pdata_buf->conditions != HOST_SLEEP_CFG_CANCEL)
+        && ((priv->adapter->ArpFilterSize > 0)
+            && (priv->adapter->ArpFilterSize <= ARP_FILTER_MAX_BUF_SIZE))) {
+        PRINTM(INFO, "Attach %d bytes ArpFilter to HSCfg cmd\n",
+               priv->adapter->ArpFilterSize);
+        memcpy(((u8 *) phwuc) + sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG),
+               priv->adapter->ArpFilter, priv->adapter->ArpFilterSize);
+        cmd->Size =
+            wlan_cpu_to_le16(priv->adapter->ArpFilterSize +
+                             sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG) +
+                             S_DS_GEN);
+    } else
+        cmd->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG) +
+                             S_DS_GEN);
+    phwuc->conditions = wlan_cpu_to_le32(pdata_buf->conditions);
+    phwuc->gpio = pdata_buf->gpio;
+    phwuc->gap = pdata_buf->gap;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of inactivity_timeout.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   Action: GET SET
+ *  @param pdata_buf 	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * cmd,
+                                   u16 cmd_action, void *pdata_buf)
+{
+    u16 *timeout = (u16 *) pdata_buf;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_INACTIVITY_TIMEOUT);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_INACTIVITY_TIMEOUT) +
+                         S_DS_GEN);
+
+    cmd->params.inactivity_timeout.Action = wlan_cpu_to_le16(cmd_action);
+
+    if (cmd_action)
+        cmd->params.inactivity_timeout.Timeout = wlan_cpu_to_le16(*timeout);
+    else
+        cmd->params.inactivity_timeout.Timeout = 0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of sleep_period.
+ *  
+ *  @param priv    		A pointer to wlan_private structure
+ *  @param cmd	   		A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 		the action: GET or SET
+ *  @param pdata_buf		A pointer to data buffer
+ *  @return 	   		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_sleep_period(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd,
+                             u16 cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_SLEEP_PERIOD *pSleepPeriod = &cmd->params.ps_sleeppd;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) +
+                                 S_DS_GEN);
+    memmove(pSleepPeriod, pdata_buf, sizeof(HostCmd_DS_802_11_SLEEP_PERIOD));
+    pSleepPeriod->Action = wlan_cpu_to_le16(pSleepPeriod->Action);
+    pSleepPeriod->Period = wlan_cpu_to_le16(pSleepPeriod->Period);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of sleep_params.
+ *  
+ *  @param priv    		A pointer to wlan_private structure
+ *  @param cmd	   		A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 		the action: GET or SET
+ *  @return 	   		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_sleep_params(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_SLEEP_PARAMS *sp = &cmd->params.sleep_params;
+
+    ENTER();
+
+    cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SLEEP_PARAMS)) +
+                                 S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
+
+    if (cmd_action == HostCmd_ACT_GEN_GET) {
+        memset(&Adapter->sp, 0, sizeof(SleepParams));
+        memset(sp, 0, sizeof(HostCmd_DS_802_11_SLEEP_PARAMS));
+        sp->Action = wlan_cpu_to_le16(cmd_action);
+    } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+        sp->Action = wlan_cpu_to_le16(cmd_action);
+        sp->Error = wlan_cpu_to_le16(Adapter->sp.sp_error);
+        sp->Offset = wlan_cpu_to_le16(Adapter->sp.sp_offset);
+        sp->StableTime = wlan_cpu_to_le16(Adapter->sp.sp_stabletime);
+        sp->CalControl = (u8) Adapter->sp.sp_calcontrol;
+        sp->ExternalSleepClk = (u8) Adapter->sp.sp_extsleepclk;
+        sp->Reserved = wlan_cpu_to_le16(Adapter->sp.sp_reserved);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+#define WEP_40_BIT_LEN	5
+#define WEP_104_BIT_LEN	13
+
+/** 
+ *  @brief This function prepares command of set_wep.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_oid   OID: ADD_WEP KEY or REMOVE_WEP KEY
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_set_wep(wlan_private * priv,
+                        HostCmd_DS_COMMAND * cmd, u32 cmd_oid)
+{
+    HostCmd_DS_802_11_SET_WEP *wep = &cmd->params.wep;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (cmd_oid == OID_802_11_ADD_WEP) {
+        cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP);
+        cmd->Size =
+            wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SET_WEP)) + S_DS_GEN);
+        wep->Action = wlan_cpu_to_le16(HostCmd_ACT_ADD);
+
+        /* default tx key index */
+        wep->KeyIndex = wlan_cpu_to_le16(Adapter->CurrentWepKeyIndex &
+                                         HostCmd_WEP_KEY_INDEX_MASK);
+
+        PRINTM(INFO, "Tx Key Index: %u\n", wep->KeyIndex);
+
+        switch (Adapter->WepKey[0].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial,
+                    Adapter->WepKey[0].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial,
+                    Adapter->WepKey[0].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key1 Length = %d is incorrect\n",
+                   Adapter->WepKey[0].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        switch (Adapter->WepKey[1].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial,
+                    Adapter->WepKey[1].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial,
+                    Adapter->WepKey[1].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key2 Length = %d is incorrect\n",
+                   Adapter->WepKey[1].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        switch (Adapter->WepKey[2].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial,
+                    Adapter->WepKey[2].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial,
+                    Adapter->WepKey[2].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key3 Length = %d is incorrect\n",
+                   Adapter->WepKey[2].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        switch (Adapter->WepKey[3].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial,
+                    Adapter->WepKey[3].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial,
+                    Adapter->WepKey[3].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key4 Length = %d is incorrect\n",
+                   Adapter->WepKey[3].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    } else if (cmd_oid == OID_802_11_REMOVE_WEP) {
+        cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP);
+        cmd->Size =
+            wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SET_WEP)) + S_DS_GEN);
+        wep->Action = wlan_cpu_to_le16(HostCmd_ACT_REMOVE);
+
+        /* default tx key index */
+        wep->KeyIndex = wlan_cpu_to_le16((u16) (Adapter->CurrentWepKeyIndex &
+                                                (u32)
+                                                HostCmd_WEP_KEY_INDEX_MASK));
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of key_material.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 	the action: GET or SET
+ *  @param cmd_oid	OID: ENABLE or DISABLE
+ *  @param pdata_buf    A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_key_material(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd,
+                             u16 cmd_action,
+                             WLAN_OID cmd_oid, void *pdata_buf)
+{
+    HostCmd_DS_802_11_KEY_MATERIAL *pKeyMaterial = &cmd->params.keymaterial;
+    WLAN_802_11_KEY *pKey = (WLAN_802_11_KEY *) pdata_buf;
+    u16 KeyParamSet_len;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+    pKeyMaterial->Action = wlan_cpu_to_le16(cmd_action);
+
+    if (cmd_action == HostCmd_ACT_GET) {
+        cmd->Size = wlan_cpu_to_le16(2 + S_DS_GEN);
+        ret = WLAN_STATUS_SUCCESS;
+        goto done;
+    }
+
+    memset(&pKeyMaterial->KeyParamSet, 0, sizeof(MrvlIEtype_KeyParamSet_t));
+
+    if (pKey->KeyLength == WPA_AES_KEY_LEN) {
+        PRINTM(INFO, "WPA_AES\n");
+        pKeyMaterial->KeyParamSet.KeyTypeId =
+            wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+
+        if (cmd_oid == (WLAN_OID) KEY_INFO_ENABLED)
+            pKeyMaterial->KeyParamSet.KeyInfo =
+                wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+        else
+            pKeyMaterial->KeyParamSet.KeyInfo =
+                !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+        if (pKey->KeyIndex & 0x40000000)        //AES pairwise key: unicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+        else                    //AES group key: multicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+    } else if (pKey->KeyLength == WPA_TKIP_KEY_LEN) {
+        PRINTM(INFO, "WPA_TKIP\n");
+        pKeyMaterial->KeyParamSet.KeyTypeId =
+            wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+        pKeyMaterial->KeyParamSet.KeyInfo =
+            wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+        if (pKey->KeyIndex & 0x40000000)        //TKIP pairwise key: unicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+        else                    //TKIP group key: multicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+    }
+
+    if (pKeyMaterial->KeyParamSet.KeyTypeId) {
+        pKeyMaterial->KeyParamSet.Type =
+            wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+        pKeyMaterial->KeyParamSet.KeyLen = wlan_cpu_to_le16(pKey->KeyLength);
+        memcpy(pKeyMaterial->KeyParamSet.Key,
+               pKey->KeyMaterial, pKey->KeyLength);
+        pKeyMaterial->KeyParamSet.Length =
+            wlan_cpu_to_le16(pKey->KeyLength + 6);
+
+#define TYPE_LEN_FIELDS_LEN 4
+        KeyParamSet_len = (pKey->KeyLength + 6) + TYPE_LEN_FIELDS_LEN;
+#define ACTION_FIELD_LEN 2
+        cmd->Size =
+            wlan_cpu_to_le16(KeyParamSet_len + ACTION_FIELD_LEN + S_DS_GEN);
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of get_log.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_get_log(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of snmp_mib.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param cmd_oid   	the OID of SNMP MIB
+ *  @param pdata_buf	the pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+                         HostCmd_DS_COMMAND * cmd,
+                         int cmd_action, int cmd_oid, void *pdata_buf)
+{
+    HostCmd_DS_802_11_SNMP_MIB *pSNMPMIB = &cmd->params.smib;
+    wlan_adapter *Adapter = priv->adapter;
+    u8 ucTemp;
+
+    ENTER();
+
+    PRINTM(INFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SNMP_MIB) + S_DS_GEN);
+
+    switch (cmd_oid) {
+    case OID_802_11_INFRASTRUCTURE_MODE:
+        pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+        pSNMPMIB->OID = wlan_cpu_to_le16((u16) DesiredBssType_i);
+        pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u8));
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure)
+            ucTemp = SNMP_MIB_VALUE_INFRA;
+        else
+            ucTemp = SNMP_MIB_VALUE_ADHOC;
+
+        memmove(pSNMPMIB->Value, &ucTemp, sizeof(u8));
+
+        break;
+
+    case OID_802_11D_ENABLE:
+        {
+            u32 ulTemp;
+
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) Dot11D_i);
+
+            if (cmd_action == HostCmd_ACT_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *(u32 *) pdata_buf;
+                *((PUSHORT) (pSNMPMIB->Value)) =
+                    wlan_cpu_to_le16((u16) ulTemp);
+            }
+            break;
+        }
+
+    case OID_802_11_FRAGMENTATION_THRESHOLD:
+        {
+            WLAN_802_11_FRAGMENTATION_THRESHOLD ulTemp;
+
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) FragThresh_i);
+
+            if (cmd_action == HostCmd_ACT_GET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+            } else if (cmd_action == HostCmd_ACT_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *((WLAN_802_11_FRAGMENTATION_THRESHOLD *)
+                           pdata_buf);
+                *((PUSHORT) (pSNMPMIB->Value)) =
+                    wlan_cpu_to_le16((u16) ulTemp);
+
+            }
+
+            break;
+        }
+
+    case OID_802_11_RTS_THRESHOLD:
+        {
+
+            WLAN_802_11_RTS_THRESHOLD ulTemp;
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) RtsThresh_i);
+
+            if (cmd_action == HostCmd_ACT_GET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+            } else if (cmd_action == HostCmd_ACT_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *((WLAN_802_11_RTS_THRESHOLD *)
+                           pdata_buf);
+                *(PUSHORT) (pSNMPMIB->Value) = wlan_cpu_to_le16((u16) ulTemp);
+
+            }
+            break;
+        }
+    case OID_802_11_TX_RETRYCOUNT:
+        pSNMPMIB->OID = wlan_cpu_to_le16((u16) ShortRetryLim_i);
+
+        if (cmd_action == HostCmd_ACT_GET) {
+            pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+        } else if (cmd_action == HostCmd_ACT_SET) {
+            pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+            pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+            *((PUSHORT) (pSNMPMIB->Value)) =
+                wlan_cpu_to_le16((u16) Adapter->TxRetryCount);
+        }
+
+        break;
+    default:
+        break;
+    }
+
+    PRINTM(INFO,
+           "SNMP_CMD: Command=0x%x, Size=0x%x, SeqNum=0x%x, Result=0x%x\n",
+           cmd->Command, cmd->Size, cmd->SeqNum, cmd->Result);
+
+    PRINTM(INFO,
+           "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
+           pSNMPMIB->QueryType, pSNMPMIB->OID, pSNMPMIB->BufSize,
+           *(u16 *) pSNMPMIB->Value);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of radio_control.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_radio_control(wlan_private * priv,
+                              HostCmd_DS_COMMAND * cmd, int cmd_action)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_RADIO_CONTROL *pRadioControl = &cmd->params.radio;
+
+    ENTER();
+
+    cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL))
+                                 + S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
+
+    pRadioControl->Action = wlan_cpu_to_le16(cmd_action);
+    pRadioControl->Control = wlan_cpu_to_le16(Adapter->RadioOn);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of bca_timeshare.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param user_bca_ts	A pointer to HostCmd_DS_802_11_BCA_TIMESHARE structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_bca_timeshare(wlan_private * priv,
+                              HostCmd_DS_COMMAND * cmd,
+                              u16 cmd_action,
+                              HostCmd_DS_802_11_BCA_TIMESHARE * user_bca_ts)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &cmd->params.bca_timeshare;
+
+    ENTER();
+
+    cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_BCA_TIMESHARE)) +
+                                 S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE);
+
+    if (cmd_action == HostCmd_ACT_GEN_GET) {
+        memset(&Adapter->bca_ts, 0, sizeof(bca_ts));
+        memset(bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
+        bca_ts->Action = wlan_cpu_to_le16(cmd_action);
+        bca_ts->TrafficType = wlan_cpu_to_le16(user_bca_ts->TrafficType);
+    } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+        bca_ts->Action = wlan_cpu_to_le16(cmd_action);
+        bca_ts->TrafficType = wlan_cpu_to_le16(user_bca_ts->TrafficType);
+        bca_ts->TimeShareInterval =
+            wlan_cpu_to_le32(user_bca_ts->TimeShareInterval);
+        bca_ts->BTTime = wlan_cpu_to_le32(user_bca_ts->BTTime);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rf_tx_power.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+                            HostCmd_DS_COMMAND * cmd,
+                            u16 cmd_action, void *pdata_buf)
+{
+
+    HostCmd_DS_802_11_RF_TX_POWER *pRTP = &cmd->params.txp;
+
+    ENTER();
+
+    cmd->Size =
+        wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RF_TX_POWER)) + S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER);
+    pRTP->Action = cmd_action;
+
+    PRINTM(INFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n", cmd->Size,
+           cmd->Command, pRTP->Action);
+
+    switch (cmd_action) {
+    case HostCmd_ACT_GEN_GET:
+        pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+        pRTP->CurrentLevel = 0;
+        break;
+
+    case HostCmd_ACT_GEN_SET:
+        pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+        pRTP->CurrentLevel = wlan_cpu_to_le16(*((u16 *) pdata_buf));
+        break;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rf_antenna.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+                           HostCmd_DS_COMMAND * cmd,
+                           u16 cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_RF_ANTENNA *rant = &cmd->params.rant;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
+
+    rant->Action = wlan_cpu_to_le16(cmd_action);
+    if ((cmd_action == HostCmd_ACT_SET_RX) ||
+        (cmd_action == HostCmd_ACT_SET_TX)) {
+        rant->AntennaMode =
+            wlan_cpu_to_le16((u16) (*(WLAN_802_11_ANTENNA *) pdata_buf));
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rate_adapt_rateset.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_802_11_RATE_ADAPT_RATESET * rateadapt = &cmd->params.rateset;
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RATE_ADAPT_RATESET) +
+                         S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RATE_ADAPT_RATESET);
+
+    ENTER();
+
+    rateadapt->Action = wlan_cpu_to_le16(cmd_action);
+    rateadapt->HWRateDropMode = wlan_cpu_to_le16(Adapter->HWRateDropMode);
+    rateadapt->Threshold = wlan_cpu_to_le16(Adapter->Threshold);
+    rateadapt->FinalRate = wlan_cpu_to_le16(Adapter->FinalRate);
+    rateadapt->Bitmap = wlan_cpu_to_le16(Adapter->RateBitmap);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of mac_multicast_adr.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_mac_multicast_adr(wlan_private * priv,
+                           HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_MAC_MULTICAST_ADR *pMCastAdr = &cmd->params.madr;
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) + S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+    pMCastAdr->Action = wlan_cpu_to_le16(cmd_action);
+    pMCastAdr->NumOfAdrs =
+        wlan_cpu_to_le16((u16) Adapter->NumOfMulticastMACAddr);
+    memcpy(pMCastAdr->MACList, Adapter->MulticastList,
+           Adapter->NumOfMulticastMACAddr * ETH_ALEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rf_channel.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rf_channel(wlan_private * priv,
+                           HostCmd_DS_COMMAND * cmd,
+                           int option, void *pdata_buf)
+{
+    HostCmd_DS_802_11_RF_CHANNEL *rfchan = &cmd->params.rfchannel;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL)
+                                 + S_DS_GEN);
+
+    if (option == HostCmd_OPT_802_11_RF_CHANNEL_SET) {
+        rfchan->CurrentChannel = wlan_cpu_to_le16(*((u16 *) pdata_buf));
+    }
+
+    rfchan->Action = wlan_cpu_to_le16(option);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rssi.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rssi(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RSSI);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI) + S_DS_GEN);
+    cmd->params.rssi.N = wlan_cpu_to_le16(Adapter->bcn_avg_factor);
+
+    /* reset Beacon SNR/NF/RSSI values */
+    Adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+    Adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+    Adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+    Adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
+    Adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+    Adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of reg_access.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_reg_access(wlan_private * priv,
+                    HostCmd_DS_COMMAND * CmdPtr,
+                    u8 cmd_action, void *pdata_buf)
+{
+    wlan_offset_value *offval;
+
+    ENTER();
+
+    offval = (wlan_offset_value *) pdata_buf;
+
+    switch (CmdPtr->Command) {
+    case HostCmd_CMD_MAC_REG_ACCESS:
+        {
+            HostCmd_DS_MAC_REG_ACCESS *macreg;
+
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) +
+                                 S_DS_GEN);
+            macreg = (HostCmd_DS_MAC_REG_ACCESS *) & CmdPtr->params.macreg;
+
+            macreg->Action = wlan_cpu_to_le16(cmd_action);
+            macreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
+            macreg->Value = wlan_cpu_to_le32(offval->value);
+
+            break;
+        }
+
+    case HostCmd_CMD_BBP_REG_ACCESS:
+        {
+            HostCmd_DS_BBP_REG_ACCESS *bbpreg;
+
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) +
+                                 S_DS_GEN);
+            bbpreg = (HostCmd_DS_BBP_REG_ACCESS *) & CmdPtr->params.bbpreg;
+
+            bbpreg->Action = wlan_cpu_to_le16(cmd_action);
+            bbpreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
+            bbpreg->Value = (u8) offval->value;
+
+            break;
+        }
+
+    case HostCmd_CMD_RF_REG_ACCESS:
+        {
+            HostCmd_DS_RF_REG_ACCESS *rfreg;
+
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+            rfreg = (HostCmd_DS_RF_REG_ACCESS *) & CmdPtr->params.rfreg;
+
+            rfreg->Action = wlan_cpu_to_le16(cmd_action);
+            rfreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
+            rfreg->Value = (u8) offval->value;
+
+            break;
+        }
+
+    default:
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of mac_address.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_mac_address(wlan_private * priv,
+                            HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
+                                 S_DS_GEN);
+    cmd->Result = 0;
+
+    cmd->params.macadd.Action = wlan_cpu_to_le16(cmd_action);
+
+    if (cmd_action == HostCmd_ACT_SET) {
+        memcpy(cmd->params.macadd.MacAdd, Adapter->CurrentAddr, ETH_ALEN);
+        HEXDUMP("SET_CMD: MAC ADDRESS-", Adapter->CurrentAddr, 6);
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of cal_data_ext.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_cal_data_ext(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_802_11_CAL_DATA_EXT *PCalDataext = pdata_buf;
+
+    HostCmd_DS_802_11_CAL_DATA_EXT *pCmdCalData =
+        (HostCmd_DS_802_11_CAL_DATA_EXT *) & cmd->params.caldataext;
+
+    ENTER();
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_CAL_DATA_EXT);
+
+    PRINTM(INFO, "CalDataLen = %d(d)\n", PCalDataext->CalDataLen);
+
+    if (PCalDataext->CalDataLen >
+        MAX_SETGET_CONF_CMD_LEN - CAL_DATA_HEADER_LEN) {
+        PRINTM(MSG, "CAL_DATA_EXT: Cal data lenght too large!\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memcpy(pCmdCalData, PCalDataext,
+           PCalDataext->CalDataLen + CAL_DATA_HEADER_LEN);
+
+    pCmdCalData->Action = wlan_cpu_to_le16(pCmdCalData->Action);
+    pCmdCalData->Revision = wlan_cpu_to_le16(pCmdCalData->Revision);
+    pCmdCalData->CalDataLen = wlan_cpu_to_le16(pCmdCalData->CalDataLen);
+
+    cmd->Size = wlan_cpu_to_le16(PCalDataext->CalDataLen +
+                                 CAL_DATA_HEADER_LEN + S_DS_GEN);
+
+    PRINTM(INFO, "CAL_DATA_EXT: cmd->Size = %d(d)\n", cmd->Size);
+
+    cmd->Result = 0;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of eeprom_access.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+                              HostCmd_DS_COMMAND * cmd,
+                              int cmd_action, void *pdata_buf)
+{
+    wlan_ioctl_regrdwr *ea = pdata_buf;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_EEPROM_ACCESS);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) + S_DS_GEN);
+    cmd->Result = 0;
+
+    cmd->params.rdeeprom.Action = wlan_cpu_to_le16(ea->Action);
+    cmd->params.rdeeprom.Offset = wlan_cpu_to_le16(ea->Offset);
+    cmd->params.rdeeprom.ByteCount = wlan_cpu_to_le16(ea->NOB);
+    cmd->params.rdeeprom.Value = 0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+static int
+wlan_cmd_802_11_IBSS_Coalesced_Status(wlan_private * priv,
+                                      HostCmd_DS_COMMAND * cmd,
+                                      int cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_IBSS_Status *pIBSSReq = &(cmd->params.ibssCoalescing);
+    u16 *enable = pdata_buf;
+
+    PRINTM(INFO, "HostCmd_CMD_802_11_BSSID_QUERY request");
+
+    cmd->Command =
+        wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_Status) + S_DS_GEN);
+    cmd->Result = 0;
+    pIBSSReq->Action = wlan_cpu_to_le16(cmd_action);
+
+    switch (cmd_action) {
+    case HostCmd_ACT_SET:
+        pIBSSReq->Enable = wlan_cpu_to_le16(*enable);
+        break;
+
+        /* In other case.. Noting to do */
+    case HostCmd_ACT_GET:
+    default:
+        break;
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function queues the command to cmd list.
+ *  
+ *  @param Adapter	A pointer to wlan_adapter structure
+ *  @param CmdNode   	A pointer to CmdCtrlNode structure
+ *  @param addtail	specify if the cmd needs to be queued in the header or tail
+ *  @return 	   	n/a
+ */
+void
+QueueCmd(wlan_adapter * Adapter, CmdCtrlNode * CmdNode, BOOLEAN addtail)
+{
+    ulong flags;
+    HostCmd_DS_COMMAND *CmdPtr;
+    u16 command;
+
+    ENTER();
+
+    if (!CmdNode) {
+        PRINTM(WARN, "QUEUE_CMD: CmdNode is NULL\n");
+        goto done;
+    }
+
+    CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+    if (!CmdPtr) {
+        PRINTM(WARN, "QUEUE_CMD: CmdPtr is NULL\n");
+        goto done;
+    }
+
+    command = wlan_le16_to_cpu(CmdPtr->Command);
+
+    /* Exit_PS command needs to be queued in the header always. */
+    if (command == HostCmd_CMD_802_11_PS_MODE) {
+        HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode;
+        if (wlan_le16_to_cpu(psm->Action) == HostCmd_SubCmd_Exit_PS) {
+            if (Adapter->PSState != PS_STATE_FULL_POWER)
+                addtail = FALSE;
+        }
+    }
+
+    if ((command == HostCmd_CMD_802_11_WAKEUP_CONFIRM)
+        || (command == HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE)
+        || (command == HostCmd_CMD_802_11_HOST_SLEEP_CFG)
+        ) {
+        addtail = FALSE;
+    }
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+
+    if (addtail)
+        list_add_tail((struct list_head *) CmdNode, &Adapter->CmdPendingQ);
+    else
+        list_add((struct list_head *) CmdNode, &Adapter->CmdPendingQ);
+
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    PRINTM(INFO, "QUEUE_CMD: cmd=0x%x is queued\n", command);
+
+  done:
+    LEAVE();
+    return;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/** 
+ *  @brief This function sends general command to firmware.
+ *  
+ *  @param priv     	A pointer to wlan_private structure
+ *  @param cmd      	A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return         	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_mfg_cmd(wlan_private * priv,
+                 HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_GEN *pCmdPtr;
+
+    ENTER();
+
+    pCmdPtr = (HostCmd_DS_GEN *) pdata_buf;
+
+    /* copy the MFG command to command buffer */
+    memcpy((void *) cmd, pdata_buf, pCmdPtr->Size);
+
+    PRINTM(INFO, "MFG command size = %d\n", pCmdPtr->Size);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
+    cmd->Size = wlan_cpu_to_le16(cmd->Size);
+    cmd->Result = 0;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+#endif
+
+/** 
+ *  @brief This function downloads the command to firmware.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param CmdNode   	A pointer to CmdCtrlNode structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+DownloadCommandToStation(wlan_private * priv, CmdCtrlNode * CmdNode)
+{
+    ulong flags;
+    HostCmd_DS_COMMAND *CmdPtr;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 CmdSize;
+    u16 Command;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    if (!Adapter || !CmdNode) {
+        PRINTM(ERROR, "DNLD_CMD: Adapter = %#x, CmdNode = %#x\n",
+               (int) Adapter, (int) CmdNode);
+        if (CmdNode)
+            CleanupAndInsertCmd(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+
+    if (!CmdPtr || !CmdPtr->Size) {
+        PRINTM(ERROR, "DNLD_CMD: CmdPtr is Null or Cmd Size is Zero, "
+               "Not sending\n");
+        CleanupAndInsertCmd(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Set command sequence number */
+    Adapter->SeqNum++;
+    CmdPtr->SeqNum = wlan_cpu_to_le16(Adapter->SeqNum);
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+    Adapter->CurCmd = CmdNode;
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+    Adapter->CurCmdRetCode = 0;
+
+    Command = wlan_le16_to_cpu(CmdPtr->Command);
+    CmdSize = wlan_le16_to_cpu(CmdPtr->Size);
+
+    CmdNode->CmdWaitQWoken = FALSE;
+
+    ret = sbi_host_to_card(priv, MVMS_CMD, (u8 *) CmdPtr, CmdSize);
+
+    /* clear TxDone interrupt bit */
+    OS_INT_DISABLE;
+    Adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
+    OS_INT_RESTORE;
+
+    if (ret != 0) {
+        PRINTM(ERROR, "DNLD_CMD: Host to Card Failed\n");
+        /* set error code that will be transferred back to PrepareAndSendCommand() */
+        Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
+        CleanupAndInsertCmd(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+        Adapter->dbg.num_cmd_host_to_card_failure++;
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Save the last command id and action to debug log */
+    Adapter->dbg.LastCmdIndex = (Adapter->dbg.LastCmdIndex + 1) % DBG_CMD_NUM;
+    Adapter->dbg.LastCmdId[Adapter->dbg.LastCmdIndex] = Command;
+    Adapter->dbg.LastCmdAct[Adapter->dbg.LastCmdIndex] =
+        wlan_le16_to_cpu(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN));
+
+    PRINTM(CMND, "DNLD_CMD: 0x%x, act 0x%x, len %d, seqno %d @ %lu\n",
+           Command, wlan_le16_to_cpu(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN)),
+           CmdSize, wlan_le16_to_cpu(CmdPtr->SeqNum), os_time_get());
+    DBG_HEXDUMP(CMD_D, "DNLD_CMD", CmdNode->BufVirtualAddr, CmdSize);
+
+    /* Setup the timer after transmit command */
+    if (Command == HostCmd_CMD_802_11_SCAN
+        || Command == HostCmd_CMD_802_11_DEAUTHENTICATE
+        || Command == HostCmd_CMD_802_11_ASSOCIATE
+        || Command == HostCmd_CMD_WMM_ADDTS_REQ) {
+        ModTimer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_10S);
+    } else {
+        ModTimer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_5S);
+    }
+
+    Adapter->CommandTimerIsSet = TRUE;
+
+    if (Command == HostCmd_CMD_802_11_DEEP_SLEEP) {
+        if (Adapter->IntCounter || Adapter->CurrentTxSkb)
+            PRINTM(INFO, "DNLD_CMD: DS- IntCnt=%d CurTxSkb=%s\n",
+                   Adapter->IntCounter, (Adapter->CurrentTxSkb) ? "Y" : "N");
+
+        if (Adapter->IntCounter) {
+            OS_INT_DISABLE;
+            Adapter->IntCounterSaved = Adapter->IntCounter;
+            Adapter->IntCounter = 0;
+            OS_INT_RESTORE;
+        }
+        if (Adapter->CurrentTxSkb) {
+            kfree_skb(Adapter->CurrentTxSkb);
+            OS_INT_DISABLE;
+            Adapter->CurrentTxSkb = NULL;
+            OS_INT_RESTORE;
+            priv->stats.tx_dropped++;
+        }
+        /* 1. change the PS state to DEEP_SLEEP
+         * 2. since there is no response for this command, so 
+         *    delete the command timer and free the Node. */
+
+        Adapter->IsDeepSleep = TRUE;
+
+        CleanupAndInsertCmd(priv, CmdNode);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+        if (Adapter->CommandTimerIsSet) {
+            CancelTimer(&Adapter->MrvDrvCommandTimer);
+            Adapter->CommandTimerIsSet = FALSE;
+        }
+
+        if (!Adapter->IsAutoDeepSleepEnabled
+            || (Adapter->bHostSleepConfigured &&
+                (Adapter->HSCfg.gpio != HOST_SLEEP_CFG_WAKEUP_THRU_INTERFACE))
+            )
+            /* stop clock to save more power */
+            sbi_set_bus_clock(priv, FALSE);
+
+        if (Adapter->IsAutoDeepSleepEnabled) {
+            Adapter->bWakeupDevRequired = TRUE;
+            /* For auto deep sleep mode, after entering deep sleep state, 
+             * dnld_sent flag should be cleared so that the commands in 
+             * pending queue can be handled by main thread. */
+            priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+        }
+
+        if (Adapter->bHostSleepConfigured) {
+            Adapter->bWakeupDevRequired = TRUE;
+            wlan_host_sleep_activated_event(priv);
+        }
+
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of mac_control.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd		A pointer to HostCmd_DS_COMMAND structure
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_mac_control(wlan_private * priv,
+                     HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    HostCmd_DS_MAC_CONTROL *mac = &cmd->params.macctrl;
+    u16 Action = *((u16 *) InfoBuf);
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
+    mac->Action = wlan_cpu_to_le16(Action);
+
+    PRINTM(INFO, "wlan_cmd_mac_control(): Action=0x%X Size=%d\n",
+           mac->Action, cmd->Size);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function inserts command node to CmdFreeQ
+ *  after cleans it.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param pTempCmd	A pointer to CmdCtrlNode structure
+ *  @return 		n/a
+ */
+void
+CleanupAndInsertCmd(wlan_private * priv, CmdCtrlNode * pTempCmd)
+{
+    ulong flags;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!pTempCmd)
+        goto done;
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+    CleanUpCmdCtrlNode(pTempCmd);
+    list_add_tail((struct list_head *) pTempCmd, &Adapter->CmdFreeQ);
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+  done:
+    LEAVE();
+}
+
+/** 
+ *  @brief This function prepare the command before send to firmware.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd_no	command number
+ *  @param cmd_action	command action: GET or SET
+ *  @param wait_option	wait option: wait response or not
+ *  @param cmd_oid	cmd oid: treated as sub command
+ *  @param pdata_buf	A pointer to informaion buffer
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+PrepareAndSendCommand(wlan_private * priv,
+                      u16 cmd_no,
+                      u16 cmd_action,
+                      u16 wait_option, WLAN_OID cmd_oid, void *pdata_buf)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    CmdCtrlNode *CmdNode;
+    HostCmd_DS_COMMAND *CmdPtr;
+
+    ENTER();
+
+    if (!Adapter) {
+        PRINTM(ERROR, "PREP_CMD: Adapter is Null\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (Adapter->SurpriseRemoved) {
+        PRINTM(ERROR, "PREP_CMD: Card is Removed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    CmdNode = GetFreeCmdCtrlNode(priv);
+
+    if (CmdNode == NULL) {
+        PRINTM(MSG, "PREP_CMD: No free CmdNode\n");
+
+        /* Wake up main thread to execute next command */
+        wake_up_interruptible(&priv->MainThread.waitQ);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    SetCmdCtrlNode(priv, CmdNode, cmd_oid, wait_option, pdata_buf);
+
+    CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+
+    if (!CmdPtr) {
+        PRINTM(MSG, "PREP_CMD: BufVirtualAddr of CmdNode is NULL\n");
+        CleanupAndInsertCmd(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    CmdPtr->Command = cmd_no;
+    CmdPtr->Result = 0;
+
+    TX_EVENT_FLAGS_SET(&CmdNode->cmdwait_q, 0, TX_AND);
+    switch (cmd_no) {
+    case HostCmd_CMD_GET_HW_SPEC:
+        ret = wlan_cmd_hw_spec(priv, CmdPtr);
+        break;
+    case HostCmd_CMD_802_11_PS_MODE:
+        ret = wlan_cmd_802_11_ps_mode(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_SCAN:
+        ret = wlan_cmd_802_11_scan(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_MAC_CONTROL:
+        ret = wlan_cmd_mac_control(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_ASSOCIATE:
+        ret = wlan_cmd_802_11_associate(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_DEAUTHENTICATE:
+        ret = wlan_cmd_802_11_deauthenticate(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_SET_WEP:
+        ret = wlan_cmd_802_11_set_wep(priv, CmdPtr, cmd_oid);
+        break;
+
+    case HostCmd_CMD_802_11_AD_HOC_START:
+        ret = wlan_cmd_802_11_ad_hoc_start(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_RESET:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
+        break;
+
+    case HostCmd_CMD_802_11_GET_LOG:
+        ret = wlan_cmd_802_11_get_log(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_SNMP_MIB:
+        ret = wlan_cmd_802_11_snmp_mib(priv, CmdPtr,
+                                       cmd_action, cmd_oid, pdata_buf);
+        break;
+
+    case HostCmd_CMD_MAC_REG_ACCESS:
+    case HostCmd_CMD_BBP_REG_ACCESS:
+    case HostCmd_CMD_RF_REG_ACCESS:
+        ret = wlan_cmd_reg_access(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RF_CHANNEL:
+        ret = wlan_cmd_802_11_rf_channel(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RF_TX_POWER:
+        ret = wlan_cmd_802_11_rf_tx_power(priv, CmdPtr,
+                                          cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RADIO_CONTROL:
+        ret = wlan_cmd_802_11_radio_control(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_RF_ANTENNA:
+        ret = wlan_cmd_802_11_rf_antenna(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RATE_ADAPT_RATESET:
+        ret = wlan_cmd_802_11_rate_adapt_rateset(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_MAC_MULTICAST_ADR:
+        ret = wlan_cmd_mac_multicast_adr(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_AD_HOC_JOIN:
+        ret = wlan_cmd_802_11_ad_hoc_join(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RSSI:
+        ret = wlan_cmd_802_11_rssi(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_AD_HOC_STOP:
+        ret = wlan_cmd_802_11_ad_hoc_stop(priv, CmdPtr);
+        break;
+    case HostCmd_CMD_802_11_KEY_MATERIAL:
+        ret = wlan_cmd_802_11_key_material(priv, CmdPtr,
+                                           cmd_action, cmd_oid, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_MAC_ADDRESS:
+        ret = wlan_cmd_802_11_mac_address(priv, CmdPtr, cmd_action);
+        break;
+    case HostCmd_CMD_802_11_CAL_DATA_EXT:
+        ret = wlan_cmd_802_11_cal_data_ext(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_DEEP_SLEEP:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size = wlan_cpu_to_le16((u16)
+                                        (sizeof
+                                         (HostCmd_DS_802_11_DEEP_SLEEP)));
+        break;
+
+    case HostCmd_CMD_802_11_HOST_SLEEP_CFG:
+        ret = wlan_cmd_802_11_host_sleep_cfg(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_WAKEUP_CONFIRM:
+    case HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
+        break;
+
+    case HostCmd_CMD_802_11_EEPROM_ACCESS:
+        ret = wlan_cmd_802_11_eeprom_access(priv, CmdPtr,
+                                            cmd_action, pdata_buf);
+        break;
+
+#ifdef MFG_CMD_SUPPORT
+    case HostCmd_CMD_MFG_COMMAND:
+        ret = wlan_cmd_mfg_cmd(priv, CmdPtr, pdata_buf);
+        break;
+#endif
+
+    case HostCmd_CMD_802_11D_DOMAIN_INFO:
+        ret = wlan_cmd_802_11d_domain_info(priv, CmdPtr, cmd_no, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_SLEEP_PARAMS:
+        ret = wlan_cmd_802_11_sleep_params(priv, CmdPtr, cmd_action);
+        break;
+    case HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE:
+        ret = wlan_cmd_802_11_bca_timeshare(priv, CmdPtr,
+                                            cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_INACTIVITY_TIMEOUT:
+        ret = wlan_cmd_802_11_inactivity_timeout(priv, CmdPtr,
+                                                 cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+        ret = wlan_cmd_802_11_bg_scan_config(priv, CmdPtr,
+                                             cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+        ret = wlan_cmd_802_11_bg_scan_query(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_FW_WAKE_METHOD:
+        ret = wlan_cmd_802_11_fw_wakeup_method(priv, CmdPtr,
+                                               cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_WMM_GET_STATUS:
+        ret = wlan_cmd_wmm_get_status(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_WMM_ADDTS_REQ:
+        ret = wlan_cmd_wmm_addts_req(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_DELTS_REQ:
+        ret = wlan_cmd_wmm_delts_req(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_QUEUE_CONFIG:
+        ret = wlan_cmd_wmm_queue_config(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_QUEUE_STATS:
+        ret = wlan_cmd_wmm_queue_stats(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_TX_PKT_STATS:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_TX_PKT_STATS);
+        CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_TPC_CFG:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TPC_CFG);
+        CmdPtr->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_TPC_CFG) + S_DS_GEN);
+
+        memmove(&CmdPtr->params.tpccfg,
+                pdata_buf, sizeof(HostCmd_DS_802_11_TPC_CFG));
+        CmdPtr->params.tpccfg.Action =
+            wlan_cpu_to_le16(CmdPtr->params.tpccfg.Action);
+
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_LED_CONTROL:
+        {
+            HostCmd_DS_802_11_LED_CTRL *pLedCtrl = &CmdPtr->params.ledgpio;
+            MrvlIEtypes_LedGpio_t *gpio = &pLedCtrl->LedGpio;
+            MrvlIEtypes_LedBehavior_t *pLedBehavior = pLedCtrl->LedBehavior;
+
+            memmove(&CmdPtr->params.ledgpio,
+                    pdata_buf, sizeof(HostCmd_DS_802_11_LED_CTRL));
+
+            CmdPtr->Command =
+                wlan_cpu_to_le16(HostCmd_CMD_802_11_LED_CONTROL);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+            CmdPtr->Size = wlan_cpu_to_le16(gpio->Header.Len + S_DS_GEN
+                                            +
+                                            ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+
+            pLedCtrl->Action = wlan_cpu_to_le16(pLedCtrl->Action);
+            pLedCtrl->LedNums = wlan_cpu_to_le16(pLedCtrl->LedNums);
+
+            gpio->Header.Type = wlan_cpu_to_le16(gpio->Header.Type);
+            gpio->Header.Len = wlan_cpu_to_le16(gpio->Header.Len);
+
+            pLedBehavior->Header.Type =
+                wlan_cpu_to_le16(pLedBehavior->Header.Type);
+            pLedBehavior->Header.Len =
+                wlan_cpu_to_le16(pLedBehavior->Header.Len);
+
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        }
+    case HostCmd_CMD_802_11_SLEEP_PERIOD:
+        ret = wlan_cmd_802_11_sleep_period(priv, CmdPtr,
+                                           cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_GET_TSF:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_TSF);
+        CmdPtr->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_TSF)
+                                        + S_DS_GEN);
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_TX_RATE_QUERY:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+        CmdPtr->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+        Adapter->TxRate = 0;
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+        ret =
+            wlan_cmd_802_11_IBSS_Coalesced_Status(priv, CmdPtr, cmd_action,
+                                                  pdata_buf);
+        break;
+
+    case HostCmd_CMD_SDIO_PULL_CTRL:
+        {
+            HostCmd_DS_SDIO_PULL_CTRL *pSdiopullctl =
+                &CmdPtr->params.sdiopullctl;
+
+            CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_PULL_CTRL);
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_SDIO_PULL_CTRL) +
+                                 S_DS_GEN);
+
+            memcpy(pSdiopullctl, pdata_buf,
+                   sizeof(HostCmd_DS_SDIO_PULL_CTRL));
+            pSdiopullctl->Action = wlan_cpu_to_le16(pSdiopullctl->Action);
+            pSdiopullctl->PullUp = wlan_cpu_to_le16(pSdiopullctl->PullUp);
+            pSdiopullctl->PullDown = wlan_cpu_to_le16(pSdiopullctl->PullDown);
+
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        }
+
+    case HostCmd_CMD_802_11_LDO_CONFIG:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_LDO_CONFIG) + S_DS_GEN);
+        memcpy(&CmdPtr->params.ldocfg, pdata_buf,
+               sizeof(HostCmd_DS_802_11_LDO_CONFIG));
+        CmdPtr->params.ldocfg.Action =
+            wlan_cpu_to_le16(CmdPtr->params.ldocfg.Action);
+        CmdPtr->params.ldocfg.PMSource =
+            wlan_cpu_to_le16(CmdPtr->params.ldocfg.PMSource);
+        break;
+
+    case HostCmd_CMD_VERSION_EXT:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        memcpy(&CmdPtr->params, pdata_buf, sizeof(HostCmd_DS_VERSION_EXT));
+        CmdPtr->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT)
+                                        + S_DS_GEN);
+        break;
+
+    default:
+        PRINTM(INFO, "PREP_CMD: unknown command- %#x\n", cmd_no);
+        ret = WLAN_STATUS_FAILURE;
+        break;
+    }
+
+    /* return error, since the command preparation failed */
+    if (ret != WLAN_STATUS_SUCCESS) {
+        PRINTM(ERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
+        CleanupAndInsertCmd(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    PRINTM(CMND, "PREP_CMD: 0x%x\n", cmd_no);
+
+    CmdNode->CmdWaitQWoken = FALSE;
+    QueueCmd(Adapter, CmdNode, TRUE);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+    if (wait_option & HostCmd_OPTION_WAITFORRSP) {
+        PRINTM(INFO, "PREP_CMD: Wait for CMD response...\n");
+        wait_event_interruptible(CmdNode->cmdwait_q, CmdNode->CmdWaitQWoken);
+
+        if (Adapter->CurCmdRetCode) {
+            PRINTM(INFO, "PREP_CMD: Command failed with return code=%d\n",
+                   Adapter->CurCmdRetCode);
+            Adapter->CurCmdRetCode = 0;
+            ret = WLAN_STATUS_FAILURE;
+        }
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function allocates the command buffer and link
+ *  it to command free queue.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+AllocateCmdBuffer(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u32 ulBufSize;
+    u32 i;
+    CmdCtrlNode *TempCmdArray;
+    u8 *pTempVirtualAddr;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* Allocate and initialize CmdCtrlNode */
+    ulBufSize = sizeof(CmdCtrlNode) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+    if (!(TempCmdArray = kmalloc(ulBufSize, GFP_KERNEL))) {
+        PRINTM(INFO, "ALLOC_CMD_BUF: Failed to allocate TempCmdArray\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    Adapter->CmdArray = TempCmdArray;
+    memset(Adapter->CmdArray, 0, ulBufSize);
+
+    /* Allocate and initialize command buffers */
+    ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER;
+    for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+        if (!(pTempVirtualAddr = kmalloc(ulBufSize, GFP_KERNEL))) {
+            PRINTM(INFO, "ALLOC_CMD_BUF: pTempVirtualAddr: out of memory\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        memset(pTempVirtualAddr, 0, ulBufSize);
+
+        /* Update command buffer virtual */
+        TempCmdArray[i].BufVirtualAddr = pTempVirtualAddr;
+    }
+
+    for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+        init_waitqueue_head(&TempCmdArray[i].cmdwait_q);
+        CleanupAndInsertCmd(priv, &TempCmdArray[i]);
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function frees the command buffer.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+FreeCmdBuffer(wlan_private * priv)
+{
+    u32 ulBufSize;
+    UINT i;
+    CmdCtrlNode *TempCmdArray;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* need to check if cmd array is allocated or not */
+    if (Adapter->CmdArray == NULL) {
+        PRINTM(INFO, "FREE_CMD_BUF: CmdArray is Null\n");
+        goto done;
+    }
+
+    TempCmdArray = Adapter->CmdArray;
+
+    /* Release shared memory buffers */
+    ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER;
+    for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+        if (TempCmdArray[i].BufVirtualAddr) {
+            PRINTM(INFO, "Free all the array\n");
+            kfree(TempCmdArray[i].BufVirtualAddr);
+            TempCmdArray[i].BufVirtualAddr = NULL;
+        }
+    }
+
+    /* Release CmdCtrlNode */
+    if (Adapter->CmdArray) {
+        PRINTM(INFO, "Free CmdArray\n");
+        kfree(Adapter->CmdArray);
+        Adapter->CmdArray = NULL;
+    }
+
+  done:
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function gets a free command node if available in
+ *  command free queue.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @return CmdCtrlNode A pointer to CmdCtrlNode structure or NULL
+ */
+CmdCtrlNode *
+GetFreeCmdCtrlNode(wlan_private * priv)
+{
+    CmdCtrlNode *TempNode;
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+
+    ENTER();
+
+    if (!Adapter)
+        return NULL;
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+
+    if (!list_empty(&Adapter->CmdFreeQ)) {
+        TempNode = (CmdCtrlNode *) Adapter->CmdFreeQ.next;
+        list_del((struct list_head *) TempNode);
+    } else {
+        PRINTM(WARN, "GET_CMD_NODE: CmdCtrlNode is not available\n");
+        TempNode = NULL;
+    }
+
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    if (TempNode) {
+        CleanUpCmdCtrlNode(TempNode);
+    }
+
+    LEAVE();
+    return TempNode;
+}
+
+/** 
+ *  @brief This function cleans command node.
+ *  
+ *  @param pTempNode	A pointer to CmdCtrlNode structure
+ *  @return 		n/a
+ */
+void
+CleanUpCmdCtrlNode(CmdCtrlNode * pTempNode)
+{
+    ENTER();
+
+    if (!pTempNode)
+        return;
+    pTempNode->CmdWaitQWoken = TRUE;
+    wake_up_interruptible(&pTempNode->cmdwait_q);
+    pTempNode->Status = 0;
+    pTempNode->cmd_oid = (WLAN_OID) 0;
+    pTempNode->wait_option = 0;
+    pTempNode->CmdFlags = 0;
+    pTempNode->pdata_buf = NULL;
+
+    if (pTempNode->BufVirtualAddr != NULL)
+        memset(pTempNode->BufVirtualAddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function initializes the command node.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param pTempNode	A pointer to CmdCtrlNode structure
+ *  @param cmd_oid	cmd oid: treated as sub command
+ *  @param wait_option	wait option: wait response or not
+ *  @param pdata_buf	A pointer to informaion buffer
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+void
+SetCmdCtrlNode(wlan_private * priv,
+               CmdCtrlNode * pTempNode,
+               WLAN_OID cmd_oid, u16 wait_option, void *pdata_buf)
+{
+    ENTER();
+
+    if (!pTempNode)
+        return;
+
+    pTempNode->cmd_oid = cmd_oid;
+    pTempNode->wait_option = wait_option;
+    pTempNode->pdata_buf = pdata_buf;
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function executes next command in command
+ *  pending queue. It will put fimware back to PS mode
+ *  if applicable.
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+ExecuteNextCommand(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    CmdCtrlNode *CmdNode = NULL;
+    HostCmd_DS_COMMAND *CmdPtr;
+    ulong flags;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!Adapter) {
+        PRINTM(MSG, "EXEC_NEXT_CMD: Adapter is NULL\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+
+    if (Adapter->CurCmd) {
+        PRINTM(MSG, "EXEC_NEXT_CMD: there is command in processing!\n");
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (!list_empty(&Adapter->CmdPendingQ)) {
+        CmdNode = (CmdCtrlNode *)
+            Adapter->CmdPendingQ.next;
+    }
+
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    if (CmdNode) {
+        CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+
+        if (Is_Command_Allowed_In_PS(CmdPtr->Command)) {
+            if ((Adapter->PSState == PS_STATE_SLEEP)
+                || (Adapter->PSState == PS_STATE_PRE_SLEEP)
+                ) {
+                PRINTM(INFO,
+                       "EXEC_NEXT_CMD: Cannot send cmd 0x%x in PSState %d\n",
+                       CmdPtr->Command, Adapter->PSState);
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            PRINTM(INFO, "EXEC_NEXT_CMD: OK to send command "
+                   "0x%x in PSState %d\n", CmdPtr->Command, Adapter->PSState);
+        } else if (Adapter->PSState != PS_STATE_FULL_POWER) {
+            /*
+             * 1. Non-PS command: 
+             * Queue it. set NeedToWakeup to TRUE if current state 
+             * is SLEEP, otherwise call PSWakeup to send Exit_PS.
+             * 2. PS command but not Exit_PS: 
+             * Ignore it.
+             * 3. PS command Exit_PS:
+             * Set NeedToWakeup to TRUE if current state is SLEEP, 
+             * otherwise send this command down to firmware
+             * immediately.
+             */
+            if (CmdPtr->Command !=
+                wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE)) {
+                /*  Prepare to send Exit PS,
+                 *  this non PS command will be sent later */
+                if ((Adapter->PSState == PS_STATE_SLEEP)
+                    || (Adapter->PSState == PS_STATE_PRE_SLEEP)
+                    ) {
+                    /* w/ new scheme, it will not reach here.
+                       since it is blocked in main_thread. */
+                    Adapter->NeedToWakeup = TRUE;
+                } else
+                    PSWakeup(priv, 0);
+
+                ret = WLAN_STATUS_SUCCESS;
+                goto done;
+            } else {
+                /*
+                 * PS command. Ignore it if it is not Exit_PS. 
+                 * otherwise send it down immediately.
+                 */
+                HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode;
+
+                PRINTM(INFO, "EXEC_NEXT_CMD: PS cmd- Action=0x%x\n",
+                       psm->Action);
+                if (psm->Action != wlan_cpu_to_le16(HostCmd_SubCmd_Exit_PS)) {
+                    PRINTM(INFO, "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+                    list_del((struct list_head *) CmdNode);
+                    CleanupAndInsertCmd(priv, CmdNode);
+
+                    ret = WLAN_STATUS_SUCCESS;
+                    goto done;
+                }
+
+                if ((Adapter->PSState == PS_STATE_SLEEP)
+                    || (Adapter->PSState == PS_STATE_PRE_SLEEP)
+                    ) {
+                    PRINTM(INFO,
+                           "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+                    list_del((struct list_head *) CmdNode);
+                    CleanupAndInsertCmd(priv, CmdNode);
+                    Adapter->NeedToWakeup = TRUE;
+
+                    ret = WLAN_STATUS_SUCCESS;
+                    goto done;
+                }
+
+                PRINTM(INFO, "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+            }
+        }
+        list_del((struct list_head *) CmdNode);
+        DownloadCommandToStation(priv, CmdNode);
+    } else {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            /*
+             * check if in power save mode, if yes, put the device back
+             * to PS mode
+             */
+            if ((Adapter->PSMode != Wlan802_11PowerModeCAM) &&
+                (Adapter->PSState == PS_STATE_FULL_POWER)) {
+                if (Adapter->SecInfo.WPAEnabled
+                    || Adapter->SecInfo.WPA2Enabled) {
+                    if (Adapter->IsGTK_SET) {
+                        PRINTM(INFO, "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+                               " go back to PS_SLEEP");
+                        PSSleep(priv, 0);
+                    }
+                } else {
+                    if ((Adapter->InfrastructureMode != Wlan802_11IBSS)
+                        || Adapter->CurBssParams.BSSDescriptor.ATIMWindow) {
+                        PRINTM(INFO, "EXEC_NEXT_CMD: Command PendQ is empty,"
+                               " go back to PS_SLEEP");
+                        PSSleep(priv, 0);
+                    }
+                }
+            }
+        } else {
+            /*
+             * check if in auto deep sleep mode, if yes, put the device back
+             * to DS mode
+             */
+            if (Adapter->IsAutoDeepSleepEnabled && !Adapter->IntCounter) {
+                PRINTM(INFO, "Entering Auto Deep Sleep mode...\n");
+                ret = PrepareAndSendCommand(priv,
+                                            HostCmd_CMD_802_11_DEEP_SLEEP, 0,
+                                            0, 0, NULL);
+            }
+        }
+        /* The hs_activate command is sent when Host Sleep is configured
+           and de-activated in full power mode. */
+        if (Adapter->bHostSleepConfigured && !Adapter->HS_Activated
+            && ((Adapter->MediaConnectStatus == WlanMediaStateConnected)
+                || (!Adapter->IsAutoDeepSleepEnabled))
+            && (((Adapter->PSMode == Wlan802_11PowerModeCAM)
+                 && (Adapter->PSState == PS_STATE_FULL_POWER))
+                || ((Adapter->InfrastructureMode == Wlan802_11IBSS)
+                    && !Adapter->CurBssParams.BSSDescriptor.ATIMWindow)
+            )) {
+            ret = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE,
+                                        0, 0, 0, NULL);
+        }
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ *  
+ *  @param FunctionContext    A pointer to FunctionContext
+ *  @return 	   n/a
+ */
+void
+MrvDrvCommandTimerFunction(void *FunctionContext)
+{
+    wlan_private *priv = (wlan_private *) FunctionContext;
+    wlan_adapter *Adapter = priv->adapter;
+    CmdCtrlNode *pTempNode;
+    HostCmd_DS_COMMAND *CmdPtr;
+
+    ENTER();
+
+    PRINTM(CMND, "Command timeout.\n");
+
+    Adapter->CommandTimerIsSet = FALSE;
+
+    if (!Adapter->num_cmd_timeout)
+        Adapter->dbg.num_cmd_timeout++;
+
+    pTempNode = Adapter->CurCmd;
+
+    if (pTempNode == NULL) {
+        PRINTM(INFO, "CurCmd Empty\n");
+        goto exit;
+    }
+
+    CmdPtr = (HostCmd_DS_COMMAND *) pTempNode->BufVirtualAddr;
+    if (CmdPtr == NULL) {
+        goto exit;
+    }
+
+    if (CmdPtr->Size) {
+        Adapter->dbg.TimeoutCmdId = wlan_cpu_to_le16(CmdPtr->Command);
+        Adapter->dbg.TimeoutCmdAct =
+            wlan_cpu_to_le16(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN));
+        PRINTM(CMND, "Timeout cmd = 0x%x, act = 0x%x\n",
+               Adapter->dbg.TimeoutCmdId, Adapter->dbg.TimeoutCmdAct);
+    }
+#define MAX_CMD_TIMEOUT_COUNT	5
+    Adapter->num_cmd_timeout++;
+    if (Adapter->num_cmd_timeout > MAX_CMD_TIMEOUT_COUNT) {
+        PRINTM(FATAL, "num_cmd_timeout=%d\n", Adapter->num_cmd_timeout);
+        goto exit;
+    }
+
+    /* Restart the timer to trace command response again */
+    ModTimer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_1S);
+    Adapter->CommandTimerIsSet = TRUE;
+
+    /* Wake up main thread to read int status register */
+    Adapter->IntCounter++;
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+  exit:
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function sends sleep confirm command to firmware.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param cmdptr  A pointer to the command
+ *  @param size	   the size of command
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+SendConfirmSleep(wlan_private * priv, u8 * CmdPtr, u16 size)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    static u32 i = 0;
+
+    ENTER();
+
+    HEXDUMP("SLEEP_CFM", CmdPtr, size);
+
+    ret = sbi_host_to_card(priv, MVMS_CMD, CmdPtr, size);
+    priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+
+    if (ret) {
+        PRINTM(MSG, "SLEEP_CFM: sbi_host_to_card() failed\n");
+        Adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+    } else {
+        //sdio_clear_imask(((mmc_card_t) ((priv->wlan_dev).card))->ctrlr);
+        Adapter->PSState = PS_STATE_SLEEP;
+        if (Adapter->bHostSleepConfigured &&
+            (Adapter->sleep_period.period == 0)) {
+            Adapter->bWakeupDevRequired = TRUE;
+#define SDIO_CLK_300KHZ 300
+            sd_set_clock(priv, SDIO_CLK_300KHZ);        /* set the clock to the lowest frequency */
+            wlan_host_sleep_activated_event(priv);
+        }
+#define NUM_SC_PER_LINE		16
+        if (++i % NUM_SC_PER_LINE == 0) {
+            PRINTM(EVENT, "+\n");
+        } else {
+            PRINTM(EVENT, "+");
+        }
+
+        /* check if interrupt is received after sleep confirm */
+        if (Adapter->IntCounter) {
+            PRINTM(INFO, "SLEEP_CFM: After sent, IntCnt=%d\n",
+                   Adapter->IntCounter);
+            Adapter->PSState = PS_STATE_AWAKE;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function sends Enter_PS command to firmware.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param wait_option	wait response or not
+ *  @return 	   	n/a 
+ */
+void
+PSSleep(wlan_private * priv, int wait_option)
+{
+
+    ENTER();
+
+    PrepareAndSendCommand(priv, HostCmd_CMD_802_11_PS_MODE,
+                          HostCmd_SubCmd_Enter_PS, wait_option, 0, NULL);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function sends Eixt_PS command to firmware.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param wait_option	wait response or not
+ *  @return 	   	n/a 
+ */
+void
+PSWakeup(wlan_private * priv, int wait_option)
+{
+    WLAN_802_11_POWER_MODE LocalPSMode;
+
+    ENTER();
+
+    LocalPSMode = Wlan802_11PowerModeCAM;
+
+    PrepareAndSendCommand(priv, HostCmd_CMD_802_11_PS_MODE,
+                          HostCmd_SubCmd_Exit_PS,
+                          wait_option, 0, &LocalPSMode);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function checks condition and prepares to
+ *  send sleep confirm command to firmware if ok.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param PSMode  	Power Saving mode
+ *  @return 	   	n/a 
+ */
+void
+PSConfirmSleep(wlan_private * priv, u16 PSMode)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd && !Adapter->IntCounter) {
+        SendConfirmSleep(priv, (u8 *) & Adapter->PSConfirmSleep,
+                         sizeof(PS_CMD_ConfirmSleep));
+
+        os_start_queue(priv);
+    } else {
+        PRINTM(INFO, "Delay Sleep Confirm (%s%s%s)\n",
+               (priv->wlan_dev.dnld_sent) ? "D" : "",
+               (Adapter->CurCmd) ? "C" : "",
+               (Adapter->IntCounter) ? "I" : "");
+    }
+
+    LEAVE();
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_cmdresp.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_cmdresp.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_cmdresp.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_cmdresp.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1579 @@
+/** @file wlan_cmdresp.c
+  * @brief This file contains the handling of command
+  * responses as well as events generated by firmware.
+  *
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  *  
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/10/05: Add Doxygen format comments
+	11/11/05: Add support for WMM Status change event
+	12/13/05: Add Proprietary periodic sleep support
+	12/23/05: Fix bug in adhoc start where the current index was
+	          not properly being assigned before it was used.
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join structures.
+	          Update assoc response handling; entire IEEE response returned
+	04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+	04/10/06: Add hostcmd generic API
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	05/04/06: Add IBSS coalescing related new hostcmd response handling
+	05/08/06: Remove PermanentAddr from Adapter
+	06/08/06: Remove function HandleMICFailureEvent()
+	08/29/06: Add ledgpio private command
+********************************************************/
+
+#include	"include.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function handles disconnect event. it
+ *  reports disconnect to upper layer, clean tx/rx packets,
+ *  reset link state etc.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void
+MacEventDisconnected(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    union iwreq_data wrqu;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus != WlanMediaStateConnected)
+        return;
+
+    PRINTM(INFO, "Handles disconnect event.\n");
+
+    /* Free Tx and Rx packets, report disconnect to upper layer */
+    wlan_clean_txrx(priv);
+
+    memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    /* reset SNR/NF/RSSI values */
+    memset(Adapter->SNR, 0x00, sizeof(Adapter->SNR));
+    memset(Adapter->NF, 0x00, sizeof(Adapter->NF));
+    memset(Adapter->RSSI, 0x00, sizeof(Adapter->RSSI));
+    memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
+    memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
+    Adapter->nextSNRNF = 0;
+    Adapter->numSNRNF = 0;
+    Adapter->RxPDRate = 0;
+    PRINTM(INFO, "Current SSID=%s, Ssid Length=%u\n",
+           Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid,
+           Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength);
+    PRINTM(INFO, "Previous SSID=%s, Ssid Length=%u\n",
+           Adapter->PreviousSSID.Ssid, Adapter->PreviousSSID.SsidLength);
+
+    Adapter->SecInfo.WPAEnabled = FALSE;
+    Adapter->SecInfo.WPA2Enabled = FALSE;
+    Adapter->Wpa_ie_len = 0;
+    Adapter->SecInfo.EncryptionMode = CIPHER_NONE;
+
+    Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
+
+    Adapter->AdhocLinkSensed = FALSE;
+
+    /* 
+     * memorize the previous SSID and BSSID
+     * it could be used for re-assoc
+     */
+    memcpy(&Adapter->PreviousSSID,
+           &Adapter->CurBssParams.BSSDescriptor.Ssid,
+           sizeof(WLAN_802_11_SSID));
+    memcpy(Adapter->PreviousBSSID,
+           Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+
+    /* need to erase the current SSID and BSSID info */
+    memset(&Adapter->CurBssParams, 0x00, sizeof(Adapter->CurBssParams));
+
+    if (Adapter->PSState != PS_STATE_FULL_POWER) {
+        /* make firmware to exit PS mode */
+        PRINTM(INFO, "Disconnected, so exit PS mode.\n");
+        PSWakeup(priv, 0);
+    }
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function handles link lost, deauth and
+ *  disassoc events.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+static void
+HandleDisconnectEvent(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        MacEventDisconnected(priv);
+#ifdef REASSOCIATION
+        if (Adapter->Reassoc_on == TRUE) {
+            PRINTM(INFO, "RE-ASSOC: trigger the timer\n");
+            Adapter->ReassocTimerIsSet = TRUE;
+            ModTimer(&Adapter->MrvDrvTimer, 0);
+        }
+#endif /* REASSOCIATION */
+    }
+}
+
+/** 
+ *  @brief This function handles the command response of reg_access
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param type	   the type of reg access (MAC, BBP or RF)
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_reg_access(wlan_private * priv, u16 type, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_offset_value *pOffsetValue =
+        (wlan_offset_value *) Adapter->CurCmd->pdata_buf;
+
+    ENTER();
+
+    switch (type) {
+    case HostCmd_RET_MAC_REG_ACCESS:
+        {
+            HostCmd_DS_MAC_REG_ACCESS *reg;
+
+            reg = (HostCmd_DS_MAC_REG_ACCESS *) & resp->params.macreg;
+
+            pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
+            pOffsetValue->value = wlan_le32_to_cpu(reg->Value);
+            break;
+        }
+
+    case HostCmd_RET_BBP_REG_ACCESS:
+        {
+            HostCmd_DS_BBP_REG_ACCESS *reg;
+            reg = (HostCmd_DS_BBP_REG_ACCESS *) & resp->params.bbpreg;
+
+            pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
+            pOffsetValue->value = (u8) reg->Value;
+            break;
+        }
+
+    case HostCmd_RET_RF_REG_ACCESS:
+        {
+            HostCmd_DS_RF_REG_ACCESS *reg;
+            reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rfreg;
+
+            pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
+            pOffsetValue->value = (u8) reg->Value;
+            break;
+        }
+
+    default:
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of get_hw_spec
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_get_hw_spec(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    u32 i;
+    HostCmd_DS_GET_HW_SPEC *hwspec = &resp->params.hwspec;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    Adapter->fwCapInfo = wlan_le32_to_cpu(hwspec->fwCapInfo);
+
+    Adapter->FWReleaseNumber = wlan_le32_to_cpu(hwspec->FWReleaseNumber);
+
+    PRINTM(INFO, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+           Adapter->FWReleaseNumber);
+    PRINTM(INFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+           hwspec->PermanentAddr[0], hwspec->PermanentAddr[1],
+           hwspec->PermanentAddr[2], hwspec->PermanentAddr[3],
+           hwspec->PermanentAddr[4], hwspec->PermanentAddr[5]);
+    PRINTM(INFO, "GET_HW_SPEC: HWIfVersion=0x%X  Version=0x%X\n",
+           wlan_le16_to_cpu(hwspec->HWIfVersion),
+           wlan_le16_to_cpu(hwspec->Version));
+
+    Adapter->RegionCode = wlan_le16_to_cpu(hwspec->RegionCode);
+
+    for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+        /* use the region code to search for the index */
+        if (Adapter->RegionCode == RegionCodeToIndex[i]) {
+            break;
+        }
+    }
+
+    /* if it's unidentified region code, use the default (USA) */
+    if (i >= MRVDRV_MAX_REGION_CODE) {
+        Adapter->RegionCode = 0x10;
+        PRINTM(WARN, "unidentified region code, use the default (USA)\n");
+    }
+
+    if (Adapter->CurrentAddr[0] == 0xff) {
+        memmove(Adapter->CurrentAddr, hwspec->PermanentAddr, ETH_ALEN);
+    }
+    memcpy(priv->wlan_dev.netdev->dev_addr, Adapter->CurrentAddr, ETH_ALEN);
+
+    if (wlan_set_regiontable(priv, Adapter->RegionCode, 0)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (wlan_set_universaltable(priv, 0)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the command response of host_sleep_cfg
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_host_sleep_cfg(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_HOST_SLEEP_CFG *hscfg = &resp->params.hostsleepcfg;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (hscfg->conditions != HOST_SLEEP_CFG_CANCEL) {
+        Adapter->bHostSleepConfigured = TRUE;
+    } else {
+        Adapter->bHostSleepConfigured = FALSE;
+        if (Adapter->PSState == PS_STATE_FULL_POWER && Adapter->HS_Activated) {
+            wlan_host_sleep_deactivated_event(priv);
+        }
+        os_start_queue(priv);
+        os_carrier_on(priv);
+        wmm_start_queue(priv);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the command response of fw_wakeup_method
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_fw_wakeup_method(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &resp->params.fwwakeupmethod;
+    u16 action;
+
+    ENTER();
+
+    action = wlan_le16_to_cpu(fwwm->Action);
+
+    switch (action) {
+    case HostCmd_ACT_GET:
+    case HostCmd_ACT_SET:
+        Adapter->fwWakeupMethod = wlan_le16_to_cpu(fwwm->Method);
+        break;
+    default:
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of sleep_params
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_sleep_params(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_SLEEP_PARAMS *sp = &resp->params.sleep_params;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
+           " extsleepclk=%x\n", sp->Error, sp->Offset,
+           sp->StableTime, sp->CalControl, sp->ExternalSleepClk);
+    Adapter->sp.sp_error = wlan_le16_to_cpu(sp->Error);
+    Adapter->sp.sp_offset = wlan_le16_to_cpu(sp->Offset);
+    Adapter->sp.sp_stabletime = wlan_le16_to_cpu(sp->StableTime);
+    Adapter->sp.sp_calcontrol = wlan_le16_to_cpu(sp->CalControl);
+    Adapter->sp.sp_extsleepclk = wlan_le16_to_cpu(sp->ExternalSleepClk);
+    Adapter->sp.sp_reserved = wlan_le16_to_cpu(sp->Reserved);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of sleep_params
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_sleep_period(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_SLEEP_PERIOD *sp_period = &resp->params.ps_sleeppd;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    Adapter->sleep_period.period = wlan_le16_to_cpu(sp_period->Period);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of bca_timeshare
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_bca_timeshare(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &resp->params.bca_timeshare;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(MSG, "TrafficType=%x TimeShareInterva=%x BTTime=%x\n",
+           bca_ts->TrafficType, bca_ts->TimeShareInterval, bca_ts->BTTime);
+
+    Adapter->bca_ts.TrafficType = wlan_le16_to_cpu(bca_ts->TrafficType);
+    Adapter->bca_ts.TimeShareInterval =
+        wlan_le32_to_cpu(bca_ts->TimeShareInterval);
+    Adapter->bca_ts.BTTime = wlan_le32_to_cpu(bca_ts->BTTime);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of mac_control
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_mac_control(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of set_wep
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_set_wep(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of reset
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_reset(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+    PRINTM(INFO, "HWAC - Reset command successful\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of snmp_mib
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_snmp_mib(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_SNMP_MIB *smib = &resp->params.smib;
+    u16 OID = wlan_le16_to_cpu(smib->OID);
+    u16 QueryType = wlan_le16_to_cpu(smib->QueryType);
+
+    ENTER();
+
+    PRINTM(INFO, "SNMP_RESP: value of the OID = %x, QueryType=%x\n", OID,
+           QueryType);
+    PRINTM(INFO, "SNMP_RESP: Buf size  = %x\n",
+           wlan_le16_to_cpu(smib->BufSize));
+
+    if (QueryType == HostCmd_ACT_GEN_GET) {
+        switch (OID) {
+        case FragThresh_i:
+            priv->adapter->FragThsd =
+                wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
+            PRINTM(INFO, "SNMP_RESP: FragThsd =%u\n",
+                   priv->adapter->FragThsd);
+            break;
+        case RtsThresh_i:
+            priv->adapter->RTSThsd =
+                wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
+            PRINTM(INFO, "SNMP_RESP: RTSThsd =%u\n", priv->adapter->RTSThsd);
+            break;
+        case ShortRetryLim_i:
+            priv->adapter->TxRetryCount =
+                wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
+            PRINTM(INFO, "SNMP_RESP: TxRetryCount =%u\n",
+                   priv->adapter->RTSThsd);
+            break;
+        default:
+            break;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of radio_control
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_radio_control(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of key_material
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_key_material(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_KEY_MATERIAL *pKey = &resp->params.keymaterial;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wlan_le16_to_cpu(pKey->Action) == HostCmd_ACT_SET) {
+        if ((wlan_le16_to_cpu(pKey->KeyParamSet.KeyInfo) &
+             KEY_INFO_TKIP_MCAST)
+            || (wlan_le16_to_cpu(pKey->KeyParamSet.KeyInfo) &
+                KEY_INFO_AES_MCAST)) {
+            PRINTM(INFO, "Key: GTK is set\n");
+            Adapter->IsGTK_SET = TRUE;
+        }
+    }
+
+    memcpy(Adapter->aeskey.KeyParamSet.Key, pKey->KeyParamSet.Key,
+           sizeof(pKey->KeyParamSet.Key));
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of mac_address
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_mac_address(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_MAC_ADDRESS *MacAdd = &resp->params.macadd;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    memcpy(Adapter->CurrentAddr, MacAdd->MacAdd, ETH_ALEN);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rf_tx_power
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rf_tx_power(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 Action = wlan_le16_to_cpu(rtp->Action);
+
+    ENTER();
+
+    Adapter->TxPowerLevel = wlan_le16_to_cpu(rtp->CurrentLevel);
+
+    if (Action == HostCmd_ACT_GET) {
+        Adapter->MaxTxPowerLevel = rtp->MaxPower;
+        Adapter->MinTxPowerLevel = rtp->MinPower;
+    }
+
+    PRINTM(INFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+           Adapter->TxPowerLevel, Adapter->MaxTxPowerLevel,
+           Adapter->MinTxPowerLevel);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rf_antenna
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rf_antenna(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RF_ANTENNA *pAntenna = &resp->params.rant;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 Action = wlan_le16_to_cpu(pAntenna->Action);
+
+    if (Action == HostCmd_ACT_GET_RX)
+        Adapter->RxAntennaMode = wlan_le16_to_cpu(pAntenna->AntennaMode);
+
+    if (Action == HostCmd_ACT_GET_TX)
+        Adapter->TxAntennaMode = wlan_le16_to_cpu(pAntenna->AntennaMode);
+
+    PRINTM(INFO, "RF_ANT_RESP: Action = 0x%x, Mode = 0x%04x\n",
+           Action, wlan_le16_to_cpu(pAntenna->AntennaMode));
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of multicast_address
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_mac_multicast_adr(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rate_adapt_rateset
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RATE_ADAPT_RATESET *rates = &resp->params.rateset;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wlan_le16_to_cpu(rates->Action) == HostCmd_ACT_GET) {
+        Adapter->HWRateDropMode = wlan_le16_to_cpu(rates->HWRateDropMode);
+        Adapter->Threshold = wlan_le16_to_cpu(rates->Threshold);
+        Adapter->FinalRate = wlan_le16_to_cpu(rates->FinalRate);
+        Adapter->RateBitmap = wlan_le16_to_cpu(rates->Bitmap);
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rf_channel
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rf_channel(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RF_CHANNEL *rfchannel = &resp->params.rfchannel;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 Action = wlan_le16_to_cpu(rfchannel->Action);
+    u16 newChannel = wlan_le16_to_cpu(rfchannel->CurrentChannel);
+
+    ENTER();
+
+    if (Action == HostCmd_OPT_802_11_RF_CHANNEL_GET
+        && Adapter->CurBssParams.BSSDescriptor.Channel != newChannel) {
+        PRINTM(INFO, "Channel Switch: %d to %d\n",
+               Adapter->CurBssParams.BSSDescriptor.Channel, newChannel);
+
+        /* Update the channel again */
+        Adapter->CurBssParams.BSSDescriptor.Channel = newChannel;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rssi
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rssi(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RSSI_RSP *rssirsp = &resp->params.rssirsp;
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* store the non average value */
+    Adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = wlan_le16_to_cpu(rssirsp->SNR);
+    Adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+        wlan_le16_to_cpu(rssirsp->NoiseFloor);
+
+    Adapter->SNR[TYPE_BEACON][TYPE_AVG] = wlan_le16_to_cpu(rssirsp->AvgSNR);
+    Adapter->NF[TYPE_BEACON][TYPE_AVG] =
+        wlan_le16_to_cpu(rssirsp->AvgNoiseFloor);
+
+    Adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                 Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+    Adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+                 Adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+    PRINTM(INFO, "Beacon RSSI value = 0x%x\n",
+           Adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/** 
+ *  @brief This function handles the command response of mfg_cmd
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_mfg_cmd(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "MFG command response size = %d\n", resp->Size);
+
+    resp->Size = MIN(resp->Size, MRVDRV_SIZE_OF_CMD_BUFFER);
+    memcpy(Adapter->CurCmd->pdata_buf, (void *) resp, resp->Size);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+#endif /* MFG_CMD_SUPPORT */
+
+/** 
+ *  @brief This function handles the command response of cal_data_ext.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param resp		A pointer to HostCmd_DS_COMMAND
+ *  @return    		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_cal_data_ext(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_CAL_DATA_EXT *pCalDataExt = &resp->params.caldataext;
+
+    ENTER();
+
+    if (wlan_le16_to_cpu(pCalDataExt->Action) == HostCmd_ACT_GEN_GET) {
+        pCalDataExt->Action = wlan_le16_to_cpu(pCalDataExt->Action);
+        pCalDataExt->Revision = wlan_le16_to_cpu(pCalDataExt->Revision);
+        pCalDataExt->CalDataLen = wlan_le16_to_cpu(pCalDataExt->CalDataLen);
+
+        memmove(Adapter->CurCmd->pdata_buf,
+                pCalDataExt, pCalDataExt->CalDataLen + CAL_DATA_HEADER_LEN);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of eeprom_access
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_eeprom_access(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_regrdwr *pBuf =
+        (wlan_ioctl_regrdwr *) Adapter->CurCmd->pdata_buf;
+
+    PRINTM(INFO, "eeprom read len=%x\n",
+           wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount));
+    if (pBuf->NOB < wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)) {
+        pBuf->NOB = 0;
+        PRINTM(INFO, "eeprom read return length is too big\n");
+        return WLAN_STATUS_FAILURE;
+    }
+    pBuf->NOB = wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount);
+    if (pBuf->NOB > 0) {
+        memcpy(&pBuf->Value, (u8 *) & resp->params.rdeeprom.Value, pBuf->NOB);
+        HEXDUMP("EEPROM", (char *) &pBuf->Value, pBuf->NOB);
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of get_log
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_get_log(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_GET_LOG *LogMessage =
+        (HostCmd_DS_802_11_GET_LOG *) & resp->params.glog;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* TODO Convert it to Big Endian before copy */
+    memcpy(&Adapter->LogMsg, LogMessage, sizeof(HostCmd_DS_802_11_GET_LOG));
+    endian_convert_GET_LOG(Adapter->LogMsg);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+static void
+wlan_ret_802_11_IBSS_Coalesced_Status(wlan_private * priv,
+                                      HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_IBSS_Status *IBSSStatusRsp;
+    wlan_adapter *Adapter;
+    union iwreq_data wrqu;
+    u8 nullMac[6] = { 0, 0, 0, 0, 0, 0 };
+
+    Adapter = priv->adapter;
+    IBSSStatusRsp = &(resp->params.ibssCoalescing);
+
+    if (Adapter->CurCmd->pdata_buf)
+        *(int *) Adapter->CurCmd->pdata_buf = IBSSStatusRsp->Enable;
+
+    if (wlan_le16_to_cpu(IBSSStatusRsp->Action) == HostCmd_ACT_SET) {
+        return;
+    }
+
+    PRINTM(INFO, "New BSSID %x:%x:%x:%x:%x:%x\n",
+           IBSSStatusRsp->BSSID[0],
+           IBSSStatusRsp->BSSID[1],
+           IBSSStatusRsp->BSSID[2],
+           IBSSStatusRsp->BSSID[3],
+           IBSSStatusRsp->BSSID[4], IBSSStatusRsp->BSSID[5]);
+
+    /* if rsp has NULL BSSID, Just return.. No Action */
+    if (!memcmp(IBSSStatusRsp->BSSID, nullMac, MRVDRV_ETH_ADDR_LEN)) {
+        PRINTM(MSG, "New BSSID is NULL\n");
+        return;
+    }
+
+    /* if BSSID is diff, Send evnet to Linux */
+    if (memcmp(Adapter->CurBssParams.BSSDescriptor.MacAddress,
+               IBSSStatusRsp->BSSID, ETH_ALEN)) {
+        memcpy((void *) Adapter->CurBssParams.BSSDescriptor.MacAddress,
+               (void *) IBSSStatusRsp->BSSID, MRVDRV_ETH_ADDR_LEN);
+
+        /* Beacon Interval and ATIM window */
+        Adapter->CurBssParams.BSSDescriptor.BeaconPeriod
+            = IBSSStatusRsp->BeaconInterval;
+        Adapter->CurBssParams.BSSDescriptor.ATIMWindow
+            = IBSSStatusRsp->ATIMWindow;
+        //ERP Information
+        Adapter->CurBssParams.BSSDescriptor.ERPFlags =
+            (u8) IBSSStatusRsp->UseGRateProtection;
+
+        memset(&wrqu, 0, sizeof(wrqu));
+        memcpy(wrqu.ap_addr.sa_data,
+               Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+        wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+    }
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function stop tx/rx queue and free skb
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+void
+wlan_clean_txrx(wlan_private * priv)
+{
+    os_stop_queue(priv);
+    os_carrier_off(priv);
+
+    wmm_stop_queue(priv);
+    wmm_cleanup_queues(priv);
+
+    /* Free Tx and Rx packets */
+    os_free_tx_packet(priv);
+    wlan_send_rxskbQ(priv);
+}
+
+/** 
+ *  @brief This function handles the command response
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_process_rx_command(wlan_private * priv)
+{
+    u16 RespCmd;
+    HostCmd_DS_COMMAND *resp;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    ulong flags;
+    u16 Result;
+
+    ENTER();
+
+    /* Now we got response from FW, cancel the command timer */
+    if (Adapter->CommandTimerIsSet) {
+        CancelTimer(&Adapter->MrvDrvCommandTimer);
+        Adapter->CommandTimerIsSet = FALSE;
+    }
+
+    if (!Adapter->CurCmd) {
+        resp = (HostCmd_DS_COMMAND *) priv->wlan_dev.upld_buf;
+        resp->Command = wlan_le16_to_cpu(resp->Command);
+        PRINTM(ERROR, "CMD_RESP: NULL CurCmd, 0x%x\n", resp->Command);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    Adapter->num_cmd_timeout = 0;
+
+    DBG_HEXDUMP(CMD_D, "CMD_RESP", Adapter->CurCmd->BufVirtualAddr,
+                priv->wlan_dev.upld_len);
+
+    resp = (HostCmd_DS_COMMAND *) (Adapter->CurCmd->BufVirtualAddr);
+
+    resp->Command = wlan_le16_to_cpu(resp->Command);
+    resp->Size = wlan_le16_to_cpu(resp->Size);
+    resp->SeqNum = wlan_le16_to_cpu(resp->SeqNum);
+    resp->Result = wlan_le16_to_cpu(resp->Result);
+
+    RespCmd = resp->Command;
+    Result = resp->Result;
+
+    /* Save the last command response to debug log */
+    Adapter->dbg.LastCmdRespIndex =
+        (Adapter->dbg.LastCmdRespIndex + 1) % DBG_CMD_NUM;
+    Adapter->dbg.LastCmdRespId[Adapter->dbg.LastCmdRespIndex] = RespCmd;
+
+    PRINTM(CMND, "CMD_RESP: 0x%x, result %d, len %d, seqno %d @ %lu\n",
+           RespCmd, Result, resp->Size, resp->SeqNum, os_time_get());
+
+    if (!(RespCmd & 0x8000)) {
+        PRINTM(ERROR, "CMD_RESP: Invalid response to command!");
+        Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
+        CleanupAndInsertCmd(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Store the response code to CurCmdRetCode. */
+    Adapter->CurCmdRetCode = resp->Result;
+
+    if (RespCmd == HostCmd_RET_802_11_PS_MODE) {
+        HostCmd_DS_802_11_PS_MODE *psmode;
+
+        psmode = &resp->params.psmode;
+        PRINTM(INFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+               resp->Result, psmode->Action);
+        psmode->Action = wlan_cpu_to_le16(psmode->Action);
+
+        if (Result) {
+            PRINTM(ERROR, "CMD_RESP: PS command failed- %#x \n",
+                   resp->Result);
+            if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+                /* 
+                 * We should not re-try enter-ps command in 
+                 * ad-hoc mode. It takes place in 
+                 * ExecuteNextCommand().
+                 */
+                if (psmode->Action == HostCmd_SubCmd_Enter_PS)
+                    Adapter->PSMode = Wlan802_11PowerModeCAM;
+            }
+        } else if (psmode->Action == HostCmd_SubCmd_Enter_PS) {
+            Adapter->NeedToWakeup = FALSE;
+            Adapter->PSState = PS_STATE_AWAKE;
+            if (Adapter->MediaConnectStatus != WlanMediaStateConnected) {
+                /*
+                 * When Deauth Event received before Enter_PS command
+                 * response, We need to wake up the firmware.
+                 */
+                PRINTM(INFO,
+                       "CMD_RESP: Disconnected, Going to invoke PSWakeup\n");
+                PSWakeup(priv, 0);
+            }
+        } else if (psmode->Action == HostCmd_SubCmd_Exit_PS) {
+            Adapter->NeedToWakeup = FALSE;
+            Adapter->PSState = PS_STATE_FULL_POWER;
+        } else {
+            PRINTM(INFO, "CMD_RESP: PS- Action=0x%X\n", psmode->Action);
+        }
+
+        CleanupAndInsertCmd(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+        ret = WLAN_STATUS_SUCCESS;
+        goto done;
+    }
+
+    if (Adapter->CurCmd->CmdFlags & CMD_F_HOSTCMD) {
+        /* Copy the response back to response buffer */
+        memcpy(Adapter->CurCmd->pdata_buf, resp, resp->Size);
+
+        Adapter->CurCmd->CmdFlags &= ~CMD_F_HOSTCMD;
+
+        if ((Result == HostCmd_RESULT_OK)
+            && (RespCmd == HostCmd_RET_802_11_HOST_SLEEP_CFG)) {
+            ret = wlan_ret_host_sleep_cfg(priv, resp);
+        }
+    } else {
+        /* If the command is not successful, cleanup and return failure */
+        if ((Result != HostCmd_RESULT_OK || !(RespCmd & 0x8000))) {
+            PRINTM(ERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
+                   resp->Command, resp->Result);
+            /*
+             * Handling errors here
+             */
+            switch (RespCmd) {
+            case HostCmd_RET_HW_SPEC_INFO:
+                PRINTM(INFO, "CMD_RESP: HW spec command Failed\n");
+                break;
+
+            }
+
+            CleanupAndInsertCmd(priv, Adapter->CurCmd);
+            spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+            Adapter->CurCmd = NULL;
+            spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+            return WLAN_STATUS_FAILURE;
+        }
+
+        switch (RespCmd) {
+        case HostCmd_RET_MAC_REG_ACCESS:
+        case HostCmd_RET_BBP_REG_ACCESS:
+        case HostCmd_RET_RF_REG_ACCESS:
+            ret = wlan_ret_reg_access(priv, RespCmd, resp);
+            break;
+
+        case HostCmd_RET_HW_SPEC_INFO:
+            ret = wlan_ret_get_hw_spec(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_BG_SCAN_QUERY:
+            {
+                union iwreq_data wrqu;
+
+                ret = wlan_ret_802_11_scan(priv, resp);
+                memset(&wrqu, 0, sizeof(union iwreq_data));
+                wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                    NULL);
+                PRINTM(INFO, "CMD_RESP: BG_SCAN result is ready!\n");
+                break;
+            }
+        case HostCmd_RET_802_11_SCAN:
+            ret = wlan_ret_802_11_scan(priv, resp);
+            break;
+
+        case HostCmd_RET_MAC_CONTROL:
+            ret = wlan_ret_mac_control(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_GET_LOG:
+            ret = wlan_ret_get_log(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_ASSOCIATE:
+            ret = wlan_ret_802_11_associate(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_DEAUTHENTICATE:
+            ret = wlan_ret_802_11_disassociate(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_SET_WEP:
+            ret = wlan_ret_802_11_set_wep(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_AD_HOC_START:
+        case HostCmd_RET_802_11_AD_HOC_JOIN:
+            ret = wlan_ret_802_11_ad_hoc(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_RESET:
+            ret = wlan_ret_802_11_reset(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_SNMP_MIB:
+            ret = wlan_ret_802_11_snmp_mib(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_RF_TX_POWER:
+            ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_RADIO_CONTROL:
+            ret = wlan_ret_802_11_radio_control(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_HOST_SLEEP_CFG:
+            ret = wlan_ret_host_sleep_cfg(priv, resp);
+            break;
+        case HostCmd_RET_802_11_WAKEUP_CONFIRM:
+            wlan_host_sleep_deactivated_event(priv);
+            break;
+        case HostCmd_RET_802_11_HOST_SLEEP_ACTIVATE:
+            if (Adapter->bHostSleepConfigured
+                && Adapter->HSCfg.gap == HOST_SLEEP_CFG_GAP_FF)
+                Adapter->bWakeupDevRequired = TRUE;
+            wlan_host_sleep_activated_event(priv);
+            break;
+
+        case HostCmd_RET_802_11_RF_ANTENNA:
+            ret = wlan_ret_802_11_rf_antenna(priv, resp);
+            break;
+
+        case HostCmd_RET_MAC_MULTICAST_ADR:
+            ret = wlan_ret_mac_multicast_adr(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_RATE_ADAPT_RATESET:
+            ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+            break;
+        case HostCmd_RET_802_11_RF_CHANNEL:
+            ret = wlan_ret_802_11_rf_channel(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_RSSI:
+            ret = wlan_ret_802_11_rssi(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_MAC_ADDRESS:
+            ret = wlan_ret_802_11_mac_address(priv, resp);
+            break;
+
+#ifdef MFG_CMD_SUPPORT
+        case HostCmd_RET_MFG_COMMAND:
+            ret = wlan_ret_mfg_cmd(priv, resp);
+            break;
+#endif
+        case HostCmd_RET_802_11_AD_HOC_STOP:
+            ret = wlan_ret_802_11_ad_hoc_stop(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_CAL_DATA_EXT:
+            ret = wlan_ret_802_11_cal_data_ext(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_KEY_MATERIAL:
+            ret = wlan_ret_802_11_key_material(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_EEPROM_ACCESS:
+            ret = wlan_ret_802_11_eeprom_access(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11D_DOMAIN_INFO:
+            ret = wlan_ret_802_11d_domain_info(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_SLEEP_PARAMS:
+            ret = wlan_ret_802_11_sleep_params(priv, resp);
+            break;
+        case HostCmd_RET_802_11_BCA_CONFIG_TIMESHARE:
+            ret = wlan_ret_802_11_bca_timeshare(priv, resp);
+            break;
+        case HostCmd_RET_802_11_INACTIVITY_TIMEOUT:
+            *((u16 *) Adapter->CurCmd->pdata_buf) =
+                wlan_le16_to_cpu(resp->params.inactivity_timeout.Timeout);
+            break;
+        case HostCmd_RET_802_11_BG_SCAN_CONFIG:
+            break;
+
+        case HostCmd_RET_802_11_FW_WAKE_METHOD:
+            ret = wlan_ret_fw_wakeup_method(priv, resp);
+            break;
+
+        case HostCmd_RET_802_11_SLEEP_PERIOD:
+            ret = wlan_ret_802_11_sleep_period(priv, resp);
+            break;
+        case HostCmd_RET_WMM_GET_STATUS:
+            ret = wlan_cmdresp_wmm_get_status(priv, resp);
+            break;
+        case HostCmd_RET_WMM_ADDTS_REQ:
+            ret = wlan_cmdresp_wmm_addts_req(priv, resp);
+            break;
+        case HostCmd_RET_WMM_DELTS_REQ:
+            ret = wlan_cmdresp_wmm_delts_req(priv, resp);
+            break;
+        case HostCmd_RET_WMM_QUEUE_CONFIG:
+            ret = wlan_cmdresp_wmm_queue_config(priv, resp);
+            break;
+        case HostCmd_RET_WMM_QUEUE_STATS:
+            ret = wlan_cmdresp_wmm_queue_stats(priv, resp);
+            break;
+        case HostCmd_RET_TX_PKT_STATS:
+            memcpy(Adapter->CurCmd->pdata_buf,
+                   &resp->params.txPktStats, sizeof(HostCmd_DS_TX_PKT_STATS));
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        case HostCmd_RET_802_11_TPC_CFG:
+            memmove(Adapter->CurCmd->pdata_buf,
+                    &resp->params.tpccfg, sizeof(HostCmd_DS_802_11_TPC_CFG));
+            break;
+        case HostCmd_RET_802_11_LED_CONTROL:
+            {
+                HostCmd_DS_802_11_LED_CTRL *pLedCtrl = &resp->params.ledgpio;
+                MrvlIEtypes_LedGpio_t *pGpio = &pLedCtrl->LedGpio;
+                MrvlIEtypes_LedBehavior_t *pBehavior = pLedCtrl->LedBehavior;
+
+                pLedCtrl->Action = wlan_le16_to_cpu(pLedCtrl->Action);
+                pLedCtrl->LedNums = wlan_le16_to_cpu(pLedCtrl->LedNums);
+                pGpio->Header.Type = wlan_le16_to_cpu(pGpio->Header.Type);
+                pGpio->Header.Len = wlan_le16_to_cpu(pGpio->Header.Len);
+                pBehavior->Header.Type =
+                    wlan_le16_to_cpu(pBehavior->Header.Type);
+                pBehavior->Header.Len =
+                    wlan_le16_to_cpu(pBehavior->Header.Len);
+                memmove(Adapter->CurCmd->pdata_buf, &resp->params.ledgpio,
+                        sizeof(HostCmd_DS_802_11_LED_CTRL));
+                break;
+            }
+
+        case HostCmd_RET_GET_TSF:
+            resp->params.gettsf.TsfValue =
+                wlan_le64_to_cpu(resp->params.gettsf.TsfValue);
+            memcpy(priv->adapter->CurCmd->pdata_buf,
+                   &resp->params.gettsf.TsfValue, sizeof(u64));
+            break;
+        case HostCmd_RTE_802_11_TX_RATE_QUERY:
+            priv->adapter->TxRate =
+                wlan_le16_to_cpu(resp->params.txrate.TxRate);
+            break;
+        case HostCmd_RET_802_11_IBSS_COALESCING_STATUS:
+            wlan_ret_802_11_IBSS_Coalesced_Status(priv, resp);
+            break;
+
+        case HostCmd_RET_SDIO_PULL_CTRL:
+            memmove(Adapter->CurCmd->pdata_buf,
+                    &resp->params.sdiopullctl,
+                    sizeof(HostCmd_DS_SDIO_PULL_CTRL));
+            break;
+
+        case HostCmd_RET_802_11_LDO_CONFIG:
+            resp->params.ldocfg.Action =
+                wlan_le16_to_cpu(resp->params.ldocfg.Action);
+            resp->params.ldocfg.PMSource =
+                wlan_le16_to_cpu(resp->params.ldocfg.PMSource);
+            memmove(Adapter->CurCmd->pdata_buf, &resp->params.ldocfg,
+                    sizeof(HostCmd_DS_802_11_LDO_CONFIG));
+            break;
+
+        case HostCmd_RET_VERSION_EXT:
+            memcpy(Adapter->CurCmd->pdata_buf,
+                   &resp->params.verext, sizeof(HostCmd_DS_VERSION_EXT));
+            break;
+
+        default:
+            PRINTM(INFO, "CMD_RESP: Unknown command response %#x\n",
+                   resp->Command);
+            break;
+        }
+    }
+
+    if (Adapter->CurCmd) {
+        /* Clean up and Put current command back to CmdFreeQ */
+        CleanupAndInsertCmd(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+#if WIRELESS_EXT >= 18
+/** 
+ *  @brief This function sends mic error event to application.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @para event    MIC ERROR EVENT. 
+ *  @return 	   n/a
+ */
+void
+send_mic_error_event(wlan_private * priv, u32 event)
+{
+    union iwreq_data iwrq;
+    struct iw_michaelmicfailure mic;
+
+    ENTER();
+
+    memset(&iwrq, 0, sizeof(iwrq));
+    memset(&mic, 0, sizeof(mic));
+    if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
+        mic.flags = IW_MICFAILURE_PAIRWISE;
+    } else {
+        mic.flags = IW_MICFAILURE_GROUP;
+    }
+
+    iwrq.data.pointer = &mic;
+    iwrq.data.length = sizeof(mic);
+
+    wireless_send_event(priv->wlan_dev.netdev, IWEVMICHAELMICFAILURE, &iwrq,
+                        (u8 *) & mic);
+
+    LEAVE();
+    return;
+}
+#endif
+
+/** 
+ *  @brief This function handles events generated by firmware
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_process_event(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    u32 eventcause = Adapter->EventCause >> SBI_EVENT_CAUSE_SHIFT;
+
+    ENTER();
+
+    /* Save the last event to debug log */
+    Adapter->dbg.LastEventIndex =
+        (Adapter->dbg.LastEventIndex + 1) % DBG_CMD_NUM;
+    Adapter->dbg.LastEvent[Adapter->dbg.LastEventIndex] = eventcause;
+
+    if (eventcause != MACREG_INT_CODE_PS_SLEEP &&
+        eventcause != MACREG_INT_CODE_PS_AWAKE)
+        PRINTM(EVENT, "EVENT: 0x%x @ %lu\n", eventcause, os_time_get());
+
+    switch (eventcause) {
+    case MACREG_INT_CODE_DUMMY_HOST_WAKEUP_SIGNAL:
+        PRINTM(INFO, "EVENT: DUMMY_HOST_WAKEUP_SIGNAL\n");
+        if (!priv->adapter->HS_Activated) {
+            PRINTM(WARN, "DUMMY_HOST_WAKEUP_SIGNAL (HS_Deactivated)\n");
+        } else {
+            wlan_host_sleep_gpio_int_event(priv);
+        }
+        break;
+    case MACREG_INT_CODE_LINK_SENSED:
+        PRINTM(INFO, "EVENT: LINK_SENSED\n");
+        Adapter->AdhocLinkSensed = TRUE;
+        os_carrier_on(priv);
+        os_start_queue(priv);
+        wmm_start_queue(priv);
+        send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED);
+        break;
+
+    case MACREG_INT_CODE_DEAUTHENTICATED:
+        PRINTM(INFO, "EVENT: Deauthenticated\n");
+        Adapter->dbg.num_event_deauth++;
+        HandleDisconnectEvent(priv);
+        break;
+
+    case MACREG_INT_CODE_DISASSOCIATED:
+        PRINTM(INFO, "EVENT: Disassociated\n");
+        Adapter->dbg.num_event_disassoc++;
+        HandleDisconnectEvent(priv);
+        break;
+
+    case MACREG_INT_CODE_LINK_LOST:
+        PRINTM(INFO, "EVENT: Link lost\n");
+        Adapter->dbg.num_event_link_lost++;
+        HandleDisconnectEvent(priv);
+        break;
+
+    case MACREG_INT_CODE_PS_SLEEP:
+        PRINTM(INFO, "EVENT: SLEEP\n");
+        PRINTM(EVENT, "_");
+
+        /* handle unexpected PS SLEEP event */
+        if (Adapter->PSState == PS_STATE_FULL_POWER) {
+            PRINTM(INFO, "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+            break;
+        }
+        Adapter->PSState = PS_STATE_PRE_SLEEP;
+
+        PSConfirmSleep(priv, (u16) Adapter->PSMode);
+        break;
+
+    case MACREG_INT_CODE_PS_AWAKE:
+        PRINTM(INFO, "EVENT: AWAKE \n");
+        PRINTM(EVENT, "|");
+
+        /* handle unexpected PS AWAKE event */
+        if (Adapter->PSState == PS_STATE_FULL_POWER) {
+            PRINTM(INFO, "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+            break;
+        }
+
+        Adapter->TxLockFlag = FALSE;
+        if (TRUE == CheckLastPacketIndication(priv)) {
+            if (!priv->wlan_dev.dnld_sent && Adapter->gen_null_pkg) {
+                SendNullPacket(priv, MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+                               MRVDRV_TxPD_POWER_MGMT_LAST_PACKET);
+                Adapter->TxLockFlag = TRUE;
+            }
+        }
+
+        Adapter->PSState = PS_STATE_AWAKE;
+
+        if (Adapter->NeedToWakeup == TRUE) {
+            /*
+             * wait for the command processing to finish
+             * before resuming sending 
+             * Adapter->NeedToWakeup will be set to FALSE 
+             * in PSWakup()
+             */
+            PRINTM(INFO, "Waking up...\n");
+            PSWakeup(priv, 0);
+        }
+        break;
+
+    case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+        sbi_reset_deepsleep_wakeup(priv);
+        PRINTM(INFO, "EVENT: DS_AWAKE\n");
+        if (priv->adapter->IsDeepSleep == TRUE) {
+            Adapter->IsDeepSleep = FALSE;
+            Adapter->bWakeupDevRequired = FALSE;
+            Adapter->WakeupTries = 0;
+            /* 
+             * For auto DS + BGS case, some delay is needed to 
+             * avoid going back to DS before getting BGS result
+             */
+            if (Adapter->IsAutoDeepSleepEnabled &&
+                Adapter->bgScanConfig->Enable)
+                os_sched_timeout(10);
+            priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+            priv->adapter->HisRegCpy |= HIS_TxDnLdRdy;
+        }
+        send_iwevcustom_event(priv, CUS_EVT_DEEP_SLEEP_AWAKE);
+        wake_up_interruptible(&Adapter->ds_awake_q);
+        break;
+
+    case MACREG_INT_CODE_HOST_SLEEP_AWAKE:
+        PRINTM(INFO, "EVENT: HS_AWAKE\n");
+        Adapter->bWakeupDevRequired = FALSE;
+        Adapter->WakeupTries = 0;
+        sbi_reset_deepsleep_wakeup(priv);
+
+        /*
+         * in BG SCAN mode w/ deep sleep, WAKE UP event
+         * will be sent first, Deep Sleep Awake will
+         * be sent later. 
+         */
+        if (priv->adapter->IsDeepSleep == TRUE) {
+            priv->adapter->IsDeepSleep = FALSE;
+            priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+            priv->adapter->HisRegCpy |= HIS_TxDnLdRdy;
+        }
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_WAKEUP_CONFIRM,
+                                    0, 0, 0, NULL);
+        break;
+
+    case MACREG_INT_CODE_MIC_ERR_UNICAST:
+        PRINTM(INFO, "EVENT: UNICAST MIC ERROR\n");
+#if WIRELESS_EXT >= 18
+        send_mic_error_event(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+#else
+        send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI);
+#endif
+        break;
+
+    case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+        PRINTM(INFO, "EVENT: MULTICAST MIC ERROR\n");
+#if WIRELESS_EXT >= 18
+        send_mic_error_event(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+#else
+        send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_MUL);
+#endif
+        break;
+    case MACREG_INT_CODE_MIB_CHANGED:
+    case MACREG_INT_CODE_INIT_DONE:
+        break;
+
+    case MACREG_INT_CODE_ADHOC_BCN_LOST:
+        PRINTM(INFO, "EVENT: ADHOC_BCN_LOST\n");
+        Adapter->AdhocLinkSensed = FALSE;
+        wlan_clean_txrx(priv);
+        send_iwevcustom_event(priv, CUS_EVT_ADHOC_BCN_LOST);
+        break;
+
+    case MACREG_INT_CODE_BG_SCAN_REPORT:
+        PRINTM(INFO, "EVENT: BGS_REPORT\n");
+        Adapter->bgScanConfig->Enable = FALSE;
+        ret = sendBgScanQueryCmd(priv);
+        break;
+    case MACREG_INT_CODE_WMM_STATUS_CHANGE:
+        PRINTM(INFO, "EVENT: WMM status changed\n");
+        ret = sendWMMStatusChangeCmd(priv);
+        break;
+
+    case MACREG_INT_CODE_RSSI_LOW:
+        PRINTM(INFO, "EVENT: RSSI_LOW\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
+        break;
+    case MACREG_INT_CODE_SNR_LOW:
+        PRINTM(INFO, "EVENT: SNR_LOW\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW);
+        break;
+    case MACREG_INT_CODE_MAX_FAIL:
+        PRINTM(INFO, "EVENT: MAX_FAIL\n");
+        send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
+        break;
+    case MACREG_INT_CODE_RSSI_HIGH:
+        PRINTM(INFO, "EVENT: RSSI_HIGH\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
+        break;
+    case MACREG_INT_CODE_SNR_HIGH:
+        PRINTM(INFO, "EVENT: SNR_HIGH\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH);
+        break;
+    case MACREG_INT_CODE_IBSS_COALESCED:
+        PRINTM(INFO, "EVENT: IBSS_COALESCED\n");
+        ret = sendADHOCBSSIDQuery(priv);
+        break;
+    default:
+        PRINTM(INFO, "EVENT: unknown event id: %#x\n", eventcause);
+        break;
+    }
+
+    Adapter->EventCause = 0;
+    LEAVE();
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_debug.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_debug.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_debug.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_debug.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,295 @@
+/** @file wlan_debug.c
+  * @brief This file contains functions for debug proc file.
+  *   
+  * (c) Copyright © 2003-2007, Marvell International Ltd.  
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	
+********************************************************/
+
+#include  "include.h"
+
+#ifdef CONFIG_PROC_FS
+/********************************************************
+		Local Variables
+********************************************************/
+
+#define item_size(n) (sizeof ((wlan_adapter *)0)->n)
+#define item_addr(n) ((u32) &((wlan_adapter *)0)->n)
+
+#define item_dbg_size(n) (sizeof (((wlan_adapter *)0)->dbg.n))
+#define item_dbg_addr(n) ((u32) &(((wlan_adapter *)0)->dbg.n))
+
+#define item1_size(n) (sizeof ((wlan_dev_t *)0)->n)
+#define item1_addr(n) ((u32) &((wlan_dev_t *)0)->n)
+
+struct debug_data
+{
+    char name[32];
+    u32 size;
+    u32 addr;
+    u32 offset;
+};
+
+/* To debug any member of wlan_adapter or wlan_dev_t, simply add one line here.
+ */
+#define ITEMS_FROM_WLAN_DEV		1
+
+static struct debug_data items[] = {
+    {"IntCounter", item_size(IntCounter), 0, item_addr(IntCounter)},
+    {"ConnectStatus", item_size(MediaConnectStatus), 0,
+     item_addr(MediaConnectStatus)},
+    {"wmmQStp", item_size(wmm.queueStopped), 0, item_addr(wmm.queueStopped)},
+    {"wmmPkts", item_size(wmm.packetsQueued), 0,
+     item_addr(wmm.packetsQueued)},
+    {"wmmAcVo", item_size(wmm.packetsOut[WMM_AC_VO]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_VO])},
+    {"wmmAcVi", item_size(wmm.packetsOut[WMM_AC_VI]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_VI])},
+    {"wmmAcBE", item_size(wmm.packetsOut[WMM_AC_BE]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_BE])},
+    {"wmmAcBK", item_size(wmm.packetsOut[WMM_AC_BK]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_BK])},
+    {"PSMode", item_size(PSMode), 0, item_addr(PSMode)},
+    {"PSState", item_size(PSState), 0, item_addr(PSState)},
+    {"IsDeepSleep", item_size(IsDeepSleep), 0, item_addr(IsDeepSleep)},
+    {"IsAutoDeepSleepEnabled", item_size(IsAutoDeepSleepEnabled), 0,
+     item_addr(IsAutoDeepSleepEnabled)},
+    {"WakeupDevReq", item_size(bWakeupDevRequired), 0,
+     item_addr(bWakeupDevRequired)},
+    {"WakeupTries", item_size(WakeupTries), 0, item_addr(WakeupTries)},
+    {"HS_Configured", item_size(bHostSleepConfigured), 0,
+     item_addr(bHostSleepConfigured)},
+    {"HS_Activated", item_size(HS_Activated), 0, item_addr(HS_Activated)},
+    {"num_tx_timeout", item_dbg_size(num_tx_timeout), 0,
+     item_dbg_addr(num_tx_timeout)},
+    {"num_cmd_timeout", item_dbg_size(num_cmd_timeout), 0,
+     item_dbg_addr(num_cmd_timeout)},
+    {"TimeoutCmdId", item_dbg_size(TimeoutCmdId), 0,
+     item_dbg_addr(TimeoutCmdId)},
+    {"TimeoutCmdAct", item_dbg_size(TimeoutCmdAct), 0,
+     item_dbg_addr(TimeoutCmdAct)},
+    {"LastCmdId", item_dbg_size(LastCmdId), 0, item_dbg_addr(LastCmdId)},
+    {"LastCmdAct", item_dbg_size(LastCmdAct), 0, item_dbg_addr(LastCmdAct)},
+    {"LastCmdIndex", item_dbg_size(LastCmdIndex), 0,
+     item_dbg_addr(LastCmdIndex)},
+    {"LastCmdRespId", item_dbg_size(LastCmdRespId), 0,
+     item_dbg_addr(LastCmdRespId)},
+    {"LastCmdRespIndex", item_dbg_size(LastCmdRespIndex), 0,
+     item_dbg_addr(LastCmdRespIndex)},
+    {"LastEvent", item_dbg_size(LastEvent), 0, item_dbg_addr(LastEvent)},
+    {"LastEventIndex", item_dbg_size(LastEventIndex), 0,
+     item_dbg_addr(LastEventIndex)},
+    {"num_cmd_h2c_fail", item_dbg_size(num_cmd_host_to_card_failure), 0,
+     item_dbg_addr(num_cmd_host_to_card_failure)},
+    {"num_cmd_sleep_cfm_fail",
+     item_dbg_size(num_cmd_sleep_cfm_host_to_card_failure), 0,
+     item_dbg_addr(num_cmd_sleep_cfm_host_to_card_failure)},
+    {"num_tx_h2c_fail", item_dbg_size(num_tx_host_to_card_failure), 0,
+     item_dbg_addr(num_tx_host_to_card_failure)},
+    {"num_evt_deauth", item_dbg_size(num_event_deauth), 0,
+     item_dbg_addr(num_event_deauth)},
+    {"num_evt_disassoc", item_dbg_size(num_event_disassoc), 0,
+     item_dbg_addr(num_event_disassoc)},
+    {"num_evt_link_lost", item_dbg_size(num_event_link_lost), 0,
+     item_dbg_addr(num_event_link_lost)},
+    {"num_cmd_deauth", item_dbg_size(num_cmd_deauth), 0,
+     item_dbg_addr(num_cmd_deauth)},
+    {"num_cmd_assoc_ok", item_dbg_size(num_cmd_assoc_success), 0,
+     item_dbg_addr(num_cmd_assoc_success)},
+    {"num_cmd_assoc_fail", item_dbg_size(num_cmd_assoc_failure), 0,
+     item_dbg_addr(num_cmd_assoc_failure)},
+
+    {"dnld_sent", item1_size(dnld_sent), 0, item1_addr(dnld_sent)},
+};
+
+static int num_of_items = sizeof(items) / sizeof(items[0]);
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+/** 
+ *  @brief proc read function
+ *
+ *  @param page	   pointer to buffer
+ *  @param s       read data starting position
+ *  @param off     offset
+ *  @param cnt     counter 
+ *  @param eof     end of file flag
+ *  @param data    data to output
+ *  @return 	   number of output data
+ */
+static int
+wlan_debug_read(char *page, char **s, off_t off, int cnt, int *eof,
+                void *data)
+{
+    int val = 0;
+    char *p = page;
+    int i;
+
+    struct debug_data *d = (struct debug_data *) data;
+
+    MODULE_GET;
+
+    for (i = 0; i < num_of_items; i++) {
+        if (d[i].size == 1)
+            val = *((u8 *) d[i].addr);
+        else if (d[i].size == 2)
+            val = *((u16 *) d[i].addr);
+        else if (d[i].size == 4)
+            val = *((u32 *) d[i].addr);
+        else {
+            int j;
+            p += sprintf(p, "%s=", d[i].name);
+            for (j = 0; j < d[i].size; j += 2) {
+                val = *(u16 *) (d[i].addr + j);
+                p += sprintf(p, "0x%x ", val);
+            }
+            p += sprintf(p, "\n");
+            continue;
+        }
+
+        if (strstr(d[i].name, "Id"))
+            p += sprintf(p, "%s=0x%x\n", d[i].name, val);
+        else
+            p += sprintf(p, "%s=%d\n", d[i].name, val);
+    }
+    MODULE_PUT;
+    return p - page;
+}
+
+/** 
+ *  @brief proc write function
+ *
+ *  @param f	   file pointer
+ *  @param buf     pointer to data buffer
+ *  @param cnt     data number to write
+ *  @param data    data to write
+ *  @return 	   number of data
+ */
+static int
+wlan_debug_write(struct file *f, const char *buf, unsigned long cnt,
+                 void *data)
+{
+    int r, i;
+    char *pdata;
+    char *p;
+    char *p0;
+    char *p1;
+    char *p2;
+    struct debug_data *d = (struct debug_data *) data;
+
+    MODULE_GET;
+
+    pdata = (char *) kmalloc(cnt, GFP_KERNEL);
+    if (pdata == NULL) {
+        MODULE_PUT;
+        return 0;
+    }
+
+    if (copy_from_user(pdata, buf, cnt)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(pdata);
+        MODULE_PUT;
+        return 0;
+    }
+
+    p0 = pdata;
+    for (i = 0; i < num_of_items; i++) {
+        do {
+            p = strstr(p0, d[i].name);
+            if (p == NULL)
+                break;
+            p1 = strchr(p, '\n');
+            if (p1 == NULL)
+                break;
+            p0 = p1++;
+            p2 = strchr(p, '=');
+            if (!p2)
+                break;
+            p2++;
+            r = string_to_number(p2);
+            if (d[i].size == 1)
+                *((u8 *) d[i].addr) = (u8) r;
+            else if (d[i].size == 2)
+                *((u16 *) d[i].addr) = (u16) r;
+            else if (d[i].size == 4)
+                *((u32 *) d[i].addr) = (u32) r;
+            break;
+        } while (TRUE);
+    }
+    kfree(pdata);
+    MODULE_PUT;
+    return cnt;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+/** 
+ *  @brief create debug proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @param dev     pointer net_device
+ *  @return 	   N/A
+ */
+void
+wlan_debug_entry(wlan_private * priv, struct net_device *dev)
+{
+    int i;
+    struct proc_dir_entry *r;
+
+    if (priv->proc_entry == NULL)
+        return;
+
+    for (i = 0; i < (num_of_items - ITEMS_FROM_WLAN_DEV); i++) {
+        items[i].addr = items[i].offset + (u32) priv->adapter;
+    }
+    for (i = num_of_items - ITEMS_FROM_WLAN_DEV; i < num_of_items; i++) {
+        items[i].addr = items[i].offset + (u32) & priv->wlan_dev;
+    }
+    r = create_proc_entry("debug", 0644, priv->proc_entry);
+    if (r == NULL)
+        return;
+
+    r->data = &items[0];
+    r->read_proc = wlan_debug_read;
+    r->write_proc = wlan_debug_write;
+    r->owner = THIS_MODULE;
+
+}
+
+/** 
+ *  @brief remove proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @return 	   N/A
+ */
+void
+wlan_debug_remove(wlan_private * priv)
+{
+    remove_proc_entry("debug", priv->proc_entry);
+}
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_decl.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_decl.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_decl.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_decl.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,127 @@
+/** @file wlan_decl.h
+ *  @brief This file contains declaration referring to
+ *  functions defined in other source files
+ *     
+ *  (c) Copyright © 2003-2007, Marvell International Ltd.  
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/******************************************************
+Change log:
+	09/29/05: add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join structures.
+	          Move wlan_wext statics to their source file.
+******************************************************/
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+/** Function Prototype Declaration */
+int wlan_init_fw(wlan_private * priv);
+int wlan_tx_packet(wlan_private * priv, struct sk_buff *skb);
+void wlan_free_adapter(wlan_private * priv);
+
+int SendNullPacket(wlan_private * priv, u8 flags);
+BOOLEAN CheckLastPacketIndication(wlan_private * priv);
+
+void Wep_encrypt(wlan_private * priv, u8 * Buf, u32 Len);
+int FreeCmdBuffer(wlan_private * priv);
+void CleanUpCmdCtrlNode(CmdCtrlNode * pTempNode);
+CmdCtrlNode *GetFreeCmdCtrlNode(wlan_private * priv);
+
+void SetCmdCtrlNode(wlan_private * priv,
+                    CmdCtrlNode * pTempNode,
+                    WLAN_OID cmd_oid, u16 wait_option, void *pdata_buf);
+
+BOOLEAN Is_Command_Allowed(wlan_private * priv);
+
+int PrepareAndSendCommand(wlan_private * priv,
+                          u16 cmd_no,
+                          u16 cmd_action,
+                          u16 wait_option, WLAN_OID cmd_oid, void *pdata_buf);
+
+void QueueCmd(wlan_adapter * Adapter, CmdCtrlNode * CmdNode, BOOLEAN addtail);
+
+int SetDeepSleep(wlan_private * priv, BOOLEAN bDeepSleep);
+int AllocateCmdBuffer(wlan_private * priv);
+int ExecuteNextCommand(wlan_private * priv);
+int wlan_process_event(wlan_private * priv);
+void wlan_interrupt(struct net_device *);
+u32 index_to_data_rate(u8 index);
+u8 data_rate_to_index(u32 rate);
+void HexDump(char *prompt, u8 * data, int len);
+void get_version(wlan_adapter * adapter, char *version, int maxlen);
+void wlan_read_write_rfreg(wlan_private * priv);
+
+#ifdef CONFIG_PROC_FS
+/** The proc fs interface */
+void wlan_proc_entry(wlan_private * priv, struct net_device *dev);
+void wlan_proc_remove(wlan_private * priv);
+int string_to_number(char *s);
+#ifdef PROC_DEBUG
+void wlan_debug_entry(wlan_private * priv, struct net_device *dev);
+void wlan_debug_remove(wlan_private * priv);
+#endif /* PROC_DEBUG */
+#endif /* CONFIG_PROC_FS */
+int wlan_process_rx_command(wlan_private * priv);
+void wlan_process_tx(wlan_private * priv);
+void CleanupAndInsertCmd(wlan_private * priv, CmdCtrlNode * pTempCmd);
+void MrvDrvCommandTimerFunction(void *FunctionContext);
+
+#ifdef REASSOCIATION
+void MrvDrvReassocTimerFunction(void *FunctionContext);
+#endif /* REASSOCIATION */
+
+int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+                   struct iw_point *dwrq, char *extra);
+int wlan_set_regiontable(wlan_private * priv, u8 region, u8 band);
+
+void wlan_clean_txrx(wlan_private * priv);
+
+int wlan_host_sleep_activated_event(wlan_private * priv);
+int wlan_host_sleep_deactivated_event(wlan_private * priv);
+int wlan_host_sleep_gpio_int_event(wlan_private * priv);
+int wlan_deep_sleep_ioctl(wlan_private * priv, struct ifreq *rq);
+
+int ProcessRxedPacket(wlan_private * priv, struct sk_buff *);
+
+void PSSleep(wlan_private * priv, int wait_option);
+void PSConfirmSleep(wlan_private * priv, u16 PSMode);
+void PSWakeup(wlan_private * priv, int wait_option);
+//void sdio_clear_imask(mmc_controller_t);
+//int sdio_check_idle_state(mmc_controller_t);
+//void sdio_print_imask(mmc_controller_t);
+//void sdio_clear_imask(mmc_controller_t);
+
+int sd_set_clock(wlan_private * priv, u32 slotFreq);
+int sd_start_clock(wlan_private * priv);
+int sd_stop_clock(wlan_private * priv);
+int sd_set_bus_width(wlan_private * priv, u8 width);
+int sd_set_gpo(wlan_private * priv, u8 on);
+
+void wlan_send_rxskbQ(wlan_private * priv);
+
+extern CHANNEL_FREQ_POWER *find_cfp_by_band_and_channel(wlan_adapter *
+                                                        adapter, u8 band,
+                                                        u16 channel);
+
+extern void MacEventDisconnected(wlan_private * priv);
+
+#if WIRELESS_EXT > 14
+void send_iwevcustom_event(wlan_private * priv, s8 * str);
+#endif
+
+#endif /* _WLAN_DECL_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_defs.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_defs.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_defs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_defs.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,636 @@
+/** @file wlan_defs.h
+ *  @brief This header file contains global constant/enum definitions,
+ *  global variable declaration.
+ *       
+ *  (c) Copyright © 2003-2007, Marvell International Ltd.   
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change log:
+	10/11/05: add Doxygen format comments 
+	01/11/06: Add NELEMENTS, BAND_XX defines
+	04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command
+************************************************************/
+
+#ifndef _WLAN_DEFS_H_
+#define _WLAN_DEFS_H_
+
+#include	"os_defs.h"
+
+/** Double-Word(32Bit) Bit definition */
+#define DW_BIT_0	0x00000001
+#define DW_BIT_1	0x00000002
+#define DW_BIT_2	0x00000004
+#define DW_BIT_3	0x00000008
+#define DW_BIT_4	0x00000010
+#define DW_BIT_5	0x00000020
+#define DW_BIT_6	0x00000040
+#define DW_BIT_7	0x00000080
+#define DW_BIT_8	0x00000100
+#define DW_BIT_9	0x00000200
+#define DW_BIT_10	0x00000400
+#define DW_BIT_11       0x00000800
+#define DW_BIT_12       0x00001000
+#define DW_BIT_13       0x00002000
+#define DW_BIT_14       0x00004000
+#define DW_BIT_15       0x00008000
+#define DW_BIT_16       0x00010000
+#define DW_BIT_17       0x00020000
+#define DW_BIT_18       0x00040000
+#define DW_BIT_19       0x00080000
+#define DW_BIT_20       0x00100000
+#define DW_BIT_21       0x00200000
+#define DW_BIT_22       0x00400000
+#define DW_BIT_23       0x00800000
+#define DW_BIT_24       0x01000000
+#define DW_BIT_25       0x02000000
+#define DW_BIT_26       0x04000000
+#define DW_BIT_27       0x08000000
+#define DW_BIT_28       0x10000000
+#define DW_BIT_29       0x20000000
+#define DW_BIT_30	0x40000000
+#define DW_BIT_31	0x80000000
+
+/** Word (16bit) Bit Definition*/
+#define W_BIT_0		0x0001
+#define W_BIT_1		0x0002
+#define W_BIT_2		0x0004
+#define W_BIT_3		0x0008
+#define W_BIT_4		0x0010
+#define W_BIT_5		0x0020
+#define W_BIT_6		0x0040
+#define W_BIT_7		0x0080
+#define W_BIT_8		0x0100
+#define W_BIT_9		0x0200
+#define W_BIT_10	0x0400
+#define W_BIT_11	0x0800
+#define W_BIT_12	0x1000
+#define W_BIT_13	0x2000
+#define W_BIT_14	0x4000
+#define W_BIT_15	0x8000
+
+/** Byte (8Bit) Bit definition*/
+#define B_BIT_0		0x01
+#define B_BIT_1		0x02
+#define B_BIT_2		0x04
+#define B_BIT_3		0x08
+#define B_BIT_4		0x10
+#define B_BIT_5		0x20
+#define B_BIT_6		0x40
+#define B_BIT_7		0x80
+
+/** Debug Macro definition*/
+#ifdef	DEBUG_LEVEL1
+
+extern u32 drvdbg;
+extern u32 ifdbg;
+
+/* Debug message control bit definition for drvdbg */
+#define	DBG_MSG		DW_BIT_0
+#define DBG_FATAL	DW_BIT_1
+#define DBG_ERROR	DW_BIT_2
+#define DBG_DATA	DW_BIT_3
+#define DBG_CMND	DW_BIT_4
+#define DBG_EVENT	DW_BIT_5
+#define DBG_INTR	DW_BIT_6
+
+#define DBG_DAT_D	DW_BIT_16
+#define DBG_CMD_D	DW_BIT_17
+#define DBG_FW_D	DW_BIT_18
+
+#define DBG_ENTRY	DW_BIT_28
+#define DBG_WARN	DW_BIT_29
+#define DBG_INFO	DW_BIT_30
+
+/* Debug message control bit definition for ifdbg */
+#define DBG_IF_D	DW_BIT_0
+
+#ifdef	DEBUG_LEVEL2
+#define	PRINTM_INFO(msg...)  {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);}
+#define	PRINTM_WARN(msg...)  {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);}
+#define	PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
+#else
+#define	PRINTM_INFO(msg...)  do {} while (0)
+#define	PRINTM_WARN(msg...)  do {} while (0)
+#define	PRINTM_ENTRY(msg...) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define	PRINTM_FW_D(msg...)  {if (drvdbg & DBG_FW_D) printk(KERN_DEBUG msg);}
+#define	PRINTM_CMD_D(msg...) {if (drvdbg & DBG_CMD_D) printk(KERN_DEBUG msg);}
+#define	PRINTM_DAT_D(msg...) {if (drvdbg & DBG_DAT_D) printk(KERN_DEBUG msg);}
+
+#define	PRINTM_INTR(msg...)  {if (drvdbg & DBG_INTR) printk(KERN_DEBUG msg);}
+#define	PRINTM_EVENT(msg...) {if (drvdbg & DBG_EVENT) printk(msg);}
+#define	PRINTM_CMND(msg...)  {if (drvdbg & DBG_CMND) printk(KERN_DEBUG msg);}
+#define	PRINTM_DATA(msg...)  {if (drvdbg & DBG_DATA) printk(KERN_DEBUG msg);}
+#define	PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
+#define	PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
+#define	PRINTM_MSG(msg...)   {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);}
+
+#define	PRINTM_IF_D(msg...)  {if (ifdbg & DBG_IF_D) printk(KERN_DEBUG msg);}
+
+#define	PRINTM(level,msg...) PRINTM_##level(msg)
+
+#else
+
+#define	PRINTM(level,msg...) do {} while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+#define ASSERT(cond)						\
+do {								\
+	if (!(cond))						\
+		PRINTM(INFO, "ASSERT: %s, %s:%i\n",		\
+		       __FUNCTION__, __FILE__, __LINE__);	\
+} while(0)
+
+#define	ENTER()			PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
+							__FILE__, __LINE__)
+#define	LEAVE()			PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
+							__FILE__, __LINE__)
+
+#if defined(DEBUG_LEVEL1) && defined(__KERNEL__)
+#define DBG_DUMP_BUF_LEN 	64
+#define MAX_DUMP_PER_LINE	16
+#define MAX_DATA_DUMP_LEN	48
+
+static inline void
+hexdump(char *prompt, u8 * buf, int len)
+{
+    int i;
+    char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+    char *ptr = dbgdumpbuf;
+
+    printk(KERN_DEBUG "%s:\n", prompt);
+    for (i = 1; i <= len; i++) {
+        ptr += sprintf(ptr, "%02x ", *buf);
+        buf++;
+        if (i % MAX_DUMP_PER_LINE == 0) {
+            *ptr = 0;
+            printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+            ptr = dbgdumpbuf;
+        }
+    }
+    if (len % MAX_DUMP_PER_LINE) {
+        *ptr = 0;
+        printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+    }
+}
+
+#define DBG_HEXDUMP_CMD_D(x,y,z)    {if (drvdbg & DBG_CMD_D) hexdump(x,y,z);}
+#define DBG_HEXDUMP_DAT_D(x,y,z)    {if (drvdbg & DBG_DAT_D) hexdump(x,y,z);}
+#define DBG_HEXDUMP_IF_D(x,y,z)     {if (ifdbg & DBG_IF_D) hexdump(x,y,z);}
+#define DBG_HEXDUMP_FW_D(x,y,z)     {if (drvdbg & DBG_FW_D) hexdump(x,y,z);}
+
+#define	DBG_HEXDUMP(level,x,y,z)    DBG_HEXDUMP_##level(x,y,z)
+
+#else
+#define DBG_HEXDUMP(level,x,y,z)    do {} while (0)
+#endif
+
+#if defined(DEBUG_LEVEL2) && defined(__KERNEL__)
+#define HEXDUMP(x,y,z)              {if (drvdbg & DBG_INFO) hexdump(x,y,z);}
+#else
+#define HEXDUMP(x,y,z)              do {} while (0)
+#endif
+
+#ifndef	TRUE
+#define TRUE			1
+#endif
+#ifndef	FALSE
+#define	FALSE			0
+#endif
+
+#ifndef MIN
+#define MIN(a,b)		((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b)		((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef NELEMENTS
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+/** Buffer Constants */
+
+/*	The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+*	addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+*	driver has more local TxPDs. Each TxPD on the host memory is associated 
+*	with a Tx control node. The driver maintains 8 RxPD descriptors for 
+*	station firmware to store Rx packet information.
+*
+*	Current version of MAC has a 32x6 multicast address buffer.
+*
+*	802.11b can have up to  14 channels, the driver keeps the
+*	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+#define MRVDRV_SIZE_OF_PPA		0x00000008
+#define MRVDRV_SIZE_OF_DPA		0x00000008
+#define MRVDRV_NUM_OF_TxPD		0x00000020
+#define MRVDRV_NUM_OF_CMD_BUFFER        10
+#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
+#define MRVDRV_MAX_BSSID_LIST		64
+#define MRVDRV_TIMER_10S		10000
+#define MRVDRV_TIMER_5S			5000
+#define MRVDRV_TIMER_1S			1000
+#define MRVDRV_SNAP_HEADER_LEN          8
+#define MRVDRV_ETH_HEADER_SIZE          14
+
+#define ARP_FILTER_MAX_BUF_SIZE		20
+
+#define	WLAN_UPLD_SIZE			2312
+#define DEV_NAME_LEN			32
+
+#ifndef	ETH_ALEN
+#define ETH_ALEN			6
+#endif
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+#define SDIO_HEADER_LEN		4
+
+#define MRVDRV_MAX_REGION_CODE			7
+
+#define MRVDRV_IGNORE_MULTIPLE_DTIM		0xfffe
+#define MRVDRV_MIN_MULTIPLE_DTIM		1
+#define MRVDRV_MAX_MULTIPLE_DTIM		5
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM		1
+
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL		10
+#define MRVDRV_DEFAULT_LOCAL_LISTEN_INTERVAL		0
+
+#define	MRVDRV_CHANNELS_PER_ACTIVE_SCAN		14
+#define MRVDRV_MIN_BEACON_INTERVAL		20
+#define MRVDRV_MAX_BEACON_INTERVAL		1000
+#define MRVDRV_BEACON_INTERVAL			100
+
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (2 * HZ)
+#define MRVDRV_SCAN_WATCHDOG_TIMEOUT    (10 * HZ)
+#define MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT  (10 * HZ)
+
+/** TxPD Status */
+
+/*	Station firmware use TxPD status field to report final Tx transmit
+*	result, Bit masks are used to present combined situations.
+*/
+
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Tx control node status */
+
+#define MRVDRV_TX_CTRL_NODE_STATUS_IDLE      0x0000
+
+/* Link spped */
+#define MRVDRV_LINK_SPEED_1mbps          10000  /* in unit of 100bps */
+#define MRVDRV_LINK_SPEED_11mbps         110000
+
+/** RSSI-related defines */
+/*	RSSI constants are used to implement 802.11 RSSI threshold 
+*	indication. if the Rx packet signal got too weak for 5 consecutive
+*	times, miniport driver (driver) will report this event to wrapper
+*/
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE		(-96)
+
+/** RTS/FRAG related defines */
+#define MRVDRV_RTS_MIN_VALUE		0
+#define MRVDRV_RTS_MAX_VALUE		2347
+#define MRVDRV_FRAG_MIN_VALUE		256
+#define MRVDRV_FRAG_MAX_VALUE		2346
+
+/* Fixed IE size is 8 bytes time stamp + 2 bytes beacon interval +
+ * 2 bytes cap */
+#define MRVL_FIXED_IE_SIZE      12
+
+/* This is for firmware specific length */
+#define EXTRA_LEN	36
+#define MRVDRV_MAXIMUM_ETH_PACKET_SIZE	1514
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+	(MRVDRV_MAXIMUM_ETH_PACKET_SIZE + sizeof(TxPD) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+	(MRVDRV_MAXIMUM_ETH_PACKET_SIZE + sizeof(RxPD) \
+	 + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define	CMD_F_HOSTCMD		(1 << 0)
+
+/* to resolve CISCO AP extension */
+#define MRVDRV_SCAN_LIST_VAR_IE_SPACE  	256
+#define FW_IS_WPA_ENABLED(_adapter) \
+		(_adapter->fwCapInfo & FW_CAPINFO_WPA)
+
+#define FW_CAPINFO_WPA  	(1 << 0)
+#define WLAN_802_11_AI_REQFI_CAPABILITIES 	1
+#define WLAN_802_11_AI_REQFI_LISTENINTERVAL 	2
+#define WLAN_802_11_AI_REQFI_CURRENTAPADDRESS 	4
+
+#define WLAN_802_11_AI_RESFI_CAPABILITIES 	1
+#define WLAN_802_11_AI_RESFI_STATUSCODE 	2
+#define WLAN_802_11_AI_RESFI_ASSOCIATIONID 	4
+
+#define MRVL_NUM_WEP_KEY		4
+
+/** WPA Key LENGTH*/
+/* Support 4 keys per key set */
+#define MRVL_NUM_WPA_KEY_PER_SET        4
+#define MRVL_MAX_WPA_KEY_LENGTH 	32
+
+#define WPA_AES_KEY_LEN 		16
+#define WPA_TKIP_KEY_LEN 		32
+
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/* 104 bits */
+#define MAX_WEP_KEY_SIZE	13
+/*40 bits RC4 - WEP*/
+#define MIN_WEP_KEY_SIZE	5
+
+#define RF_ANTENNA_1		0x1
+#define RF_ANTENNA_2		0x2
+#define RF_ANTENNA_AUTO		0xFFFF
+
+#define KEY_INFO_ENABLED	0x01
+
+#define SNR_BEACON		0
+#define SNR_RXPD		1
+#define NF_BEACON		2
+#define NF_RXPD			3
+
+/** MACRO DEFINITIONS */
+#define CAL_NF(NF)			((s32)(-(s32)(NF)))
+#define CAL_RSSI(SNR, NF) 		((s32)((s32)(SNR) + CAL_NF(NF)))
+#define SCAN_RSSI(RSSI)			(0x100 - ((u8)(RSSI)))
+
+#define DEFAULT_BCN_AVG_FACTOR		8
+#define DEFAULT_DATA_AVG_FACTOR		8
+#define MIN_BCN_AVG_FACTOR		1
+#define MAX_BCN_AVG_FACTOR		8
+#define MIN_DATA_AVG_FACTOR		1
+#define MAX_DATA_AVG_FACTOR		8
+#define AVG_SCALE			100
+#define CAL_AVG_SNR_NF(AVG, SNRNF, N)         \
+                        (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
+                        ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+                        AVG_SCALE))  / N))
+
+#define WLAN_STATUS_SUCCESS			(0)
+#define WLAN_STATUS_FAILURE			(-1)
+#define WLAN_STATUS_NOT_ACCEPTED                (-2)
+
+#define	MAX_LEDS			3
+#define	LED_DISABLED			16
+#define	LED_BLINKING			2
+
+/* Max loop count (* 100ms) for waiting device ready at init time */
+#define MAX_WAIT_DEVICE_READY_COUNT	50
+
+/* S_SWAP : To swap 2 u8 */
+#define S_SWAP(a,b) 	do { \
+				u8  t = SArr[a]; \
+				SArr[a] = SArr[b]; SArr[b] = t; \
+			} while(0)
+
+/* SWAP: swap u8 */
+#define SWAP_U8(a,b)	{u8 t; t=a; a=b; b=t;}
+
+/* SWAP: swap u8 */
+#define SWAP_U16(a,b)	{u16 t; t=a; a=b; b=t;}
+
+#define wlan_le16_to_cpu(x) x
+#define wlan_le32_to_cpu(x) x
+#define wlan_le64_to_cpu(x) x
+#define wlan_cpu_to_le16(x) x
+#define wlan_cpu_to_le32(x) x
+#define wlan_cpu_to_le64(x) x
+
+#define endian_convert_TxPD(x)
+#define endian_convert_RxPD(x)
+#define endian_convert_GET_LOG(x)
+
+/** Global Varibale Declaration */
+typedef struct _wlan_private wlan_private;
+typedef struct _wlan_adapter wlan_adapter;
+typedef struct _HostCmd_DS_COMMAND HostCmd_DS_COMMAND;
+
+extern u32 DSFreqList[15];
+extern const char driver_version[];
+extern u32 DSFreqList[];
+extern u16 RegionCodeToIndex[MRVDRV_MAX_REGION_CODE];
+
+extern u8 WlanDataRates[WLAN_SUPPORTED_RATES];
+
+extern u8 SupportedRates[G_SUPPORTED_RATES];
+
+extern u8 AdhocRates_G[G_SUPPORTED_RATES];
+
+extern u8 AdhocRates_B[4];
+extern wlan_private *wlanpriv;
+
+#ifdef MFG_CMD_SUPPORT
+#define SIOCCFMFG SIOCDEVPRIVATE
+#endif /* MFG_CMD_SUPPORT */
+
+/** ENUM definition*/
+/** SNRNF_TYPE */
+typedef enum _SNRNF_TYPE
+{
+    TYPE_BEACON = 0,
+    TYPE_RXPD,
+    MAX_TYPE_B
+} SNRNF_TYPE;
+
+/** SNRNF_DATA*/
+typedef enum _SNRNF_DATA
+{
+    TYPE_NOAVG = 0,
+    TYPE_AVG,
+    MAX_TYPE_AVG
+} SNRNF_DATA;
+
+/** WLAN_802_11_AUTH_ALG*/
+typedef enum _WLAN_802_11_AUTH_ALG
+{
+    AUTH_ALG_OPEN_SYSTEM = 1,
+    AUTH_ALG_SHARED_KEY = 2,
+    AUTH_ALG_NETWORK_EAP = 8,
+} WLAN_802_11_AUTH_ALG;
+
+/** WLAN_802_11_ENCRYPTION_MODE */
+typedef enum _WLAN_802_11_ENCRYPTION_MODE
+{
+    CIPHER_NONE,
+    CIPHER_WEP40,
+    CIPHER_TKIP,
+    CIPHER_CCMP,
+    CIPHER_WEP104,
+} WLAN_802_11_ENCRYPTION_MODE;
+
+/** WLAN_802_11_POWER_MODE */
+typedef enum _WLAN_802_11_POWER_MODE
+{
+    Wlan802_11PowerModeCAM,
+    Wlan802_11PowerModeMAX_PSP,
+    Wlan802_11PowerModeFast_PSP,
+
+    /*not a real mode, defined as an upper bound */
+    Wlan802_11PowerModeMax
+} WLAN_802_11_POWER_MODE;
+
+/** PS_STATE */
+typedef enum _PS_STATE
+{
+    PS_STATE_FULL_POWER,
+    PS_STATE_AWAKE,
+    PS_STATE_PRE_SLEEP,
+    PS_STATE_SLEEP
+} PS_STATE;
+
+/** DNLD_STATE */
+typedef enum _DNLD_STATE
+{
+    DNLD_RES_RECEIVED,
+    DNLD_DATA_SENT,
+    DNLD_CMD_SENT
+} DNLD_STATE;
+
+/** WLAN_MEDIA_STATE */
+typedef enum _WLAN_MEDIA_STATE
+{
+    WlanMediaStateDisconnected,
+    WlanMediaStateConnected
+} WLAN_MEDIA_STATE;
+
+/** WLAN_802_11_PRIVACY_FILTER */
+typedef enum _WLAN_802_11_PRIVACY_FILTER
+{
+    Wlan802_11PrivFilterAcceptAll,
+    Wlan802_11PrivFilter8021xWEP
+} WLAN_802_11_PRIVACY_FILTER;
+
+/** mv_ms_type */
+typedef enum _mv_ms_type
+{
+    MVMS_DAT = 0,
+    MVMS_CMD = 1,
+    /* 2: reserved */
+    MVMS_EVENT = 3
+} mv_ms_type;
+
+/* Hardware status codes */
+typedef enum _WLAN_HARDWARE_STATUS
+{
+    WlanHardwareStatusReady,
+    WlanHardwareStatusInitializing,
+    WlanHardwareStatusReset,
+    WlanHardwareStatusClosing,
+    WlanHardwareStatusNotReady
+} WLAN_HARDWARE_STATUS;
+
+/** WLAN_802_11_AUTHENTICATION_MODE */
+typedef enum _WLAN_802_11_AUTHENTICATION_MODE
+{
+    Wlan802_11AuthModeOpen = 0x00,
+    Wlan802_11AuthModeShared = 0x01,
+    Wlan802_11AuthModeNetworkEAP = 0x80,
+} WLAN_802_11_AUTHENTICATION_MODE;
+
+/** WLAN_802_11_WEP_STATUS */
+typedef enum _WLAN_802_11_WEP_STATUS
+{
+    Wlan802_11WEPEnabled,
+    Wlan802_11WEPDisabled,
+    Wlan802_11WEPKeyAbsent,
+    Wlan802_11WEPNotSupported
+} WLAN_802_11_WEP_STATUS;
+
+/** SNMP_MIB_INDEX_e */
+typedef enum _SNMP_MIB_INDEX_e
+{
+    DesiredBssType_i = 0,
+    OpRateSet_i,
+    BcnPeriod_i,
+    DtimPeriod_i,
+    AssocRspTimeOut_i,
+    RtsThresh_i,
+    ShortRetryLim_i,
+    LongRetryLim_i,
+    FragThresh_i,
+    Dot11D_i,
+    Dot11H_i,
+    ManufId_i,
+    ProdId_i,
+    ManufOui_i,
+    ManufName_i,
+    ManufProdName_i,
+    ManufProdVer_i
+} SNMP_MIB_INDEX_e;
+
+/** KEY_TYPE_ID */
+typedef enum _KEY_TYPE_ID
+{
+    KEY_TYPE_ID_WEP = 0,
+    KEY_TYPE_ID_TKIP,
+    KEY_TYPE_ID_AES
+} KEY_TYPE_ID;
+
+/** KEY_INFO_WEP*/
+typedef enum _KEY_INFO_WEP
+{
+    KEY_INFO_WEP_DEFAULT_KEY = 0x01
+} KEY_INFO_WEP;
+
+/** KEY_INFO_TKIP */
+typedef enum _KEY_INFO_TKIP
+{
+    KEY_INFO_TKIP_MCAST = 0x01,
+    KEY_INFO_TKIP_UNICAST = 0x02,
+    KEY_INFO_TKIP_ENABLED = 0x04
+} KEY_INFO_TKIP;
+
+/** KEY_INFO_AES*/
+typedef enum _KEY_INFO_AES
+{
+    KEY_INFO_AES_MCAST = 0x01,
+    KEY_INFO_AES_UNICAST = 0x02,
+    KEY_INFO_AES_ENABLED = 0x04
+} KEY_INFO_AES;
+
+/** SNMP_MIB_VALUE_e */
+typedef enum _SNMP_MIB_VALUE_e
+{
+    SNMP_MIB_VALUE_INFRA = 1,
+    SNMP_MIB_VALUE_ADHOC
+} SNMP_MIB_VALUE_e;
+
+/** HWRateDropMode */
+typedef enum _HWRateDropMode
+{
+    NO_HW_RATE_DROP,
+    HW_TABLE_RATE_DROP,
+    HW_SINGLE_RATE_DROP
+} HWRateDropMode;
+
+#ifdef __KERNEL__
+extern struct iw_handler_def wlan_handler_def;
+struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev);
+int wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+#endif
+
+#endif /* _WLAN_DEFS_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_dev.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_dev.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_dev.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_dev.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,478 @@
+/** @file wlan_dev.h
+ *  @brief This file contains definitions and data structures specific
+ *          to Marvell 802.11 NIC. It contains the Device Information
+ *          structure wlan_adapter.  
+ *  
+ *  (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *      
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change log:
+	09/26/05: add Doxygen format comments 
+	01/11/06: Conditionalize new scan/join structures.
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+		  implementation through generic hostcmd API
+	05/08/06: Remove PermanentAddr from Adapter
+
+ ************************************************************/
+
+#ifndef _WLAN_DEV_H_
+#define _WLAN_DEV_H_
+
+#define	MAX_BSSID_PER_CHANNEL		16
+
+/* For the extended Scan */
+#define MAX_EXTENDED_SCAN_BSSID_LIST    MAX_BSSID_PER_CHANNEL * \
+						MRVDRV_MAX_CHANNEL_SIZE + 1
+
+typedef struct _PER_CHANNEL_BSSID_LIST_DATA
+{
+    u8 ucStart;
+    u8 ucNumEntry;
+} PER_CHANNEL_BSSID_LIST_DATA, *PPER_CHANNEL_BSSID_LIST_DATA;
+
+typedef struct _MRV_BSSID_IE_LIST
+{
+    WLAN_802_11_FIXED_IEs FixedIE;
+    u8 VariableIE[MRVDRV_SCAN_LIST_VAR_IE_SPACE];
+} MRV_BSSID_IE_LIST, *PMRV_BSSID_IE_LIST;
+
+#define	MAX_REGION_CHANNEL_NUM	2
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _CHANNEL_FREQ_POWER
+{
+        /** Channel Number		*/
+    u16 Channel;
+        /** Frequency of this Channel	*/
+    u32 Freq;
+        /** Max allowed Tx power level	*/
+    u16 MaxTxPower;
+        /** TRUE:channel unsupported;  FLASE:supported*/
+    BOOLEAN Unsupported;
+} CHANNEL_FREQ_POWER;
+
+/** region-band mapping table*/
+typedef struct _REGION_CHANNEL
+{
+        /** TRUE if this entry is valid		     */
+    BOOLEAN Valid;
+        /** Region code for US, Japan ...	     */
+    u8 Region;
+        /** Band B/G/A, used for BAND_CONFIG cmd	     */
+    u8 Band;
+        /** Actual No. of elements in the array below */
+    u8 NrCFP;
+        /** chan-freq-txpower mapping table*/
+    CHANNEL_FREQ_POWER *CFP;
+} REGION_CHANNEL;
+
+typedef struct _wlan_802_11_security_t
+{
+    BOOLEAN WPAEnabled;
+    BOOLEAN WPA2Enabled;
+    WLAN_802_11_WEP_STATUS WEPStatus;
+    WLAN_802_11_AUTHENTICATION_MODE AuthenticationMode;
+    WLAN_802_11_ENCRYPTION_MODE EncryptionMode;
+} wlan_802_11_security_t;
+
+/** Current Basic Service Set State Structure */
+typedef struct
+{
+    BSSDescriptor_t BSSDescriptor;
+
+        /** band */
+    u8 band;
+
+        /** number of rates supported */
+    int NumOfRates;
+
+        /** supported rates*/
+    u8 DataRates[WLAN_SUPPORTED_RATES];
+
+        /** wmm enable? */
+    u8 wmm_enabled;
+
+        /** uapsd enable?*/
+    u8 wmm_uapsd_enabled;
+} CurrentBSSParams_t;
+
+/** sleep_params */
+typedef struct SleepParams
+{
+    u16 sp_error;
+    u16 sp_offset;
+    u16 sp_stabletime;
+    u8 sp_calcontrol;
+    u8 sp_extsleepclk;
+    u16 sp_reserved;
+} SleepParams;
+
+/** sleep_period */
+typedef struct SleepPeriod
+{
+    u16 period;
+    u16 reserved;
+} SleepPeriod;
+
+#define DBG_CMD_NUM	5
+
+/** info for debug purpose */
+typedef struct _wlan_dbg
+{
+    u32 num_cmd_host_to_card_failure;
+    u32 num_cmd_sleep_cfm_host_to_card_failure;
+    u32 num_tx_host_to_card_failure;
+    u32 num_event_deauth;
+    u32 num_event_disassoc;
+    u32 num_event_link_lost;
+    u32 num_cmd_deauth;
+    u32 num_cmd_assoc_success;
+    u32 num_cmd_assoc_failure;
+    u32 num_tx_timeout;
+    u32 num_cmd_timeout;
+    u16 TimeoutCmdId;
+    u16 TimeoutCmdAct;
+    u16 LastCmdId[DBG_CMD_NUM];
+    u16 LastCmdAct[DBG_CMD_NUM];
+    u16 LastCmdIndex;
+    u16 LastCmdRespId[DBG_CMD_NUM];
+    u16 LastCmdRespIndex;
+    u16 LastEvent[DBG_CMD_NUM];
+    u16 LastEventIndex;
+} wlan_dbg;
+
+/** Data structure for the Marvell WLAN device */
+typedef struct _wlan_dev
+{
+        /** device name */
+    char name[DEV_NAME_LEN];
+        /** card pointer */
+    void *card;
+        /** IO port */
+    u32 ioport;
+        /** Upload received */
+    u32 upld_rcv;
+        /** Upload type */
+    u32 upld_typ;
+        /** Upload length */
+    u32 upld_len;
+        /** netdev pointer */
+    struct net_device *netdev;
+    /* Upload buffer */
+    u8 upld_buf[WLAN_UPLD_SIZE];
+    /* Download sent: 
+       bit0 1/0=data_sent/data_tx_done, 
+       bit1 1/0=cmd_sent/cmd_tx_done, 
+       all other bits reserved 0 */
+    u8 dnld_sent;
+} wlan_dev_t, *pwlan_dev_t;
+
+/* Data structure for WPS information */
+typedef struct
+{
+    IEEEtypes_VendorSpecific_t wpsIe;
+    BOOLEAN SessionEnable;
+} wps_t;
+
+/** Private structure for the MV device */
+struct _wlan_private
+{
+    int open;
+
+    wlan_adapter *adapter;
+    wlan_dev_t wlan_dev;
+
+    struct net_device_stats stats;
+
+    struct iw_statistics wstats;
+#ifdef CONFIG_PROC_FS
+    struct proc_dir_entry *proc_entry;
+    struct proc_dir_entry *proc_dev;
+#endif
+    const struct firmware *fw_helper;
+    const struct firmware *firmware;
+    struct device *hotplug_device;
+
+        /** thread to service interrupts */
+    wlan_thread MainThread;
+
+#ifdef REASSOCIATION
+        /** thread to service mac events */
+    wlan_thread ReassocThread;
+#endif                          /* REASSOCIATION */
+};
+
+/** Wlan Adapter data structure*/
+struct _wlan_adapter
+{
+    u8 TmpTxBuf[WLAN_UPLD_SIZE] __ATTRIB_ALIGN__;
+        /** STATUS variables */
+    WLAN_HARDWARE_STATUS HardwareStatus;
+    u32 FWReleaseNumber;
+    u32 fwCapInfo;
+    u8 chip_rev;
+
+        /** Command-related variables */
+    u16 SeqNum;
+    CmdCtrlNode *CmdArray;
+        /** Current Command */
+    CmdCtrlNode *CurCmd;
+    int CurCmdRetCode;
+
+        /** Command Queues */
+        /** Free command buffers */
+    struct list_head CmdFreeQ;
+        /** Pending command buffers */
+    struct list_head CmdPendingQ;
+
+        /** Variables brought in from private structure */
+    int irq;
+
+        /** Async and Sync Event variables */
+    u32 IntCounter;
+    u32 IntCounterSaved;        /* save int for DS/PS */
+    u32 EventCause;
+    u8 nodeName[16];            /* nickname */
+
+        /** spin locks */
+    spinlock_t QueueSpinLock __ATTRIB_ALIGN__;
+
+        /** Timers */
+    WLAN_DRV_TIMER MrvDrvCommandTimer __ATTRIB_ALIGN__;
+    BOOLEAN CommandTimerIsSet;
+
+#ifdef REASSOCIATION
+        /**Reassociation timer*/
+    BOOLEAN ReassocTimerIsSet;
+    WLAN_DRV_TIMER MrvDrvTimer __ATTRIB_ALIGN__;
+#endif                          /* REASSOCIATION */
+
+        /** Event Queues */
+    wait_queue_head_t ds_awake_q __ATTRIB_ALIGN__;
+
+    u8 HisRegCpy;
+
+    /** bg scan related variable */
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *bgScanConfig;
+    u32 bgScanConfigSize;
+
+    /** WMM related variable*/
+    WMM_DESC wmm;
+
+        /** current ssid/bssid related parameters*/
+    CurrentBSSParams_t CurBssParams;
+
+    WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+
+    BSSDescriptor_t *pAttemptedBSSDesc;
+
+    WLAN_802_11_SSID AttemptedSSIDBeforeScan;
+    WLAN_802_11_SSID PreviousSSID;
+    u8 PreviousBSSID[MRVDRV_ETH_ADDR_LEN];
+
+    BSSDescriptor_t *ScanTable;
+    u32 NumInScanTable;
+
+    u8 ScanType;
+    u32 ScanMode;
+    u16 SpecificScanTime;
+    u16 ActiveScanTime;
+    u16 PassiveScanTime;
+
+    u16 BeaconPeriod;
+    u8 AdhocCreate;
+    BOOLEAN AdhocLinkSensed;
+
+#ifdef REASSOCIATION
+        /** Reassociation on and off */
+    BOOLEAN Reassoc_on;
+    SEMAPHORE ReassocSem;
+#endif                          /* REASSOCIATION */
+
+    BOOLEAN ATIMEnabled;
+
+        /** MAC address information */
+    u8 CurrentAddr[MRVDRV_ETH_ADDR_LEN];
+    u8 MulticastList[MRVDRV_MAX_MULTICAST_LIST_SIZE]
+        [MRVDRV_ETH_ADDR_LEN];
+    u32 NumOfMulticastMACAddr;
+
+    u16 HWRateDropMode;
+    u16 RateBitmap;
+    u16 Threshold;
+    u16 FinalRate;
+        /** control G Rates */
+    BOOLEAN adhoc_grate_enabled;
+
+    WLAN_802_11_ANTENNA TxAntenna;
+    WLAN_802_11_ANTENNA RxAntenna;
+
+    u8 AdhocChannel;
+    WLAN_802_11_FRAGMENTATION_THRESHOLD FragThsd;
+    WLAN_802_11_RTS_THRESHOLD RTSThsd;
+
+    u32 DataRate;
+    BOOLEAN Is_DataRate_Auto;
+
+        /** number of association attempts for the current SSID cmd */
+    u16 ListenInterval;
+    u8 TxRetryCount;
+
+        /** Tx-related variables (for single packet tx) */
+    struct sk_buff *CurrentTxSkb;
+    struct sk_buff RxSkbQ;
+    BOOLEAN TxLockFlag;
+    u16 gen_null_pkg;
+    spinlock_t CurrentTxLock __ATTRIB_ALIGN__;
+
+        /** NIC Operation characteristics */
+    u16 CurrentPacketFilter;
+    u32 MediaConnectStatus;
+    u16 RegionCode;
+    u16 TxPowerLevel;
+    u8 MaxTxPowerLevel;
+    u8 MinTxPowerLevel;
+
+        /** POWER MANAGEMENT AND PnP SUPPORT */
+    BOOLEAN SurpriseRemoved;
+    u16 AtimWindow;
+
+    u16 PSMode;                 /* Wlan802_11PowerModeCAM=disable
+                                   Wlan802_11PowerModeMAX_PSP=enable */
+    u16 MultipleDtim;
+    u16 BCNMissTimeOut;
+    u32 PSState;
+    BOOLEAN NeedToWakeup;
+
+    PS_CMD_ConfirmSleep PSConfirmSleep;
+    u16 LocalListenInterval;
+    u16 NullPktInterval;
+    u16 AdhocAwakePeriod;
+    u16 fwWakeupMethod;
+    BOOLEAN IsDeepSleep;
+    BOOLEAN IsAutoDeepSleepEnabled;
+    BOOLEAN bWakeupDevRequired;
+    u32 WakeupTries;
+    BOOLEAN bHostSleepConfigured;
+    HostCmd_DS_802_11_HOST_SLEEP_CFG HSCfg;
+        /** ARP filter related variable */
+    u8 ArpFilter[ARP_FILTER_MAX_BUF_SIZE];
+    u32 ArpFilterSize;
+    BOOLEAN HS_Activated;
+
+        /** Encryption parameter */
+    wlan_802_11_security_t SecInfo;
+
+    MRVL_WEP_KEY WepKey[MRVL_NUM_WEP_KEY];
+    u16 CurrentWepKeyIndex;
+
+    /** Buffer for TLVs passed from the application to be inserted into the
+     *    association request to firmware 
+     */
+    u8 mrvlAssocTlvBuffer[MRVDRV_ASSOC_TLV_BUF_SIZE];
+
+    /** Length of the data stored in mrvlAssocTlvBuffer*/
+    u8 mrvlAssocTlvBufferLen;
+
+    /** Buffer to store the association response for application retrieval */
+    u8 assocRspBuffer[MRVDRV_ASSOC_RSP_BUF_SIZE];
+
+    /** Length of the data stored in assocRspBuffer */
+    int assocRspSize;
+
+    /** Generice IEEE IEs passed from the application to be inserted into the
+     *    association request to firmware 
+     */
+    u8 genIeBuffer[MRVDRV_GENIE_BUF_SIZE];
+
+    /** Length of the data stored in genIeBuffer */
+    u8 genIeBufferLen;
+
+    BOOLEAN IsGTK_SET;
+
+        /** Encryption Key*/
+    u8 Wpa_ie[256];
+    u8 Wpa_ie_len;
+
+    HostCmd_DS_802_11_KEY_MATERIAL aeskey;
+
+    /* Advanced Encryption Standard */
+    BOOLEAN AdhocAESEnabled;
+    wait_queue_head_t cmd_EncKey __ATTRIB_ALIGN__;
+
+    u16 RxAntennaMode;
+    u16 TxAntennaMode;
+
+        /** Requested Signal Strength*/
+    u16 bcn_avg_factor;
+    u16 data_avg_factor;
+    u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+    u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+    u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+    u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
+    u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+    u16 nextSNRNF;
+    u16 numSNRNF;
+    u32 RxPDAge;
+    u16 RxPDRate;
+
+    BOOLEAN RadioOn;
+
+        /** Blue Tooth Co-existence Arbitration */
+    HostCmd_DS_802_11_BCA_TIMESHARE bca_ts;
+
+        /** sleep_params */
+    SleepParams sp;
+
+        /** sleep_period (Enhanced Power Save) */
+    SleepPeriod sleep_period;
+
+#define	MAX_REGION_CHANNEL_NUM	2
+        /** Region Channel data */
+    REGION_CHANNEL region_channel[MAX_REGION_CHANNEL_NUM];
+
+    REGION_CHANNEL universal_channel[MAX_REGION_CHANNEL_NUM];
+
+        /** 11D and Domain Regulatory Data */
+    wlan_802_11d_domain_reg_t DomainReg;
+    parsed_region_chan_11d_t parsed_region_chan;
+
+        /** FSM variable for 11d support */
+    wlan_802_11d_state_t State11D;
+    u8 beaconBuffer[MAX_SCAN_BEACON_BUFFER];
+    u8 *pBeaconBufEnd;
+
+        /**	MISCELLANEOUS */
+    /* Card Information Structure */
+    u8 CisInfoBuf[512];
+    u16 CisInfoLen;
+
+    HostCmd_DS_802_11_GET_LOG LogMsg;
+    u16 ScanProbes;
+
+    u32 PktTxCtrl;
+
+    u16 TxRate;
+
+    wps_t wps;
+
+    wlan_dbg dbg;
+    wlan_subscribe_event subevent;
+    u32 num_cmd_timeout;
+};
+
+#endif /* _WLAN_DEV_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_fw.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_fw.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_fw.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_fw.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,500 @@
+/** @file wlan_fw.c
+  * @brief This file contains the initialization for FW
+  * and HW
+  *
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  * 
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	09/28/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join functions.
+	          Cleanup association response handler initialization.
+	01/06/05: Add FW file read
+	05/08/06: Remove the 2nd GET_HW_SPEC command and TempAddr/PermanentAddr
+	06/30/06: replaced MODULE_PARM(name, type) with module_param(name, type, perm)
+
+********************************************************/
+
+#include	"include.h"
+#include <linux/vmalloc.h>
+
+#include	<linux/firmware.h>
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+char *helper_name = NULL;
+char *fw_name = NULL;
+
+module_param(helper_name, charp, 0);
+module_param(fw_name, charp, 0);
+
+#ifdef MFG_CMD_SUPPORT
+int mfgmode = 0;
+module_param(mfgmode, int, 0);
+#endif
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function downloads firmware image, gets
+ *  HW spec from firmware and set basic parameters to
+ *  firmware.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_setup_station_hw(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    sbi_disable_host_int(priv);
+
+    if ((ret =
+         request_firmware(&priv->fw_helper, helper_name,
+                          priv->hotplug_device)) < 0) {
+        PRINTM(FATAL,
+               "request_firmware() failed (helper), error code = %#x\n", ret);
+        goto done;
+    }
+
+    if ((ret =
+         request_firmware(&priv->firmware, fw_name,
+                          priv->hotplug_device)) < 0) {
+        PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
+        goto done;
+    }
+
+    /* Download the helper */
+    ret = sbi_prog_helper(priv);
+
+    if (ret) {
+        PRINTM(INFO, "Bootloader in invalid state!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    /* Download the main firmware via the helper firmware */
+    if (sbi_prog_firmware_w_helper(priv)) {
+        PRINTM(INFO, "Wlan FW download failed!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* check if the fimware is downloaded successfully or not */
+    if (sbi_verify_fw_download(priv)) {
+        PRINTM(INFO, "FW failed to be active in time!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+#define RF_REG_OFFSET 0x07
+#define RF_REG_VALUE  0xc8
+
+    sbi_enable_host_int(priv);
+
+#ifdef MFG_CMD_SUPPORT
+    if (mfgmode == 0) {
+#endif
+
+        /*
+         * Read MAC address from HW
+         */
+        memset(adapter->CurrentAddr, 0xff, MRVDRV_ETH_ADDR_LEN);
+
+        ret = PrepareAndSendCommand(priv, HostCmd_CMD_GET_HW_SPEC,
+                                    0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_MAC_CONTROL,
+                                    0, HostCmd_OPTION_WAITFORRSP, 0,
+                                    &adapter->CurrentPacketFilter);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_FW_WAKE_METHOD,
+                                    HostCmd_ACT_GET,
+                                    HostCmd_OPTION_WAITFORRSP, 0,
+                                    &priv->adapter->fwWakeupMethod);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+#ifdef MFG_CMD_SUPPORT
+    }
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+    if (mfgmode == 0) {
+#endif
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                                    HostCmd_ACT_GEN_GET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, NULL);
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        priv->adapter->DataRate = 0;
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_RF_TX_POWER,
+                                    HostCmd_ACT_GEN_GET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+#ifdef MFG_CMD_SUPPORT
+    }
+#endif
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    if (priv->fw_helper) {
+        release_firmware(priv->fw_helper);
+    }
+    if (priv->firmware) {
+        release_firmware(priv->firmware);
+    }
+
+    LEAVE();
+
+    return (ret);
+}
+
+/** 
+ *  @brief This function initializes timers.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+static void
+init_sync_objects(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    InitializeTimer(&Adapter->MrvDrvCommandTimer,
+                    MrvDrvCommandTimerFunction, priv);
+    Adapter->CommandTimerIsSet = FALSE;
+
+#ifdef REASSOCIATION
+    /* Initialize the timer for the reassociation */
+    InitializeTimer(&Adapter->MrvDrvTimer, MrvDrvReassocTimerFunction, priv);
+    Adapter->ReassocTimerIsSet = FALSE;
+#endif /* REASSOCIATION */
+
+    return;
+}
+
+/** 
+ *  @brief This function allocates buffer for the member of adapter
+ *  structure like command buffer and BSSID list.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_allocate_adapter(wlan_private * priv)
+{
+    u32 ulBufSize;
+    wlan_adapter *Adapter = priv->adapter;
+
+    BSSDescriptor_t *pTempScanTable;
+
+    /* Allocate buffer to store the BSSID list */
+    ulBufSize = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
+    if (!(pTempScanTable = kmalloc(ulBufSize, GFP_KERNEL))) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    Adapter->ScanTable = pTempScanTable;
+    memset(Adapter->ScanTable, 0, ulBufSize);
+
+    if (!(Adapter->bgScanConfig =
+          kmalloc(sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG), GFP_KERNEL))) {
+        return WLAN_STATUS_FAILURE;
+    }
+    Adapter->bgScanConfigSize = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
+    memset(Adapter->bgScanConfig, 0, Adapter->bgScanConfigSize);
+
+    spin_lock_init(&Adapter->QueueSpinLock);
+
+    /* Allocate the command buffers */
+    if (AllocateCmdBuffer(priv) != WLAN_STATUS_SUCCESS) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memset(&Adapter->PSConfirmSleep, 0, sizeof(PS_CMD_ConfirmSleep));
+    Adapter->PSConfirmSleep.SeqNum = wlan_cpu_to_le16(++Adapter->SeqNum);
+    Adapter->PSConfirmSleep.Command =
+        wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE);
+    Adapter->PSConfirmSleep.Size =
+        wlan_cpu_to_le16(sizeof(PS_CMD_ConfirmSleep));
+    Adapter->PSConfirmSleep.Result = 0;
+    Adapter->PSConfirmSleep.Action =
+        wlan_cpu_to_le16(HostCmd_SubCmd_Sleep_Confirmed);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function initializes the adapter structure
+ *  and set default value to the member of adapter.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+static void
+wlan_init_adapter(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+
+    Adapter->ScanProbes = 0;
+
+    Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+    Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+    /* ATIM params */
+    Adapter->AtimWindow = 0;
+    Adapter->ATIMEnabled = FALSE;
+
+    Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
+
+    memset(Adapter->CurrentAddr, 0xff, MRVDRV_ETH_ADDR_LEN);
+
+    /* Status variables */
+    Adapter->HardwareStatus = WlanHardwareStatusInitializing;
+
+    /* scan type */
+    Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE;
+
+    /* scan mode */
+    Adapter->ScanMode = HostCmd_BSS_TYPE_ANY;
+
+    /* scan time */
+    Adapter->SpecificScanTime = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
+    Adapter->ActiveScanTime = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+    Adapter->PassiveScanTime = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+
+    /* 802.11 specific */
+    Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled;
+    for (i = 0; i < sizeof(Adapter->WepKey) / sizeof(Adapter->WepKey[0]); i++)
+        memset(&Adapter->WepKey[i], 0, sizeof(MRVL_WEP_KEY));
+    Adapter->CurrentWepKeyIndex = 0;
+    Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+    Adapter->SecInfo.EncryptionMode = CIPHER_NONE;
+    Adapter->AdhocAESEnabled = FALSE;
+    Adapter->InfrastructureMode = Wlan802_11Infrastructure;
+
+    Adapter->NumInScanTable = 0;
+    Adapter->pAttemptedBSSDesc = NULL;
+#ifdef REASSOCIATION
+    OS_INIT_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+    Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
+
+    Adapter->HisRegCpy |= HIS_TxDnLdRdy;
+
+    memset(&Adapter->CurBssParams, 0, sizeof(Adapter->CurBssParams));
+
+    /* PnP and power profile */
+    Adapter->SurpriseRemoved = FALSE;
+
+    Adapter->CurrentPacketFilter =
+        HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON;
+
+    Adapter->RadioOn = RADIO_ON;
+#ifdef REASSOCIATION
+#if (WIRELESS_EXT >= 18)
+    Adapter->Reassoc_on = FALSE;
+#else
+    Adapter->Reassoc_on = TRUE;
+#endif
+#endif /* REASSOCIATION */
+    Adapter->TxAntenna = RF_ANTENNA_2;
+    Adapter->RxAntenna = RF_ANTENNA_AUTO;
+
+    Adapter->HWRateDropMode = HW_TABLE_RATE_DROP;
+    Adapter->Is_DataRate_Auto = TRUE;
+    Adapter->BeaconPeriod = MRVDRV_BEACON_INTERVAL;
+
+    Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+
+    Adapter->PSMode = Wlan802_11PowerModeCAM;
+    Adapter->MultipleDtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+    Adapter->ListenInterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+    Adapter->PSState = PS_STATE_FULL_POWER;
+    Adapter->NeedToWakeup = FALSE;
+    Adapter->LocalListenInterval = 0;   /* default value in firmware will be used */
+    Adapter->fwWakeupMethod = WAKEUP_FW_UNCHANGED;
+
+    Adapter->IsDeepSleep = FALSE;
+    Adapter->IsAutoDeepSleepEnabled = FALSE;
+
+    Adapter->bWakeupDevRequired = FALSE;
+    Adapter->WakeupTries = 0;
+    Adapter->bHostSleepConfigured = FALSE;
+    Adapter->HSCfg.conditions = HOST_SLEEP_CFG_CANCEL;
+    Adapter->HSCfg.gpio = 0;
+    Adapter->HSCfg.gap = 0;
+
+    Adapter->DataRate = 0;      // Initially indicate the rate as auto 
+
+    Adapter->adhoc_grate_enabled = FALSE;
+
+    Adapter->IntCounter = Adapter->IntCounterSaved = 0;
+
+    INIT_LIST_HEAD((struct list_head *) &Adapter->RxSkbQ);
+
+    Adapter->gen_null_pkg = TRUE;       /*Enable NULL Pkg generation */
+
+    init_waitqueue_head(&Adapter->cmd_EncKey);
+
+    spin_lock_init(&Adapter->CurrentTxLock);
+
+    Adapter->CurrentTxSkb = NULL;
+    Adapter->PktTxCtrl = 0;
+
+    return;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function initializes firmware
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_init_fw(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* Allocate adapter structure */
+    if ((ret = wlan_allocate_adapter(priv)) != WLAN_STATUS_SUCCESS) {
+        goto done;
+    }
+
+    /* init adapter structure */
+    wlan_init_adapter(priv);
+
+    /* init timer etc. */
+    init_sync_objects(priv);
+
+    /* download fimrware etc. */
+    if ((ret = wlan_setup_station_hw(priv)) != WLAN_STATUS_SUCCESS) {
+        Adapter->HardwareStatus = WlanHardwareStatusNotReady;
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    /* init 802.11d */
+    wlan_init_11d(priv);
+
+    Adapter->HardwareStatus = WlanHardwareStatusReady;
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function frees the structure of adapter
+ *    
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void
+wlan_free_adapter(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Adapter) {
+        PRINTM(INFO, "Why double free adapter?:)\n");
+        return;
+    }
+
+    PRINTM(INFO, "Free Command buffer\n");
+    FreeCmdBuffer(priv);
+
+    PRINTM(INFO, "Free CommandTimer\n");
+    if (Adapter->CommandTimerIsSet) {
+        CancelTimer(&Adapter->MrvDrvCommandTimer);
+        Adapter->CommandTimerIsSet = FALSE;
+    }
+    FreeTimer(&Adapter->MrvDrvCommandTimer);
+#ifdef REASSOCIATION
+    PRINTM(INFO, "Free MrvDrvTimer\n");
+    if (Adapter->ReassocTimerIsSet) {
+        CancelTimer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+    FreeTimer(&Adapter->MrvDrvTimer);
+#endif /* REASSOCIATION */
+
+    if (Adapter->bgScanConfig) {
+        kfree(Adapter->bgScanConfig);
+        Adapter->bgScanConfig = NULL;
+    }
+
+    OS_FREE_LOCK(&Adapter->CurrentTxLock);
+    OS_FREE_LOCK(&Adapter->QueueSpinLock);
+
+    PRINTM(INFO, "Free ScanTable\n");
+    if (Adapter->ScanTable) {
+        kfree(Adapter->ScanTable);
+        Adapter->ScanTable = NULL;
+    }
+
+    PRINTM(INFO, "Free Adapter\n");
+
+    /* Free the adapter object itself */
+    kfree(Adapter);
+    priv->adapter = NULL;
+    LEAVE();
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_join.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_join.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_join.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_join.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,2030 @@
+/** @file wlan_join.c
+ *
+ *  @brief Functions implementing wlan infrastructure and adhoc join routines
+ *
+ *  IOCTL handlers as well as command preperation and response routines
+ *   for sending adhoc start, adhoc join, and association commands
+ *   to the firmware.
+ *  
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *   
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    01/11/06: Initial revision. Match new scan code, relocate related functions
+    01/19/06: Fix failure to save adhoc ssid as current after adhoc start
+    03/16/06: Add a semaphore to protect reassociation thread
+
+************************************************************/
+
+#include    "include.h"
+
+/**
+ *  @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ *   care, either before or after calling this function
+ *
+ *  @param Adapter     A pointer to wlan_adapter structure
+ *  @param rate1       the buffer which keeps input and output
+ *  @param rate1_size  the size of rate1 buffer
+ *  @param rate2       the buffer which keeps rate2
+ *  @param rate2_size  the size of rate2 buffer.
+ *
+ *  @return            WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+get_common_rates(wlan_adapter * Adapter, u8 * rate1,
+                 int rate1_size, u8 * rate2, int rate2_size)
+{
+    u8 *ptr = rate1;
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 *tmp = NULL;
+    int i, j;
+
+    if (!(tmp = kmalloc(rate1_size, GFP_KERNEL))) {
+        PRINTM(WARN, "Allocate buffer for common rates failed\n");
+        return -ENOMEM;
+    }
+
+    memcpy(tmp, rate1, rate1_size);
+    memset(rate1, 0, rate1_size);
+
+    for (i = 0; rate2[i] && i < rate2_size; i++) {
+        for (j = 0; tmp[j] && j < rate1_size; j++) {
+            /* Check common rate, excluding the bit for basic rate */
+            if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+                *rate1++ = tmp[j];
+                break;
+            }
+        }
+    }
+
+    HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
+    HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
+    HEXDUMP("Common Rates", ptr, rate1 - ptr);
+    PRINTM(INFO, "Tx DataRate is set to 0x%X\n", Adapter->DataRate);
+
+    if (!Adapter->Is_DataRate_Auto) {
+        while (*ptr) {
+            if ((*ptr & 0x7f) == Adapter->DataRate) {
+                ret = WLAN_STATUS_SUCCESS;
+                goto done;
+            }
+            ptr++;
+        }
+        PRINTM(MSG, "Previously set fixed data rate %#x isn't "
+               "compatible with the network.\n", Adapter->DataRate);
+
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    kfree(tmp);
+    return ret;
+}
+
+/**
+ *  @brief Create the intersection of the rates supported by a target BSS and
+ *         our Adapter settings for use in an assoc/join command.
+ *
+ *  @param Adapter       A pointer to wlan_adapter structure
+ *  @param pBSSDesc      BSS Descriptor whose rates are used in the setup
+ *  @param pOutRates     Output: Octet array of rates common between the BSS
+ *                       and the Adapter supported rates settings
+ *  @param pOutRatesSize Output: Number of rates/octets set in pOutRates
+ *
+ *  @return              WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ */
+static int
+setup_rates_from_bssdesc(wlan_adapter * Adapter,
+                         BSSDescriptor_t * pBSSDesc,
+                         u8 * pOutRates, int *pOutRatesSize)
+{
+    u8 *card_rates;
+    int card_rates_size;
+
+    ENTER();
+
+    memcpy(pOutRates, pBSSDesc->SupportedRates, WLAN_SUPPORTED_RATES);
+
+    card_rates = SupportedRates;
+    card_rates_size = sizeof(SupportedRates);
+
+    if (get_common_rates(Adapter, pOutRates, WLAN_SUPPORTED_RATES,
+                         card_rates, card_rates_size)) {
+        *pOutRatesSize = 0;
+        PRINTM(INFO, "get_common_rates failed\n");
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    *pOutRatesSize = MIN(strlen(pOutRates), WLAN_SUPPORTED_RATES);
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Retrieve the association response
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_assoc_rsp_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int copySize;
+
+    /*
+     * Set the amount to copy back to the application as the minimum of the
+     *   available assoc resp data or the buffer provided by the application
+     */
+    copySize = MIN(Adapter->assocRspSize, wrq->u.data.length);
+
+    /* Copy the (re)association response back to the application */
+    if (copy_to_user(wrq->u.data.pointer, Adapter->assocRspBuffer, copySize)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    /* Returned copy length */
+    wrq->u.data.length = copySize;
+
+    /* Reset assoc buffer */
+    Adapter->assocRspSize = 0;
+
+    /* No error on return */
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Set an opaque block of Marvell TLVs for insertion into the
+ *         association command
+ *
+ *  Pass an opaque block of data, expected to be Marvell TLVs, to the driver
+ *    for eventual passthrough to the firmware in an associate/join
+ *    (and potentially start) command.
+ *
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_mrvl_tlv_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    /* If the passed length is zero, reset the buffer */
+    if (wrq->u.data.length == 0) {
+        Adapter->mrvlAssocTlvBufferLen = 0;
+    } else {
+        /*
+         * Verify that the passed length is not larger than the available
+         *   space remaining in the buffer
+         */
+        if (wrq->u.data.length < (sizeof(Adapter->mrvlAssocTlvBuffer)
+                                  - Adapter->mrvlAssocTlvBufferLen)) {
+            /* Append the passed data to the end of the mrvlAssocTlvBuffer */
+            if (copy_from_user(Adapter->mrvlAssocTlvBuffer
+                               + Adapter->mrvlAssocTlvBufferLen,
+                               wrq->u.data.pointer, wrq->u.data.length)) {
+                PRINTM(INFO, "Copy from user failed\n");
+                return -EFAULT;
+            }
+
+            /* Increment the stored buffer length by the size passed */
+            Adapter->mrvlAssocTlvBufferLen += wrq->u.data.length;
+        } else {
+            /* Passed data does not fit in the remaining buffer space */
+            ret = WLAN_STATUS_FAILURE;
+        }
+    }
+
+    /* Return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE */
+    return ret;
+}
+
+/**
+ *  @brief Stop Adhoc Network
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_do_adhocstop_ioctl(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode == Wlan802_11IBSS &&
+        Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+        ret = StopAdhocNetwork(priv);
+
+    } else {
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Set essid
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    WLAN_802_11_SSID reqSSID;
+    int i;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    /* Clear any past association response stored for application retrieval */
+    Adapter->assocRspSize = 0;
+
+#ifdef REASSOCIATION
+    // cancel re-association timer if there's one
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        CancelTimer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_set_essid\n");
+        return -EBUSY;
+    }
+#endif /* REASSOCIATION */
+
+    /* Check the size of the string */
+    //if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {	//mid
+    	if (dwrq->length > IW_ESSID_MAX_SIZE ) {
+	        ret = -E2BIG;
+	        goto setessid_ret;
+    	}
+
+    memset(&reqSSID, 0, sizeof(WLAN_802_11_SSID));
+
+    /*
+     * Check if we asked for `any' or 'particular'
+     */
+    if (!dwrq->flags) {
+        if (FindBestNetworkSsid(priv, &reqSSID)) {
+            PRINTM(INFO, "Could not find best network\n");
+            ret = WLAN_STATUS_SUCCESS;
+            goto setessid_ret;
+        }
+    } else {
+        /* Set the SSID */
+        //reqSSID.SsidLength = dwrq->length - 1;	//mid
+        reqSSID.SsidLength = dwrq->length;
+        memcpy(reqSSID.Ssid, extra, reqSSID.SsidLength);
+
+    }
+
+    PRINTM(INFO, "Requested new SSID = %s\n",
+           (reqSSID.SsidLength > 0) ? (char *) reqSSID.Ssid : "NULL");
+
+    if (!reqSSID.SsidLength || reqSSID.Ssid[0] < 0x20) {
+        PRINTM(INFO, "Invalid SSID - aborting set_essid\n");
+        ret = -EINVAL;
+        goto setessid_ret;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+        /* infrastructure mode */
+        PRINTM(INFO, "SSID requested = %s\n", reqSSID.Ssid);
+
+        if ((dwrq->flags & IW_ENCODE_INDEX) > 1) {
+            i = (dwrq->flags & IW_ENCODE_INDEX) - 1;    /* convert to 0 based */
+
+            PRINTM(INFO, "Request SSID by index = %d\n", i);
+
+            if (i > Adapter->NumInScanTable) {
+                /* Failed to find in table since index is > current max. */
+                i = -EINVAL;
+            }
+        } else {
+            SendSpecificSSIDScan(priv, &reqSSID);
+            i = FindSSIDInList(Adapter,
+                               &reqSSID, NULL, Wlan802_11Infrastructure);
+        }
+
+        if (i >= 0) {
+            PRINTM(INFO, "SSID found in scan list ... associating...\n");
+
+            ret = wlan_associate(priv, &Adapter->ScanTable[i]);
+
+            if (ret) {
+                goto setessid_ret;
+            }
+        } else {                /* i >= 0 */
+            ret = i;            /* return -ENETUNREACH, passed from FindSSIDInList */
+            goto setessid_ret;
+        }
+    } else {
+        /* ad hoc mode */
+        /* If the requested SSID matches current SSID return */
+        if (!SSIDcmp(&Adapter->CurBssParams.BSSDescriptor.Ssid, &reqSSID)) {
+            ret = WLAN_STATUS_SUCCESS;
+            goto setessid_ret;
+        }
+
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            /*
+             * Exit Adhoc mode
+             */
+            PRINTM(INFO, "Sending Adhoc Stop\n");
+            ret = StopAdhocNetwork(priv);
+
+            if (ret) {
+                goto setessid_ret;
+            }
+        }
+        Adapter->AdhocLinkSensed = FALSE;
+
+        if ((dwrq->flags & IW_ENCODE_INDEX) > 1) {
+            i = (dwrq->flags & IW_ENCODE_INDEX) - 1;    /* 0 based */
+            if (i > Adapter->NumInScanTable) {
+                /* Failed to find in table since index is > current max. */
+                i = -EINVAL;
+            }
+        } else {
+            /* Scan for the network */
+            SendSpecificSSIDScan(priv, &reqSSID);
+
+            /* Search for the requested SSID in the scan table */
+            i = FindSSIDInList(Adapter, &reqSSID, NULL, Wlan802_11IBSS);
+        }
+
+        if (i >= 0) {
+            PRINTM(INFO, "SSID found at %d in List, so join\n", i);
+            JoinAdhocNetwork(priv, &Adapter->ScanTable[i]);
+        } else {
+            /* else send START command */
+            PRINTM(INFO, "SSID not found in list, "
+                   "so creating adhoc with ssid = %s\n", reqSSID.Ssid);
+
+            StartAdhocNetwork(priv, &reqSSID);
+        }                       /* end of else (START command) */
+    }                           /* end of else (Ad hoc mode) */
+
+    /*
+     * The MediaConnectStatus change can be removed later when
+     *   the ret code is being properly returned.
+     */
+    /* Check to see if we successfully connected */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        ret = WLAN_STATUS_SUCCESS;
+    } else {
+        ret = -ENETDOWN;
+    }
+
+  setessid_ret:
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * NOTE: Scan should be issued by application before this function is called
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param awrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+             struct sockaddr *awrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
+    u8 reqBSSID[ETH_ALEN];
+    int i;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    /* Clear any past association response stored for application retrieval */
+    Adapter->assocRspSize = 0;
+
+    if (awrq->sa_family != ARPHRD_ETHER)
+        return -EINVAL;
+
+    PRINTM(INFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n",
+           (u8) awrq->sa_data[0], (u8) awrq->sa_data[1],
+           (u8) awrq->sa_data[2], (u8) awrq->sa_data[3],
+           (u8) awrq->sa_data[4], (u8) awrq->sa_data[5]);
+
+#ifdef REASSOCIATION
+    // cancel re-association timer if there's one
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        CancelTimer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+#endif /* REASSOCIATION */
+
+    if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
+        i = FindBestSSIDInList(Adapter);
+    } else {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            if (memcmp
+                (awrq->sa_data,
+                 Adapter->CurBssParams.BSSDescriptor.MacAddress,
+                 ETH_ALEN) == 0)
+                return WLAN_STATUS_SUCCESS;
+        }
+        memcpy(reqBSSID, awrq->sa_data, ETH_ALEN);
+
+        PRINTM(INFO, "ASSOC: WAP: Bssid = %02x:%02x:%02x:%02x:%02x:%02x\n",
+               reqBSSID[0], reqBSSID[1], reqBSSID[2],
+               reqBSSID[3], reqBSSID[4], reqBSSID[5]);
+
+        /* Search for index position in list for requested MAC */
+        i = FindBSSIDInList(Adapter, reqBSSID, Adapter->InfrastructureMode);
+    }
+
+    if (i < 0) {
+        PRINTM(INFO, "ASSOC: WAP: MAC address not found in BSSID List\n");
+        return -ENETUNREACH;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+
+        ret = wlan_associate(priv, &Adapter->ScanTable[i]);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    } else {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            /* Exit Adhoc mode */
+            ret = StopAdhocNetwork(priv);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+        }
+        Adapter->AdhocLinkSensed = FALSE;
+
+        JoinAdhocNetwork(priv, &Adapter->ScanTable[i]);
+    }
+
+    /* Check to see if we successfully connected */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        ret = WLAN_STATUS_SUCCESS;
+    } else {
+        ret = -ENETDOWN;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Associated to a specific BSS discovered in a scan
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param pBSSDesc  Pointer to the BSS descriptor to associate with.
+ *
+ *  @return          WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int enableData = TRUE;
+    union iwreq_data wrqu;
+    int ret;
+    IEEEtypes_AssocRsp_t *pAssocRsp;
+    u8 currentBSSID[MRVDRV_ETH_ADDR_LEN];
+    int reassocAttempt = FALSE;
+
+    ENTER();
+
+    /* Return error if the Adapter or table entry is not marked as infra */
+    if ((Adapter->InfrastructureMode != Wlan802_11Infrastructure)
+        || (pBSSDesc->InfrastructureMode != Wlan802_11Infrastructure)) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    memcpy(&currentBSSID,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress,
+           sizeof(currentBSSID));
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        reassocAttempt = TRUE;
+        PRINTM(INFO, "Attempting reassociation, stopping wmm queues\n");
+        wmm_stop_queue(priv);
+    }
+
+    /* Clear any past association response stored for application retrieval */
+    Adapter->assocRspSize = 0;
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_ASSOCIATE,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc);
+
+    if (Adapter->wmm.enabled) {
+        /* Don't re-enable carrier until we get the WMM_GET_STATUS event */
+        enableData = FALSE;
+    } else {
+        /* Since WMM is not enabled, setup the queues with the defaults */
+        wmm_setup_queues(priv);
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+        if (reassocAttempt
+            && (memcmp(&currentBSSID,
+                       &Adapter->CurBssParams.BSSDescriptor.MacAddress,
+                       sizeof(currentBSSID)) == 0)) {
+
+            /* Reassociation attempt failed, still associated to old AP,
+             **   no need to wait for WMM notification to restart data
+             */
+            enableData = TRUE;
+        }
+        if (enableData) {
+            PRINTM(INFO, "Post association, re-enabling data flow\n");
+            wmm_start_queue(priv);
+            os_carrier_on(priv);
+            os_start_queue(priv);
+        }
+    } else {
+        PRINTM(INFO, "Post association, stopping data flow\n");
+        os_carrier_off(priv);
+        os_stop_queue(priv);
+    }
+
+    memcpy(wrqu.ap_addr.sa_data,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    pAssocRsp = (IEEEtypes_AssocRsp_t *) Adapter->assocRspBuffer;
+
+    if (ret || pAssocRsp->StatusCode) {
+        ret = -ENETUNREACH;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Associated to a specific indexed entry in the ScanTable
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param tableIdx  Index into the ScanTable to associate to, index parameter
+ *                   base value is 1.  No scanning is done before the 
+ *                   association attempt.
+ *
+ *  @return          WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+wlan_associate_to_table_idx(wlan_private * priv, int tableIdx)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret;
+
+    ENTER();
+
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error\n");
+        return -EBUSY;
+    }
+#endif
+
+    PRINTM(INFO, "ASSOC: iwpriv: Index = %d, NumInScanTable = %d\n",
+           tableIdx, Adapter->NumInScanTable);
+
+    /* Check index in table, subtract 1 if within range and call association
+     *   sub-function.  ScanTable[] is 0 based, parameter is 1 based to
+     *   conform with IW_ENCODE_INDEX flag parameter passing in iwconfig/iwlist
+     */
+    if (tableIdx && (tableIdx <= Adapter->NumInScanTable)) {
+        ret = wlan_associate(priv, &Adapter->ScanTable[tableIdx - 1]);
+    } else {
+        ret = -EINVAL;
+    }
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief Start an Adhoc Network
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param AdhocSSID    The ssid of the Adhoc Network
+ *  @return             WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+StartAdhocNetwork(wlan_private * priv, WLAN_802_11_SSID * AdhocSSID)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    Adapter->AdhocCreate = TRUE;
+
+    PRINTM(INFO, "Adhoc Channel = %d\n", Adapter->AdhocChannel);
+    PRINTM(INFO, "CurBssParams.channel = %d\n",
+           Adapter->CurBssParams.BSSDescriptor.Channel);
+    PRINTM(INFO, "CurBssParams.band = %d\n", Adapter->CurBssParams.band);
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_AD_HOC_START,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, AdhocSSID);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Join an adhoc network found in a previous scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pBSSDesc     Pointer to a BSS descriptor found in a previous scan
+ *                      to attempt to join
+ *
+ *  @return             WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+JoinAdhocNetwork(wlan_private * priv, BSSDescriptor_t * pBSSDesc)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    PRINTM(INFO, "JoinAdhocNetwork: CurBss.ssid =%s\n",
+           Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
+    PRINTM(INFO, "JoinAdhocNetwork: CurBss.ssid_len =%u\n",
+           Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength);
+    PRINTM(INFO, "JoinAdhocNetwork: ssid =%s\n", pBSSDesc->Ssid.Ssid);
+    PRINTM(INFO, "JoinAdhocNetwork: ssid len =%u\n",
+           pBSSDesc->Ssid.SsidLength);
+
+    /* check if the requested SSID is already joined */
+    if (Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength
+        && !SSIDcmp(&pBSSDesc->Ssid,
+                    &Adapter->CurBssParams.BSSDescriptor.Ssid)
+        && (Adapter->CurBssParams.BSSDescriptor.InfrastructureMode ==
+            Wlan802_11IBSS)) {
+
+        PRINTM(INFO,
+               "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+               "not attempting to re-join");
+
+        return WLAN_STATUS_FAILURE;
+    }
+
+    PRINTM(INFO, "CurBssParams.channel = %d\n",
+           Adapter->CurBssParams.BSSDescriptor.Channel);
+    PRINTM(INFO, "CurBssParams.band = %c\n", Adapter->CurBssParams.band);
+
+    Adapter->AdhocCreate = FALSE;
+
+    // store the SSID info temporarily
+    memset(&Adapter->AttemptedSSIDBeforeScan, 0, sizeof(WLAN_802_11_SSID));
+    memcpy(&Adapter->AttemptedSSIDBeforeScan,
+           &pBSSDesc->Ssid, sizeof(WLAN_802_11_SSID));
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Stop the Adhoc Network
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @return          WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+StopAdhocNetwork(wlan_private * priv)
+{
+    return PrepareAndSendCommand(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
+                                 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+}
+
+/**
+ *  @brief Send Deauthentication Request
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @return          WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+SendDeauthentication(wlan_private * priv)
+{
+    return PrepareAndSendCommand(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+                                 0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+}
+
+/**
+ *  @brief Set Idle Off
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlanidle_off(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    const u8 zeroMac[] = { 0, 0, 0, 0, 0, 0 };
+    int i;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            if (memcmp(Adapter->PreviousBSSID, zeroMac, sizeof(zeroMac)) != 0) {
+
+                PRINTM(INFO, "Previous SSID = %s\n",
+                       Adapter->PreviousSSID.Ssid);
+                PRINTM(INFO, "Previous BSSID = "
+                       "%02x:%02x:%02x:%02x:%02x:%02x:\n",
+                       Adapter->PreviousBSSID[0], Adapter->PreviousBSSID[1],
+                       Adapter->PreviousBSSID[2], Adapter->PreviousBSSID[3],
+                       Adapter->PreviousBSSID[4], Adapter->PreviousBSSID[5]);
+
+                i = FindSSIDInList(Adapter,
+                                   &Adapter->PreviousSSID,
+                                   Adapter->PreviousBSSID,
+                                   Adapter->InfrastructureMode);
+
+                if (i < 0) {
+                    SendSpecificBSSIDScan(priv, Adapter->PreviousBSSID);
+                    i = FindSSIDInList(Adapter,
+                                       &Adapter->PreviousSSID,
+                                       Adapter->PreviousBSSID,
+                                       Adapter->InfrastructureMode);
+                }
+
+                if (i < 0) {
+                    /* If the BSSID could not be found, try just the SSID */
+                    i = FindSSIDInList(Adapter,
+                                       &Adapter->PreviousSSID,
+                                       NULL, Adapter->InfrastructureMode);
+                }
+
+                if (i < 0) {
+                    SendSpecificSSIDScan(priv, &Adapter->PreviousSSID);
+                    i = FindSSIDInList(Adapter,
+                                       &Adapter->PreviousSSID,
+                                       NULL, Adapter->InfrastructureMode);
+                }
+
+                if (i >= 0) {
+                    ret = wlan_associate(priv, &Adapter->ScanTable[i]);
+                }
+            }
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+            ret = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_802_11_AD_HOC_START,
+                                        0, HostCmd_OPTION_WAITFORRSP,
+                                        0, &Adapter->PreviousSSID);
+        }
+    }
+    /* else it is connected */
+
+    PRINTM(INFO, "\nwlanidle is off");
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Set Idle On
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlanidle_on(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            PRINTM(INFO, "Previous SSID = %s\n", Adapter->PreviousSSID.Ssid);
+            memcpy(&Adapter->PreviousSSID,
+                   &Adapter->CurBssParams.BSSDescriptor.Ssid,
+                   sizeof(WLAN_802_11_SSID));
+            SendDeauthentication(priv);
+
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+            ret = StopAdhocNetwork(priv);
+        }
+
+    }
+#ifdef REASSOCIATION
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        CancelTimer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+#endif /* REASSOCIATION */
+
+    PRINTM(INFO, "\nwlanidle is on");
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Append a generic IE as a passthrough TLV to a TLV buffer.
+ *
+ *  This function is called from the network join command prep. routine. 
+ *    If the IE buffer has been setup by the application, this routine appends
+ *    the buffer as a passthrough TLV type to the request.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ppBuffer pointer to command buffer pointer
+ *
+ *  @return         bytes added to the buffer
+ */
+static int
+wlan_cmd_append_generic_ie(wlan_private * priv, u8 ** ppBuffer)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int retLen = 0;
+    MrvlIEtypesHeader_t ieHeader;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    /*
+     * If there is a generic ie buffer setup, append it to the return
+     *   parameter buffer pointer.
+     */
+    if (Adapter->genIeBufferLen) {
+        PRINTM(INFO, "append generic %d to %p\n", Adapter->genIeBufferLen,
+               *ppBuffer);
+
+        /* Wrap the generic IE buffer with a passthrough TLV type */
+        ieHeader.Type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+        ieHeader.Len = wlan_cpu_to_le16(Adapter->genIeBufferLen);
+        memcpy(*ppBuffer, &ieHeader, sizeof(ieHeader));
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += sizeof(ieHeader);
+        retLen += sizeof(ieHeader);
+
+        /* Copy the generic IE buffer to the output buffer, advance pointer */
+        memcpy(*ppBuffer, Adapter->genIeBuffer, Adapter->genIeBufferLen);
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += Adapter->genIeBufferLen;
+        retLen += Adapter->genIeBufferLen;
+
+        /* Reset the generic IE buffer */
+        Adapter->genIeBufferLen = 0;
+    }
+
+    /* return the length appended to the buffer */
+    return retLen;
+}
+
+/**
+ *  @brief Append any application provided Marvell TLVs to a TLV buffer.
+ *
+ *  This function is called from the network join command prep. routine. 
+ *    If the Marvell TLV buffer has been setup by the application, this routine
+ *    appends the buffer to the request.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ppBuffer pointer to command buffer pointer
+ *
+ *  @return         bytes added to the buffer
+ */
+static int
+wlan_cmd_append_marvell_tlv(wlan_private * priv, u8 ** ppBuffer)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int retLen = 0;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    /*
+     * If there is a Marvell TLV buffer setup, append it to the return
+     *   parameter buffer pointer.
+     */
+    if (Adapter->mrvlAssocTlvBufferLen) {
+        PRINTM(INFO, "append tlv %d to %p\n",
+               Adapter->mrvlAssocTlvBufferLen, *ppBuffer);
+
+        /* Copy the TLV buffer to the output buffer, advance pointer */
+        memcpy(*ppBuffer,
+               Adapter->mrvlAssocTlvBuffer, Adapter->mrvlAssocTlvBufferLen);
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += Adapter->mrvlAssocTlvBufferLen;
+        retLen += Adapter->mrvlAssocTlvBufferLen;
+
+        /* Reset the Marvell TLV buffer */
+        Adapter->mrvlAssocTlvBufferLen = 0;
+    }
+
+    /* return the length appended to the buffer */
+    return retLen;
+}
+
+/**
+ *  @brief Append TSF tracking info from the scan table for the target AP
+ *
+ *  This function is called from the network join command prep. routine. 
+ *    The TSF table TSF sent to the firmware contians two TSF values:
+ *      - the TSF of the target AP from its previous beacon/probe response
+ *      - the TSF timestamp of our local MAC at the time we observed the
+ *        beacon/probe response.
+ *
+ *    The firmware uses the timestamp values to set an initial TSF value
+ *      in the MAC for the new association after a reassociation attempt.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ppBuffer A pointer to command buffer pointer
+ *  @param pBSSDesc A pointer to the BSS Descriptor from the scan table of
+ *                  the AP we are trying to join
+ *
+ *  @return         bytes added to the buffer
+ */
+static int
+wlan_cmd_append_tsf_tlv(wlan_private * priv, u8 ** ppBuffer,
+                        BSSDescriptor_t * pBSSDesc)
+{
+    MrvlIEtypes_TsfTimestamp_t tsfTlv;
+    u64 tsfVal;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    tsfTlv.Header.Type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+    tsfTlv.Header.Len = wlan_cpu_to_le16(2 * sizeof(tsfVal));
+
+    memcpy(*ppBuffer, &tsfTlv, sizeof(tsfTlv.Header));
+    *ppBuffer += sizeof(tsfTlv.Header);
+
+    /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received */
+    tsfVal = wlan_cpu_to_le64(pBSSDesc->networkTSF);
+    memcpy(*ppBuffer, &tsfVal, sizeof(tsfVal));
+    *ppBuffer += sizeof(tsfVal);
+
+    memcpy(&tsfVal, pBSSDesc->TimeStamp, sizeof(tsfVal));
+
+    PRINTM(INFO, "ASSOC: TSF offset calc: %016llx - %016llx\n",
+           tsfVal, pBSSDesc->networkTSF);
+
+    tsfVal = wlan_cpu_to_le64(tsfVal);
+    memcpy(*ppBuffer, &tsfVal, sizeof(tsfVal));
+    *ppBuffer += sizeof(tsfVal);
+
+    return (sizeof(tsfTlv.Header) + (2 * sizeof(tsfVal)));
+}
+
+/**
+ *  @brief This function prepares command of deauthenticate.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_deauthenticate(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_DEAUTHENTICATE *dauth = &cmd->params.deauth;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) + S_DS_GEN);
+
+    /* set AP MAC address */
+    memcpy(dauth->MacAddr,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+
+    /* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+    dauth->ReasonCode = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function prepares command of association.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf Void cast of BSSDescriptor_t from the scan table to assoc
+ *  @return          WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_associate(wlan_private * priv,
+                          HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_ASSOCIATE *pAsso = &cmd->params.associate;
+    int ret = WLAN_STATUS_SUCCESS;
+    BSSDescriptor_t *pBSSDesc;
+    WLAN_802_11_RATES rates;
+    int ratesSize;
+    u8 *pos;
+    u16 TmpCap;
+    MrvlIEtypes_SsIdParamSet_t *pSsidTlv;
+    MrvlIEtypes_PhyParamSet_t *pPhyTlv;
+    MrvlIEtypes_SsParamSet_t *pSsTlv;
+    MrvlIEtypes_RatesParamSet_t *pRatesTlv;
+    MrvlIEtypes_AuthType_t *pAuthTlv;
+    MrvlIEtypes_RsnParamSet_t *pRsnTlv;
+
+    ENTER();
+
+    pBSSDesc = (BSSDescriptor_t *) pdata_buf;
+    pos = (u8 *) pAsso;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+    /* Save so we know which BSS Desc to use in the response handler */
+    Adapter->pAttemptedBSSDesc = pBSSDesc;
+
+    memcpy(pAsso->PeerStaAddr,
+           pBSSDesc->MacAddress, sizeof(pAsso->PeerStaAddr));
+    pos += sizeof(pAsso->PeerStaAddr);
+
+    /* set the listen interval */
+    pAsso->ListenInterval = wlan_cpu_to_le16(Adapter->ListenInterval);
+
+    pos += sizeof(pAsso->CapInfo);
+    pos += sizeof(pAsso->ListenInterval);
+    pos += sizeof(pAsso->Reserved1);
+
+    pSsidTlv = (MrvlIEtypes_SsIdParamSet_t *) pos;
+    pSsidTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+    pSsidTlv->Header.Len = pBSSDesc->Ssid.SsidLength;
+    memcpy(pSsidTlv->SsId, pBSSDesc->Ssid.Ssid, pSsidTlv->Header.Len);
+    pos += sizeof(pSsidTlv->Header) + pSsidTlv->Header.Len;
+    pSsidTlv->Header.Len = wlan_cpu_to_le16(pSsidTlv->Header.Len);
+
+    pPhyTlv = (MrvlIEtypes_PhyParamSet_t *) pos;
+    pPhyTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
+    pPhyTlv->Header.Len = sizeof(pPhyTlv->fh_ds.DsParamSet);
+    memcpy(&pPhyTlv->fh_ds.DsParamSet,
+           &pBSSDesc->PhyParamSet.DsParamSet.CurrentChan,
+           sizeof(pPhyTlv->fh_ds.DsParamSet));
+    pos += sizeof(pPhyTlv->Header) + pPhyTlv->Header.Len;
+    pPhyTlv->Header.Len = wlan_cpu_to_le16(pPhyTlv->Header.Len);
+
+    pSsTlv = (MrvlIEtypes_SsParamSet_t *) pos;
+    pSsTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CF);
+    pSsTlv->Header.Len = sizeof(pSsTlv->cf_ibss.CfParamSet);
+    pos += sizeof(pSsTlv->Header) + pSsTlv->Header.Len;
+    pSsTlv->Header.Len = wlan_cpu_to_le16(pSsTlv->Header.Len);
+
+    /* Get the common rates supported between the driver and the BSS Desc */
+    if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Setup the Rates TLV in the association command */
+    pRatesTlv = (MrvlIEtypes_RatesParamSet_t *) pos;
+    pRatesTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+    pRatesTlv->Header.Len = wlan_cpu_to_le16(ratesSize);
+    memcpy(pRatesTlv->Rates, rates, ratesSize);
+    pos += sizeof(pRatesTlv->Header) + ratesSize;
+    PRINTM(INFO, "ASSOC_CMD: Rates size = %d\n", ratesSize);
+
+    /* Add the Authentication type to be used for Auth frames if needed */
+    pAuthTlv = (MrvlIEtypes_AuthType_t *) pos;
+    pAuthTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+    pAuthTlv->Header.Len = sizeof(pAuthTlv->AuthType);
+    pAuthTlv->AuthType = Adapter->SecInfo.AuthenticationMode;
+    pos += sizeof(pAuthTlv->Header) + pAuthTlv->Header.Len;
+    pAuthTlv->Header.Len = wlan_cpu_to_le16(pAuthTlv->Header.Len);
+
+    if (!Adapter->wps.SessionEnable) {
+        if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled) {
+            pRsnTlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+            pRsnTlv->Header.Type = (u16) Adapter->Wpa_ie[0];    /* WPA_IE or WPA2_IE */
+            pRsnTlv->Header.Type = pRsnTlv->Header.Type & 0x00FF;
+            pRsnTlv->Header.Type = wlan_cpu_to_le16(pRsnTlv->Header.Type);
+            pRsnTlv->Header.Len = (u16) Adapter->Wpa_ie[1];
+            pRsnTlv->Header.Len = pRsnTlv->Header.Len & 0x00FF;
+            if (pRsnTlv->Header.Len <= (sizeof(Adapter->Wpa_ie) - 2)) {
+                memcpy(pRsnTlv->RsnIE, &Adapter->Wpa_ie[2],
+                       pRsnTlv->Header.Len);
+            } else {
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+
+            HEXDUMP("ASSOC_CMD: RSN IE", (u8 *) pRsnTlv,
+                    sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len);
+            pos += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
+            pRsnTlv->Header.Len = wlan_cpu_to_le16(pRsnTlv->Header.Len);
+        }
+    }
+
+    wlan_wmm_process_association_req(priv, &pos, &pBSSDesc->wmmIE);
+
+    wlan_cmd_append_generic_ie(priv, &pos);
+
+    wlan_cmd_append_marvell_tlv(priv, &pos);
+
+    wlan_cmd_append_tsf_tlv(priv, &pos, pBSSDesc);
+
+    if (wlan_create_dnld_countryinfo_11d(priv, 0)) {
+        PRINTM(INFO, "Dnld_countryinfo_11d failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    if (wlan_parse_dnld_countryinfo_11d(priv)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    cmd->Size = wlan_cpu_to_le16((u16) (pos - (u8 *) pAsso) + S_DS_GEN);
+
+    /* set the Capability info at last */
+    memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(pAsso->CapInfo));
+    TmpCap &= CAPINFO_MASK;
+    PRINTM(INFO, "ASSOC_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n",
+           TmpCap, CAPINFO_MASK);
+    TmpCap = wlan_cpu_to_le16(TmpCap);
+    memcpy(&pAsso->CapInfo, &TmpCap, sizeof(pAsso->CapInfo));
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function prepares command of ad_hoc_start.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *  @param pssid    A pointer to WLAN_802_11_SSID structure
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_ad_hoc_start(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, void *pssid)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_AD_HOC_START *adhs = &cmd->params.ads;
+    int ret = WLAN_STATUS_SUCCESS;
+    int cmdAppendSize = 0;
+    int i;
+    u16 TmpCap;
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    if (!Adapter) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+    pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
+    Adapter->pAttemptedBSSDesc = pBSSDesc;
+
+    /*
+     * Fill in the parameters for 2 data structures:
+     *   1. HostCmd_DS_802_11_AD_HOC_START Command
+     *   2. pBSSDesc
+     *
+     * Driver will fill up SSID, BSSType,IBSS param, Physical Param,
+     *   probe delay, and Cap info.
+     *
+     * Firmware will fill up beacon period, Basic rates
+     *   and operational rates.
+     */
+
+    memset(adhs->SSID, 0, MRVDRV_MAX_SSID_LENGTH);
+
+    memcpy(adhs->SSID, ((WLAN_802_11_SSID *) pssid)->Ssid,
+           ((WLAN_802_11_SSID *) pssid)->SsidLength);
+
+    PRINTM(INFO, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+    memset(pBSSDesc->Ssid.Ssid, 0, MRVDRV_MAX_SSID_LENGTH);
+    memcpy(pBSSDesc->Ssid.Ssid,
+           ((WLAN_802_11_SSID *) pssid)->Ssid,
+           ((WLAN_802_11_SSID *) pssid)->SsidLength);
+
+    pBSSDesc->Ssid.SsidLength = ((WLAN_802_11_SSID *) pssid)->SsidLength;
+
+    /* set the BSS type */
+    adhs->BSSType = HostCmd_BSS_TYPE_IBSS;
+    pBSSDesc->InfrastructureMode = Wlan802_11IBSS;
+    adhs->BeaconPeriod = wlan_cpu_to_le16(Adapter->BeaconPeriod);
+    pBSSDesc->BeaconPeriod = Adapter->BeaconPeriod;
+
+    /* set Physical param set */
+#define DS_PARA_IE_ID   3
+#define DS_PARA_IE_LEN  1
+
+    adhs->PhyParamSet.DsParamSet.ElementId = DS_PARA_IE_ID;
+    adhs->PhyParamSet.DsParamSet.Len = DS_PARA_IE_LEN;
+
+    ASSERT(Adapter->AdhocChannel);
+
+    PRINTM(INFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
+           Adapter->AdhocChannel);
+
+    Adapter->CurBssParams.BSSDescriptor.Channel = Adapter->AdhocChannel;
+
+    pBSSDesc->Channel = Adapter->AdhocChannel;
+    adhs->PhyParamSet.DsParamSet.CurrentChan = Adapter->AdhocChannel;
+
+    memcpy(&pBSSDesc->PhyParamSet,
+           &adhs->PhyParamSet, sizeof(IEEEtypes_PhyParamSet_t));
+
+    pBSSDesc->NetworkTypeInUse = Wlan802_11DS;
+
+    /* set IBSS param set */
+#define IBSS_PARA_IE_ID   6
+#define IBSS_PARA_IE_LEN  2
+
+    adhs->SsParamSet.IbssParamSet.ElementId = IBSS_PARA_IE_ID;
+    adhs->SsParamSet.IbssParamSet.Len = IBSS_PARA_IE_LEN;
+    adhs->SsParamSet.IbssParamSet.AtimWindow
+        = wlan_cpu_to_le16(Adapter->AtimWindow);
+    pBSSDesc->ATIMWindow = Adapter->AtimWindow;
+    memcpy(&pBSSDesc->SsParamSet,
+           &adhs->SsParamSet, sizeof(IEEEtypes_SsParamSet_t));
+
+    /* set Capability info */
+    adhs->Cap.Ess = 0;
+    adhs->Cap.Ibss = 1;
+    pBSSDesc->Cap.Ibss = 1;
+
+    /* set up privacy in pBSSDesc */
+    if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
+        || Adapter->AdhocAESEnabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+        PRINTM(INFO, "ADHOC_S_CMD: WEPStatus set, Privacy to WEP\n");
+        pBSSDesc->Privacy = Wlan802_11PrivFilter8021xWEP;
+        adhs->Cap.Privacy = AD_HOC_CAP_PRIVACY_ON;
+    } else {
+        PRINTM(INFO, "ADHOC_S_CMD: WEPStatus NOT set, Setting "
+               "Privacy to ACCEPT ALL\n");
+        pBSSDesc->Privacy = Wlan802_11PrivFilterAcceptAll;
+    }
+
+    memset(adhs->DataRate, 0, sizeof(adhs->DataRate));
+
+    if (Adapter->adhoc_grate_enabled == TRUE) {
+        memcpy(adhs->DataRate, AdhocRates_G,
+               MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_G)));
+        if (Adapter->
+            CurrentPacketFilter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON) {
+            ret =
+                PrepareAndSendCommand(priv, HostCmd_CMD_MAC_CONTROL, 0,
+                                      HostCmd_OPTION_WAITFORRSP, 0,
+                                      &Adapter->CurrentPacketFilter);
+            if (ret) {
+                PRINTM(INFO, "ADHOC_S_CMD: G Protection config failed\n");
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+        }
+    } else {
+        memcpy(adhs->DataRate, AdhocRates_B,
+               MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_B)));
+    }
+
+    /* Find the last non zero */
+    for (i = 0; i < sizeof(adhs->DataRate) && adhs->DataRate[i]; i++);
+
+    Adapter->CurBssParams.NumOfRates = i;
+
+    /* Copy the ad-hoc creating rates into Current BSS state structure */
+    memcpy(&Adapter->CurBssParams.DataRates,
+           &adhs->DataRate, Adapter->CurBssParams.NumOfRates);
+
+    PRINTM(INFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n",
+           adhs->DataRate[0], adhs->DataRate[1],
+           adhs->DataRate[2], adhs->DataRate[3]);
+
+    PRINTM(INFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+    if (wlan_create_dnld_countryinfo_11d(priv, Adapter->CurBssParams.band)) {
+        PRINTM(INFO, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_START)
+                                 + S_DS_GEN + cmdAppendSize);
+
+    memcpy(&TmpCap, &adhs->Cap, sizeof(u16));
+    TmpCap = wlan_cpu_to_le16(TmpCap);
+    memcpy(&adhs->Cap, &TmpCap, sizeof(u16));
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function prepares command of ad_hoc_stop.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_ad_hoc_stop(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_STOP)
+                                 + S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function prepares command of ad_hoc_join.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf Void cast of BSSDescriptor_t from the scan table to join
+ *
+ *  @return          WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_ad_hoc_join(wlan_private * priv,
+                            HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_AD_HOC_JOIN *pAdHocJoin = &cmd->params.adj;
+    BSSDescriptor_t *pBSSDesc = (BSSDescriptor_t *) pdata_buf;
+    int cmdAppendSize = 0;
+    int ret = WLAN_STATUS_SUCCESS;
+    WLAN_802_11_RATES rates;
+    int ratesSize;
+    u16 TmpCap;
+    u16 CurrentPacketFilter;
+
+    ENTER();
+
+#define USE_G_PROTECTION	0x02
+    if (pBSSDesc->ERPFlags & USE_G_PROTECTION) {
+        CurrentPacketFilter =
+            Adapter->
+            CurrentPacketFilter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+        ret =
+            PrepareAndSendCommand(priv, HostCmd_CMD_MAC_CONTROL, 0,
+                                  HostCmd_OPTION_WAITFORRSP, 0,
+                                  &CurrentPacketFilter);
+        if (ret) {
+            PRINTM(INFO, "ADHOC_S_CMD: G Protection config failed\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    }
+    Adapter->pAttemptedBSSDesc = pBSSDesc;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+    pAdHocJoin->BssDescriptor.BSSType = HostCmd_BSS_TYPE_IBSS;
+
+    pAdHocJoin->BssDescriptor.BeaconPeriod
+        = wlan_cpu_to_le16(pBSSDesc->BeaconPeriod);
+
+    memcpy(&pAdHocJoin->BssDescriptor.BSSID,
+           &pBSSDesc->MacAddress, MRVDRV_ETH_ADDR_LEN);
+
+    memcpy(&pAdHocJoin->BssDescriptor.SSID,
+           &pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength);
+
+    memcpy(&pAdHocJoin->BssDescriptor.PhyParamSet,
+           &pBSSDesc->PhyParamSet, sizeof(IEEEtypes_PhyParamSet_t));
+
+    memcpy(&pAdHocJoin->BssDescriptor.SsParamSet,
+           &pBSSDesc->SsParamSet, sizeof(IEEEtypes_SsParamSet_t));
+
+    memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(IEEEtypes_CapInfo_t));
+
+    TmpCap &= CAPINFO_MASK;
+
+    PRINTM(INFO, "ADHOC_J_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n",
+           TmpCap, CAPINFO_MASK);
+    memcpy(&pAdHocJoin->BssDescriptor.Cap, &TmpCap,
+           sizeof(IEEEtypes_CapInfo_t));
+
+    /* information on BSSID descriptor passed to FW */
+    PRINTM(INFO,
+           "ADHOC_J_CMD: BSSID = %02x-%02x-%02x-%02x-%02x-%02x, SSID = %s\n",
+           pAdHocJoin->BssDescriptor.BSSID[0],
+           pAdHocJoin->BssDescriptor.BSSID[1],
+           pAdHocJoin->BssDescriptor.BSSID[2],
+           pAdHocJoin->BssDescriptor.BSSID[3],
+           pAdHocJoin->BssDescriptor.BSSID[4],
+           pAdHocJoin->BssDescriptor.BSSID[5],
+           pAdHocJoin->BssDescriptor.SSID);
+
+    /* Get the common rates supported between the driver and the BSS Desc */
+    if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Copy Data Rates from the Rates recorded in scan response */
+    memset(pAdHocJoin->BssDescriptor.DataRates, 0,
+           sizeof(pAdHocJoin->BssDescriptor.DataRates));
+    memcpy(pAdHocJoin->BssDescriptor.DataRates, rates, ratesSize);
+
+    /* Copy the adhoc join rates into Current BSS state structure */
+    Adapter->CurBssParams.NumOfRates = ratesSize;
+    memcpy(&Adapter->CurBssParams.DataRates, rates, ratesSize);
+
+    /* Copy the channel information */
+    Adapter->CurBssParams.BSSDescriptor.Channel = pBSSDesc->Channel;
+
+    if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
+        || Adapter->AdhocAESEnabled) {
+        pAdHocJoin->BssDescriptor.Cap.Privacy = AD_HOC_CAP_PRIVACY_ON;
+    }
+
+    if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) {
+        /* wake up first */
+        WLAN_802_11_POWER_MODE LocalPSMode;
+
+        LocalPSMode = Wlan802_11PowerModeCAM;
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_PS_MODE,
+                                    HostCmd_ACT_GEN_SET, 0, 0, &LocalPSMode);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    }
+
+    if (wlan_create_dnld_countryinfo_11d(priv, 0)) {
+        PRINTM(INFO, "Dnld_countryinfo_11d failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (wlan_parse_dnld_countryinfo_11d(priv)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN)
+                                 + S_DS_GEN + cmdAppendSize);
+
+    memcpy(&TmpCap, &pAdHocJoin->BssDescriptor.Cap,
+           sizeof(IEEEtypes_CapInfo_t));
+    TmpCap = wlan_cpu_to_le16(TmpCap);
+
+    memcpy(&pAdHocJoin->BssDescriptor.Cap,
+           &TmpCap, sizeof(IEEEtypes_CapInfo_t));
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Association firmware command response handler
+ *
+ *   The response buffer for the association command has the following
+ *      memory layout.
+ *
+ *   For cases where an association response was not received (indicated
+ *      by the CapInfo and AId field):
+ *
+ *     .------------------------------------------------------------.
+ *     |  Header(4 * sizeof(u16)):  Standard command response hdr   |
+ *     .------------------------------------------------------------.
+ *     |  CapInfo/Error Return(u16):                                |
+ *     |           0xFFFF(-1): Internal error                       |
+ *     |           0xFFFE(-2): Authentication unhandled message     |
+ *     |           0xFFFD(-3): Authentication refused               |
+ *     |           0xFFFC(-4): Timeout waiting for AP response      |
+ *     .------------------------------------------------------------.
+ *     |  StatusCode(u16):                                          |
+ *     |        If CapInfo is -1:                                   |
+ *     |           An internal firmware failure prevented the       |
+ *     |           command from being processed.  The StatusCode    |
+ *     |           will be set to 1.                                |
+ *     |                                                            |
+ *     |        If CapInfo is -2:                                   |
+ *     |           An authentication frame was received but was     |
+ *     |           not handled by the firmware.  IEEE Status        |
+ *     |           code for the failure is returned.                |
+ *     |                                                            |
+ *     |        If CapInfo is -3:                                   |
+ *     |           An authentication frame was received and the     |
+ *     |           StatusCode is the IEEE Status reported in the    |
+ *     |           response.                                        |
+ *     |                                                            |
+ *     |        If CapInfo is -4:                                   |
+ *     |           (1) Association response timeout                 |
+ *     |           (2) Authentication response timeout              |
+ *     .------------------------------------------------------------.
+ *     |  AId(u16): 0xFFFF                                          |
+ *     .------------------------------------------------------------.
+ *
+ *
+ *   For cases where an association response was received, the IEEE 
+ *     standard association response frame is returned:
+ *
+ *     .------------------------------------------------------------.
+ *     |  Header(4 * sizeof(u16)):  Standard command response hdr   |
+ *     .------------------------------------------------------------.
+ *     |  CapInfo(u16): IEEE Capability                             |
+ *     .------------------------------------------------------------.
+ *     |  StatusCode(u16): IEEE Status Code                         |
+ *     .------------------------------------------------------------.
+ *     |  AId(u16): IEEE Association ID                             |
+ *     .------------------------------------------------------------.
+ *     |  IEEE IEs(variable): Any received IEs comprising the       |
+ *     |                      remaining portion of a received       |
+ *     |                      association response frame.           |
+ *     .------------------------------------------------------------.
+ *
+ *  For simplistic handling, the StatusCode field can be used to determine
+ *    an association success (0) or failure (non-zero).
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_associate(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    IEEEtypes_AssocRsp_t *pAssocRsp;
+    BSSDescriptor_t *pBSSDesc;
+    WLAN_802_11_RATES rates;
+    int ratesSize;
+
+    ENTER();
+
+    pAssocRsp = (IEEEtypes_AssocRsp_t *) & resp->params;
+
+    HEXDUMP("ASSOC_RESP:", (void *) &resp->params,
+            wlan_le16_to_cpu(resp->Size) - S_DS_GEN);
+
+    Adapter->assocRspSize = MIN(wlan_le16_to_cpu(resp->Size) - S_DS_GEN,
+                                sizeof(Adapter->assocRspBuffer));
+
+    memcpy(Adapter->assocRspBuffer, &resp->params, Adapter->assocRspSize);
+
+    if (pAssocRsp->StatusCode) {
+        priv->adapter->dbg.num_cmd_assoc_failure++;
+        PRINTM(CMND, "ASSOC_RESP: Association Failed, "
+               "status code = %d, error = %d\n",
+               pAssocRsp->StatusCode, *(short *) &pAssocRsp->Capability);
+
+        ret = WLAN_STATUS_FAILURE;
+
+        goto done;
+    }
+
+    /* Send a Media Connected event, according to the Spec */
+    Adapter->MediaConnectStatus = WlanMediaStateConnected;
+
+    /* Set the attempted BSSID Index to current */
+    pBSSDesc = Adapter->pAttemptedBSSDesc;
+
+    PRINTM(INFO, "ASSOC_RESP: %s\n", pBSSDesc->Ssid.Ssid);
+
+    /* Make a copy of current BSSID descriptor */
+    memcpy(&Adapter->CurBssParams.BSSDescriptor,
+           pBSSDesc, sizeof(BSSDescriptor_t));
+
+    /* update CurBssParams */
+    Adapter->CurBssParams.BSSDescriptor.Channel
+        = pBSSDesc->PhyParamSet.DsParamSet.CurrentChan;
+
+    if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Copy the infra. association rates into Current BSS state structure */
+    Adapter->CurBssParams.NumOfRates = ratesSize;
+    memcpy(&Adapter->CurBssParams.DataRates, rates, ratesSize);
+
+    /* Adjust the timestamps in the scan table to be relative to the newly
+     *   associated AP's TSF
+     */
+    wlan_scan_update_tsf_timestamps(priv, pBSSDesc);
+
+    if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
+        Adapter->CurBssParams.wmm_enabled = TRUE;
+    } else {
+        Adapter->CurBssParams.wmm_enabled = FALSE;
+    }
+
+    if (Adapter->wmm.required && Adapter->CurBssParams.wmm_enabled) {
+        Adapter->wmm.enabled = TRUE;
+    } else {
+        Adapter->wmm.enabled = FALSE;
+    }
+
+    Adapter->CurBssParams.wmm_uapsd_enabled = FALSE;
+
+    if (Adapter->wmm.enabled == TRUE) {
+        Adapter->CurBssParams.wmm_uapsd_enabled
+            = pBSSDesc->wmmIE.QoSInfo.QosUAPSD;
+    }
+
+    PRINTM(INFO, "ASSOC_RESP: CurrentPacketFilter is %x\n",
+           Adapter->CurrentPacketFilter);
+
+    if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled)
+        Adapter->IsGTK_SET = FALSE;
+
+    Adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+    Adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+    memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
+    memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
+    Adapter->nextSNRNF = 0;
+    Adapter->numSNRNF = 0;
+
+    priv->adapter->dbg.num_cmd_assoc_success++;
+    PRINTM(INFO, "ASSOC_RESP: Associated \n");
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function handles the command response of disassociate
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_disassociate(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+
+    priv->adapter->dbg.num_cmd_deauth++;
+    MacEventDisconnected(priv);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function handles the command response of ad_hoc_start and
+ *  ad_hoc_join
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_ad_hoc(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 Command = resp->Command;
+    u16 Result = resp->Result;
+    HostCmd_DS_802_11_AD_HOC_RESULT *pAdHocResult;
+    union iwreq_data wrqu;
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    pAdHocResult = &resp->params.result;
+
+    pBSSDesc = Adapter->pAttemptedBSSDesc;
+
+    /*
+     * Join result code 0 --> SUCCESS
+     */
+    if (Result) {
+        PRINTM(INFO, "ADHOC_RESP Failed\n");
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            MacEventDisconnected(priv);
+        }
+
+        memset(&Adapter->CurBssParams.BSSDescriptor,
+               0x00, sizeof(Adapter->CurBssParams.BSSDescriptor));
+
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /* Send a Media Connected event, according to the Spec */
+    Adapter->MediaConnectStatus = WlanMediaStateConnected;
+
+    if (Command == HostCmd_RET_802_11_AD_HOC_START) {
+        PRINTM(INFO, "ADHOC_S_RESP  %s\n", pBSSDesc->Ssid.Ssid);
+
+        /* Update the created network descriptor with the new BSSID */
+        memcpy(pBSSDesc->MacAddress,
+               pAdHocResult->BSSID, MRVDRV_ETH_ADDR_LEN);
+    } else {
+        /*
+         * Now the join cmd should be successful
+         * If BSSID has changed use SSID to compare instead of BSSID
+         */
+        PRINTM(INFO, "ADHOC_J_RESP  %s\n", pBSSDesc->Ssid.Ssid);
+
+        /* Make a copy of current BSSID descriptor, only needed for join since
+         *   the current descriptor is already being used for adhoc start
+         */
+        memcpy(&Adapter->CurBssParams.BSSDescriptor,
+               pBSSDesc, sizeof(BSSDescriptor_t));
+    }
+
+    memset(&wrqu, 0, sizeof(wrqu));
+    memcpy(wrqu.ap_addr.sa_data,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    PRINTM(INFO, "ADHOC_RESP: Channel = %d\n", Adapter->AdhocChannel);
+    PRINTM(INFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[0],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[1],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[2],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[3],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[4],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[5]);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function handles the command response of ad_hoc_stop
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_ad_hoc_stop(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+
+    MacEventDisconnected(priv);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+#ifdef REASSOCIATION
+/**
+ *  @brief This function handles re-association. it is triggered
+ *  by re-assoc timer.
+ *
+ *  @param data    A pointer to wlan_thread structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+int
+wlan_reassociation_thread(void *data)
+{
+    wlan_thread *thread = data;
+    wlan_private *priv = thread->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    wait_queue_t wait;
+    int i;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    wlan_activate_thread(thread);
+    init_waitqueue_entry(&wait, current);
+
+    current->flags |= PF_NOFREEZE;
+
+    for (;;) {
+        add_wait_queue(&thread->waitQ, &wait);
+        OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
+
+        PRINTM(INFO, "Reassoc: Thread sleeping...\n");
+
+        schedule();
+
+        OS_SET_THREAD_STATE(TASK_RUNNING);
+        remove_wait_queue(&thread->waitQ, &wait);
+
+        if (Adapter->SurpriseRemoved) {
+            break;
+        }
+
+        if (kthread_should_stop()) {
+            break;
+        }
+
+        PRINTM(INFO, "Reassoc: Thread waking up...\n");
+
+        if (Adapter->InfrastructureMode != Wlan802_11Infrastructure ||
+            Adapter->HardwareStatus != WlanHardwareStatusReady) {
+            PRINTM(MSG, "Reassoc: mode or hardware status is not correct\n");
+            continue;
+        }
+
+        /* The semaphore is used to avoid reassociation thread and 
+           wlan_set_scan/wlan_set_essid interrupting each other.
+           Reassociation should be disabled completely by application if 
+           wlan_set_user_scan_ioctl/wlan_set_wap is used.
+         */
+        if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+            PRINTM(ERROR, "Acquire semaphore error, reassociation thread\n");
+            goto settimer;
+        }
+
+        if (Adapter->MediaConnectStatus != WlanMediaStateDisconnected) {
+            OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+            PRINTM(MSG, "Reassoc: Adapter->MediaConnectStatus is wrong\n");
+            continue;
+        }
+
+        PRINTM(INFO, "Reassoc: Required ESSID: %s\n",
+               Adapter->PreviousSSID.Ssid);
+
+        PRINTM(INFO, "Reassoc: Performing Active Scan @ %lu\n",
+               os_time_get());
+        SendSpecificSSIDScan(priv, &Adapter->PreviousSSID);
+
+        i = FindSSIDInList(Adapter,
+                           &Adapter->PreviousSSID,
+                           Adapter->PreviousBSSID,
+                           Adapter->InfrastructureMode);
+
+        if (i < 0) {
+            /* If the SSID could not be found, try just the SSID */
+            i = FindSSIDInList(Adapter,
+                               &Adapter->PreviousSSID,
+                               NULL, Adapter->InfrastructureMode);
+        }
+
+        if (i >= 0) {
+            if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
+                ret = PrepareAndSendCommand(priv,
+                                            HostCmd_CMD_802_11_SET_WEP,
+                                            0, HostCmd_OPTION_WAITFORRSP,
+                                            OID_802_11_ADD_WEP, NULL);
+                if (ret)
+                    PRINTM(INFO, "Ressoc: Fail to set WEP KEY\n");
+            }
+            wlan_associate(priv, &Adapter->ScanTable[i]);
+        }
+
+        OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+
+      settimer:
+        if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+            PRINTM(INFO, "Reassoc: No AP found or assoc failed."
+                   "Restarting re-assoc Timer @ %lu\n", os_time_get());
+
+            Adapter->ReassocTimerIsSet = TRUE;
+            ModTimer(&Adapter->MrvDrvTimer, MRVDRV_TIMER_10S);
+        }
+    }
+
+    wlan_deactivate_thread(thread);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function triggers re-association by waking up
+ *  re-assoc thread.
+ *  
+ *  @param FunctionContext    A pointer to FunctionContext
+ *  @return 	   n/a
+ */
+void
+MrvDrvReassocTimerFunction(void *FunctionContext)
+{
+    wlan_private *priv = (wlan_private *) FunctionContext;
+    wlan_adapter *Adapter = priv->adapter;
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    PRINTM(INFO, "MrvDrvReassocTimer fired.\n");
+    Adapter->ReassocTimerIsSet = FALSE;
+    if (Adapter->PSState != PS_STATE_FULL_POWER) {
+        /* wait until Exit_PS command returns */
+        Adapter->ReassocTimerIsSet = TRUE;
+        ModTimer(&Adapter->MrvDrvTimer, MRVDRV_TIMER_1S);
+        PRINTM(INFO, "MrvDrvTimerFunction(PSState=%d) waiting"
+               "for Exit_PS done\n", Adapter->PSState);
+        LEAVE();
+        return;
+    }
+
+    PRINTM(INFO, "Waking Up the Reassoc Thread\n");
+
+    wake_up_interruptible(&priv->ReassocThread.waitQ);
+
+    LEAVE();
+    return;
+}
+#endif /* REASSOCIATION */
+
+int
+sendADHOCBSSIDQuery(wlan_private * priv)
+{
+    return PrepareAndSendCommand(priv,
+                                 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                                 HostCmd_ACT_GET, 0, 0, NULL);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_join.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_join.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_join.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_join.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,96 @@
+/** @file wlan_join.h
+ *
+ *  @brief Interface for the wlan infrastructure and adhoc join routines
+ *
+ *  Driver interface functions and type declarations for the join module
+ *    implemented in wlan_join.c.  Process all start/join requests for
+ *    both adhoc and infrastructure networks
+ *    
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *     
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    01/11/06: Initial revision. Match new scan code, relocate related functions
+
+************************************************************/
+
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+//! Size of buffer allocated to store the association response from firmware
+#define MRVDRV_ASSOC_RSP_BUF_SIZE  500
+
+//! Size of buffer allocated to store IEs passed to firmware in the assoc req
+#define MRVDRV_GENIE_BUF_SIZE      256
+
+//! Size of buffer allocated to store TLVs passed to firmware in the assoc req
+#define MRVDRV_ASSOC_TLV_BUF_SIZE  256
+
+extern int wlan_cmd_802_11_authenticate(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * cmd,
+                                        void *pdata_buf);
+extern int wlan_cmd_802_11_ad_hoc_join(wlan_private * priv,
+                                       HostCmd_DS_COMMAND * cmd,
+                                       void *pdata_buf);
+extern int wlan_cmd_802_11_ad_hoc_stop(wlan_private * priv,
+                                       HostCmd_DS_COMMAND * cmd);
+extern int wlan_cmd_802_11_ad_hoc_start(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * cmd,
+                                        void *pssid);
+extern int wlan_cmd_802_11_deauthenticate(wlan_private * priv,
+                                          HostCmd_DS_COMMAND * cmd);
+extern int wlan_cmd_802_11_associate(wlan_private * priv,
+                                     HostCmd_DS_COMMAND * cmd,
+                                     void *pdata_buf);
+extern int wlan_ret_802_11_authenticate(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_ad_hoc(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_ad_hoc_stop(wlan_private * priv,
+                                       HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_disassociate(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_associate(wlan_private * priv,
+                                     HostCmd_DS_COMMAND * resp);
+
+extern int wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
+extern int wlan_associate_to_table_idx(wlan_private * priv, int tableIdx);
+
+extern int wlanidle_on(wlan_private * priv);
+extern int wlanidle_off(wlan_private * priv);
+
+extern int wlan_do_adhocstop_ioctl(wlan_private * priv);
+extern int wlan_reassociation_thread(void *data);
+
+extern int StartAdhocNetwork(wlan_private * priv,
+                             WLAN_802_11_SSID * AdhocSSID);
+extern int JoinAdhocNetwork(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
+extern int StopAdhocNetwork(wlan_private * priv);
+extern int SendDeauthentication(wlan_private * priv);
+
+extern int wlan_do_adhocstop_ioctl(wlan_private * priv);
+extern int wlan_get_assoc_rsp_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_set_mrvl_tlv_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+#ifdef __KERNEL__
+extern int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+                        struct sockaddr *awrq, char *extra);
+#endif
+
+extern int sendADHOCBSSIDQuery(wlan_private * priv);
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_main.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_main.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_main.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_main.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1383 @@
+/** @file wlan_main.c
+  *  
+  * @brief This file contains the major functions in WLAN
+  * driver. It includes init, exit, open, close and main
+  * thread etc..
+  * 
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/**
+  * @mainpage M-WLAN Linux Driver
+  *
+  * @section overview_sec Overview
+  *
+  * The M-WLAN is a Linux reference driver for Marvell
+  * 802.11 (a/b/g) WLAN chipset.
+  * 
+  * @section copyright_sec Copyright
+  *
+  * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
+  *
+  */
+/********************************************************
+Change log:
+    09/30/05: Add Doxygen format comments
+    12/09/05: Add TX_QUEUE support  
+    01/05/06: Add kernel 2.6.x support  
+    01/11/06: Conditionalize new scan/join functions.
+    01/12/06: Add TxLockFlag for UAPSD power save mode 
+              and Proprietary Periodic sleep support
+********************************************************/
+
+#include    "include.h"
+
+/********************************************************
+        Local Variables
+********************************************************/
+
+#ifdef ENABLE_PM
+#define WLAN_PM_DRV_NAME "wlan_pm_drv"
+
+static int wlan_pm_suspend(struct device *pmdev, u32 state, u32 level);
+static int wlan_pm_resume(struct device *pmdev, u32 level);
+static void wlan_pm_release(struct device *pmdev);
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct device_driver wlan_pm_driver = {
+    .name = WLAN_PM_DRV_NAME,
+    .bus = &platform_bus_type,
+    .suspend = wlan_pm_suspend,
+    .resume = wlan_pm_resume,
+};
+
+/*! Device Definition for WLAN */
+static struct platform_device wlan_pm_platform_device = {
+    .name = WLAN_PM_DRV_NAME,
+    .id = 0,
+    .dev.release = wlan_pm_release,
+};
+#endif
+
+spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+ulong driver_flags;
+
+#define WLAN_TX_PWR_DEFAULT     20      /*100mW */
+#define WLAN_TX_PWR_US_DEFAULT      20  /*100mW */
+#define WLAN_TX_PWR_JP_DEFAULT      16  /*50mW */
+#define WLAN_TX_PWR_FR_100MW        20  /*100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT    20  /*100mW */
+
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/* Band: 'B/G', Region: USA FCC/Canada IC */
+static CHANNEL_FREQ_POWER channel_freq_power_US_BG[] = {
+    {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+    {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+    {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+    {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+    {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+    {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+    {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+    {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+    {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+    {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* Band: 'B/G', Region: Europe ETSI */
+static CHANNEL_FREQ_POWER channel_freq_power_EU_BG[] = {
+    {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+    {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+    {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+    {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+    {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+    {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+    {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+    {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+    {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+    {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+    {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+    {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* Band: 'B/G', Region: Spain */
+static CHANNEL_FREQ_POWER channel_freq_power_SPN_BG[] = {
+    {10, 2457, WLAN_TX_PWR_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_DEFAULT}
+};
+
+/* Band: 'B/G', Region: France */
+static CHANNEL_FREQ_POWER channel_freq_power_FR_BG[] = {
+    {10, 2457, WLAN_TX_PWR_FR_100MW},
+    {11, 2462, WLAN_TX_PWR_FR_100MW},
+    {12, 2467, WLAN_TX_PWR_FR_100MW},
+    {13, 2472, WLAN_TX_PWR_FR_100MW}
+};
+
+/* Band: 'B/G', Region: Japan */
+static CHANNEL_FREQ_POWER channel_freq_power_JPN41_BG[] = {
+    {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+    {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+    {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+    {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+    {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+    {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+    {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+    {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+    {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+    {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+    {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+    {13, 2472, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/* Band: 'B/G', Region: Japan */
+static CHANNEL_FREQ_POWER channel_freq_power_JPN40_BG[] = {
+    {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/********************************************************
+        Global Variables
+********************************************************/
+
+/* add by feng for thread conflict debug */
+int threadrunning = 0;
+
+/**
+ * the structure for channel, frequency and power
+ */
+typedef struct _region_cfp_table
+{
+    u8 region;
+    CHANNEL_FREQ_POWER *cfp_BG;
+    int cfp_no_BG;
+} region_cfp_table_t;
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+region_cfp_table_t region_cfp_table[] = {
+    {0x10,                      /*US FCC */
+     channel_freq_power_US_BG,
+     sizeof(channel_freq_power_US_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x20,                      /*CANADA IC */
+     channel_freq_power_US_BG,
+     sizeof(channel_freq_power_US_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x30, /*EU*/ channel_freq_power_EU_BG,
+     sizeof(channel_freq_power_EU_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+     sizeof(channel_freq_power_SPN_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+     sizeof(channel_freq_power_FR_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x40, /*JAPAN*/ channel_freq_power_JPN40_BG,
+     sizeof(channel_freq_power_JPN40_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x41, /*JAPAN*/ channel_freq_power_JPN41_BG,
+     sizeof(channel_freq_power_JPN41_BG) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+/*Add new region here */
+};
+
+/**
+ * the rates supported by the card
+ */
+u8 WlanDataRates[WLAN_SUPPORTED_RATES] =
+    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+    0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ * the rates supported
+ */
+u8 SupportedRates[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
+    0x60, 0x6c, 0
+};
+
+/**
+ * the rates supported for ad-hoc G mode
+ */
+u8 AdhocRates_G[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc B mode
+ */
+u8 AdhocRates_B[4] = { 0x82, 0x84, 0x8b, 0x96 };
+
+/**
+ * the global variable of a pointer to wlan_private
+ * structure variable
+ */
+wlan_private *wlanpriv = NULL;
+
+u32 DSFreqList[15] = {
+    0, 2412000, 2417000, 2422000, 2427000, 2432000, 2437000, 2442000,
+    2447000, 2452000, 2457000, 2462000, 2467000, 2472000, 2484000
+};
+
+/**
+ * the table to keep region code
+ */
+u16 RegionCodeToIndex[MRVDRV_MAX_REGION_CODE] =
+    { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41 };
+
+/********************************************************
+        Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function opens the network device
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_open(struct net_device *dev)
+{
+    wlan_private *priv = (wlan_private *) dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    // On some systems the device open handler will be called before HW ready.
+    // Use the following flag check and wait function to work around the issue.
+    {
+        int i = 0;
+
+        while ((adapter->HardwareStatus != WlanHardwareStatusReady) &&
+               (i < MAX_WAIT_DEVICE_READY_COUNT)) {
+            i++;
+            os_sched_timeout(100);
+        }
+        if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
+            PRINTM(FATAL, "HW not ready, wlan_open() return failure\n");
+            LEAVE();
+            return WLAN_STATUS_FAILURE;
+        }
+    }
+
+    MODULE_GET;
+
+    priv->open = TRUE;
+
+    if ((adapter->MediaConnectStatus == WlanMediaStateConnected)
+        && (adapter->InfrastructureMode != Wlan802_11IBSS
+            || adapter->AdhocLinkSensed == TRUE))
+        os_carrier_on(priv);
+    else
+        os_carrier_off(priv);
+
+    os_start_queue(priv);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function closes the network device
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_close(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+
+    ENTER();
+
+    if (priv->adapter)
+        wlan_clean_txrx(priv);
+
+    MODULE_PUT;
+
+    priv->open = FALSE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+#ifdef ENABLE_PM
+/**
+ * @brief
+ *     This function is called to put the SDHC in a low power state. Refer to the
+ *     document driver-model/driver.txt in the kernel source tree for more
+ *     information.
+ *
+ * @param   dev   the device structure used to give information on which SDHC
+ *                to suspend
+ * @param   state the power state the device is entering
+ * @param   level the stage in device suspension process that we want the
+ *                device to be put in
+ *
+ * @return  0 : go to sleep mode
+ *          -1 : do not accept to go to sleep mode.
+ */
+static int
+wlan_pm_suspend(struct device *pmdev, u32 state, u32 level)
+{
+    wlan_private *priv = wlanpriv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct net_device *dev = priv->wlan_dev.netdev;
+
+    switch (level) {
+
+    case SUSPEND_DISABLE:
+        PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: enter SUSPEND_DISABLE.\n");
+
+        /* in associated mode : check that chipset is in IEEE PS and well configured to wake up the host if needed */
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            if ((Adapter->PSState != PS_STATE_SLEEP)
+                || (!Adapter->bWakeupDevRequired)
+                || (Adapter->WakeupTries != 0)) {
+                PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: can't enter sleep mode because \
+		        PSstate=%d, bWakeupDevRequired=%d, wakeupTries=%d\n",
+                       Adapter->PSState, Adapter->bWakeupDevRequired, Adapter->WakeupTries);
+                return WLAN_STATUS_FAILURE;
+            }
+
+            else {
+
+                /*
+                 * Detach the network interface
+                 * if the network is running
+                 */
+                if (netif_running(dev)) {
+                    netif_device_detach(dev);
+                    PRINTM(INFO, "netif_device_detach().\n");
+                }
+                /* Stop bus clock */
+                sbi_set_bus_clock(priv, FALSE);
+            }
+        }
+
+        /* in non associated mode  : check that chipset is in Deepsleep mode */
+        else {
+            if (Adapter->IsDeepSleep == FALSE) {
+                PRINTM(INFO,
+                       "WIFI_PM_SUSPEND_CALLBACK: No allowed to enter sleep while in FW in full power.\n");
+                return WLAN_STATUS_FAILURE;
+            }
+            /*
+             * Detach the network interface 
+             * if the network is running
+             */
+            if (netif_running(dev)) {
+                netif_device_detach(dev);
+            }
+        }
+        break;
+
+    case SUSPEND_SAVE_STATE:
+
+        PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: enter SUSPEND_SAVE_STATE.\n");
+        /* Save bus state to restore it when waking up */
+        sbi_suspend(priv);
+
+        break;
+
+    case SUSPEND_POWER_DOWN:
+
+        PRINTM(INFO, "WIFI_PM_SUSPEND_CALLBACK: enter SUSPEND_POWER_DOWN.\n");
+        /* nothing to do */
+        break;
+
+    default:
+
+        break;
+
+    }
+
+    return WLAN_STATUS_SUCCESS;
+
+}
+
+/**
+ * @brief
+ *     This function is called to bring the SDHC back from a low power state. Refer
+ *     to the document driver-model/driver.txt in the kernel source tree for more
+ *     information.
+ *
+ * @param   dev   the device structure used to give information on which SDHC
+ *                to resume
+ * @param   level the stage in device resumption process that we want the
+ *                device to be put in
+ *
+ * @return  The function always returns 0.
+ */
+static int
+wlan_pm_resume(struct device *pmdev, u32 level)
+{
+    wlan_private *priv = wlanpriv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct net_device *dev = priv->wlan_dev.netdev;
+
+    switch (level) {
+
+    case RESUME_POWER_ON:
+
+        PRINTM(INFO, "WIFI_PM_RESUME_CALLBACK: enter RESUME_POWER_ON.\n");
+        /* nothing to do */
+        break;
+
+    case RESUME_RESTORE_STATE:
+
+        PRINTM(INFO,
+               "WIFI_PM_RESUME_CALLBACK: enter RESUME_RESTORE_STATE.\n");
+        /* Restore bus state */
+        sbi_resume(priv);
+        break;
+
+    case RESUME_ENABLE:
+
+        PRINTM(INFO, "WIFI_PM_RESUME_CALLBACK: enter RESUME_ENABLE.\n");
+
+        /* in associated mode */
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+            if (Adapter->bWakeupDevRequired == FALSE) {
+                /* could never happen */
+                PRINTM(MSG, "WIFI_PM_RESUME_CALLBACK: serious error.\n");
+            } else {
+                /*
+                 * Start bus clock
+                 */
+                sbi_set_bus_clock(priv, TRUE);
+                /*
+                 * Attach the network interface
+                 * if the network is running
+                 */
+                if (netif_running(dev)) {
+                    netif_device_attach(dev);
+                    PRINTM(INFO, "WIFI_PM : after netif_device_attach().\n");
+                }
+                PRINTM(INFO,
+                       "WIFI_PM : After netif attach, in associated mode.\n");
+            }
+        }
+
+        /* in non associated mode */
+        else {
+            if (netif_running(dev)) {
+                netif_device_attach(dev);
+            }
+
+            PRINTM(INFO,
+                   "WIFI_PM : after netif attach, in NON associated mode.\n");
+        }
+        break;
+
+    default:
+        break;
+
+    }
+    return WLAN_STATUS_SUCCESS;
+
+}
+
+/**
+ * @brief
+ *     Dummy function to be compliant with Linux Power Management framework.
+ *
+ * @param   pmdev   the device structure used to give information on which SDHC
+ *                  to use
+ *
+ * @return  None.
+ */
+static void
+wlan_pm_release(struct device *pmdev)
+{
+    PRINTM(INFO, "WIFI_PM_DRIVER : Into pm_device release function\n");
+    return;
+}
+
+#endif /* ENABLE_PM */
+
+/** 
+ *  @brief This function handles packet transmission
+ *  
+ *  @param skb     A pointer to sk_buff structure
+ *  @param dev     A pointer to net_device structure
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    int ret;
+    wlan_private *priv = dev->priv;
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    PRINTM(DATA, "Data <= kernel\n");
+
+    if (wlan_tx_packet(priv, skb)) {
+        /* Transmit failed */
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the timeout of packet
+ *  transmission
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        n/a
+ */
+static void
+wlan_tx_timeout(struct net_device *dev)
+{
+    wlan_private *priv = (wlan_private *) dev->priv;
+
+    ENTER();
+
+    PRINTM(DATA, "Tx timeout\n");
+    UpdateTransStart(dev);
+
+    priv->adapter->dbg.num_tx_timeout++;
+
+    priv->adapter->IntCounter++;
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function returns the network statistics
+ *  
+ *  @param dev     A pointer to wlan_private structure
+ *  @return        A pointer to net_device_stats structure
+ */
+static struct net_device_stats *
+wlan_get_stats(struct net_device *dev)
+{
+    wlan_private *priv = (wlan_private *) dev->priv;
+
+    return &priv->stats;
+}
+
+/** 
+ *  @brief This function sets the MAC address to firmware.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param pRxPD   A pointer to RxPD structure of received packet
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = (wlan_private *) dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct sockaddr *pHwAddr = (struct sockaddr *) addr;
+
+    ENTER();
+
+    memset(Adapter->CurrentAddr, 0, MRVDRV_ETH_ADDR_LEN);
+
+    /* dev->dev_addr is 8 bytes */
+    HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+    HEXDUMP("addr:", pHwAddr->sa_data, ETH_ALEN);
+    memcpy(Adapter->CurrentAddr, pHwAddr->sa_data, ETH_ALEN);
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+                                HostCmd_ACT_SET,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (ret) {
+        PRINTM(INFO, "set mac address failed.\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    HEXDUMP("Adapter->MacAddr:", Adapter->CurrentAddr, ETH_ALEN);
+    memcpy(dev->dev_addr, Adapter->CurrentAddr, ETH_ALEN);
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function sets multicast addresses to firmware
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        n/a
+ */
+static void
+wlan_set_multicast_list(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int OldPacketFilter;
+
+    ENTER();
+
+    OldPacketFilter = Adapter->CurrentPacketFilter;
+
+    if (dev->flags & IFF_PROMISC) {
+        PRINTM(INFO, "Enable Promiscuous mode\n");
+        Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+        Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+    } else {
+        /* Multicast */
+        Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+
+        if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+            MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+            PRINTM(INFO, "Enabling All Multicast!\n");
+            Adapter->CurrentPacketFilter |=
+                HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+        } else {
+            Adapter->CurrentPacketFilter &=
+                ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+
+            if (!dev->mc_count) {
+                PRINTM(INFO, "No multicast addresses - "
+                       "disabling multicast!\n");
+
+            } else {
+                int i;
+
+                Adapter->NumOfMulticastMACAddr =
+                    CopyMulticastAddrs(Adapter, dev);
+
+                PRINTM(INFO, "Multicast addresses: %d\n", dev->mc_count);
+
+                for (i = 0; i < dev->mc_count; i++) {
+                    PRINTM(INFO, "Multicast address %d:"
+                           "%x %x %x %x %x %x\n", i,
+                           Adapter->MulticastList[i][0],
+                           Adapter->MulticastList[i][1],
+                           Adapter->MulticastList[i][2],
+                           Adapter->MulticastList[i][3],
+                           Adapter->MulticastList[i][4],
+                           Adapter->MulticastList[i][5]);
+                }
+                /* set multicast addresses to firmware */
+                PrepareAndSendCommand(priv, HostCmd_CMD_MAC_MULTICAST_ADR,
+                                      HostCmd_ACT_GEN_SET, 0, 0, NULL);
+            }
+        }
+    }
+
+    if (Adapter->CurrentPacketFilter != OldPacketFilter) {
+        PrepareAndSendCommand(priv,
+                              HostCmd_CMD_MAC_CONTROL,
+                              0, 0, 0, &Adapter->CurrentPacketFilter);
+    }
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function pops rx_skb from the rx queue.
+ *  
+ *  @param RxSkbQ  A pointer to rx_skb queue
+ *  @return        A pointer to skb
+ */
+static struct sk_buff *
+wlan_pop_rx_skb(struct sk_buff *RxSkbQ)
+{
+    struct sk_buff *skb_data = NULL;
+
+    if (!list_empty((struct list_head *) RxSkbQ)) {
+        skb_data = RxSkbQ->next;
+        list_del((struct list_head *) RxSkbQ->next);
+    }
+
+    return skb_data;
+}
+
+/** 
+ *  @brief This function hanldes the major job in WLAN driver.
+ *  it handles the event generated by firmware, rx data received
+ *  from firmware and tx data sent from kernel.
+ *  
+ *  @param data    A pointer to wlan_thread structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_service_main_thread(void *data)
+{
+    wlan_thread *thread = data;
+    wlan_private *priv = thread->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    wait_queue_t wait;
+    u8 ireg = 0;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    wlan_activate_thread(thread);
+
+    init_waitqueue_entry(&wait, current);
+
+    wmm_init(priv);
+
+    for (;;) {
+        add_wait_queue(&thread->waitQ, &wait);
+        OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
+
+        TX_DISABLE;
+
+        if ((Adapter->WakeupTries) ||
+            (Adapter->PSState == PS_STATE_SLEEP
+             && !Adapter->bWakeupDevRequired) ||
+            (!Adapter->IntCounter &&
+             Adapter->PSState == PS_STATE_PRE_SLEEP) ||
+            (!Adapter->IntCounter
+             && (priv->wlan_dev.dnld_sent || Adapter->TxLockFlag
+                 || wmm_lists_empty(priv) || wmm_is_queue_stopped(priv))
+             && (priv->wlan_dev.dnld_sent || !Adapter->CurrentTxSkb)
+             && (priv->wlan_dev.dnld_sent || Adapter->CurCmd ||
+                 list_empty(&Adapter->CmdPendingQ))
+            )
+            ) {
+            PRINTM(INFO, "main-thread sleeping... "
+                   "HS_Act=%s WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n",
+                   (Adapter->HS_Activated) ? "Y" : "N",
+                   (Adapter->bWakeupDevRequired) ? "Y" : "N",
+                   (Adapter->MediaConnectStatus) ? "Y" : "N",
+                   Adapter->PSMode, Adapter->PSState);
+
+            TX_RESTORE;
+
+		/* add by feng for thread debug */
+	    threadrunning = 0;
+
+            schedule();
+        		/* add by feng for thread debug */
+	    threadrunning = 1; 
+	       
+            PRINTM(INFO, "main-thread waking up: IntCnt=%d "
+                   "CurCmd=%s CmdPending=%s\n"
+                   "                       Connect=%s "
+                   "CurTxSkb=%s dnld_sent=%d\n",
+                   Adapter->IntCounter,
+                   (Adapter->CurCmd) ? "Y" : "N",
+                   list_empty(&Adapter->CmdPendingQ) ? "N" : "Y",
+                   (Adapter->MediaConnectStatus) ? "Y" : "N",
+                   (Adapter->CurrentTxSkb) ? "Y" : "N",
+                   priv->wlan_dev.dnld_sent);
+        } else {
+            TX_RESTORE;
+        }
+
+        OS_SET_THREAD_STATE(TASK_RUNNING);
+        remove_wait_queue(&thread->waitQ, &wait);
+
+        if (kthread_should_stop() || Adapter->SurpriseRemoved) {
+            PRINTM(INFO, "main-thread: break from main thread: "
+                   "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
+            break;
+        }
+
+        if (Adapter->IntCounter) {
+            OS_INT_DISABLE;
+            Adapter->IntCounter = 0;
+            OS_INT_RESTORE;
+
+            if (sbi_get_int_status(priv, &ireg)) {
+                PRINTM(ERROR,
+                       "main-thread: reading HOST_INT_STATUS_REG failed\n");
+                continue;
+            }
+            OS_INT_DISABLE;
+            Adapter->HisRegCpy |= ireg;
+            OS_INT_RESTORE;
+            PRINTM(INTR, "INT: status = 0x%x\n", Adapter->HisRegCpy);
+        } else if (Adapter->bWakeupDevRequired
+                   && (Adapter->HS_Activated || (Adapter->IsDeepSleep)
+                   )
+            ) {
+            Adapter->WakeupTries++;
+            PRINTM(CMND,
+                   "Wakeup device... WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n",
+                   (Adapter->bWakeupDevRequired) ? "Y" : "N",
+                   (priv->adapter->MediaConnectStatus) ? "Y" : "N",
+                   priv->adapter->PSMode, priv->adapter->PSState);
+
+            /* Wake up device */
+            if (sbi_exit_deep_sleep(priv))
+                PRINTM(MSG, "main-thread: wakeup dev failed\n");
+            continue;
+        }
+
+        /* Command response? */
+        if (Adapter->HisRegCpy & HIS_CmdUpLdRdy) {
+            OS_INT_DISABLE;
+            Adapter->HisRegCpy &= ~HIS_CmdUpLdRdy;
+            OS_INT_RESTORE;
+
+            wlan_process_rx_command(priv);
+        }
+
+        /* Any received data? */
+        if (Adapter->HisRegCpy & HIS_RxUpLdRdy) {
+            OS_INT_DISABLE;
+            Adapter->HisRegCpy &= ~HIS_RxUpLdRdy;
+            OS_INT_RESTORE;
+
+            wlan_send_rxskbQ(priv);
+        }
+
+        /* Any Card Event */
+        if (Adapter->HisRegCpy & HIS_CardEvent) {
+            OS_INT_DISABLE;
+            Adapter->HisRegCpy &= ~HIS_CardEvent;
+            OS_INT_RESTORE;
+
+            if (sbi_read_event_cause(priv)) {
+                PRINTM(ERROR, "main-thread: sbi_read_event_cause failed.\n");
+                continue;
+            }
+            wlan_process_event(priv);
+        }
+
+        /* Check if we need to confirm Sleep Request received previously */
+        if (Adapter->PSState == PS_STATE_PRE_SLEEP) {
+            if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) {
+                ASSERT(Adapter->MediaConnectStatus ==
+                       WlanMediaStateConnected);
+                PSConfirmSleep(priv, (u16) Adapter->PSMode);
+            }
+        }
+
+        /* The PS state is changed during processing of 
+         * Sleep Request event above 
+         */
+        if ((Adapter->PSState == PS_STATE_SLEEP)
+            || (Adapter->PSState == PS_STATE_PRE_SLEEP)) {
+            continue;
+        }
+
+        if (Adapter->IsDeepSleep)
+            continue;
+
+        /* The HS_Activated flag is changed during processing of 
+           HS_Activate command resp */
+        /* We cannot send command or data if HS_Activated and 
+           WakeupDevRequired are TRUE */
+        if (Adapter->HS_Activated && Adapter->bWakeupDevRequired) {
+            PRINTM(INFO, "main-thread: cannot send command or data, "
+                   "HS_Activated=%d\n", Adapter->HS_Activated);
+            continue;
+        }
+
+        /* Execute the next command */
+        if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) {
+            ExecuteNextCommand(priv);
+        }
+
+        if (!priv->wlan_dev.dnld_sent
+            && !wmm_lists_empty(priv) && !wmm_is_queue_stopped(priv)) {
+            if ((Adapter->PSState == PS_STATE_FULL_POWER)
+                || (Adapter->sleep_period.period == 0)
+                || (Adapter->TxLockFlag == FALSE)) {
+                wmm_process_tx(priv);
+            }
+        }
+
+    }
+
+    wlan_deactivate_thread(thread);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the wlan_priv and initialize the device. 
+ *  
+ *  @param card    A pointer to card
+ *  @return        A pointer to wlan_private structure
+ */
+static wlan_private *
+wlan_add_card(void *card)
+{
+    struct net_device *dev = NULL;
+    wlan_private *priv = NULL;
+
+    ENTER();
+
+    /* probe the card */
+    if (sbi_probe_card(card) < 0) {
+        PRINTM(MSG, "NO card found!\n");
+        return NULL;
+    }
+
+    /* Allocate an Ethernet device and register it */
+    if (!(dev = alloc_netdev(sizeof(wlan_private), "wlan%d", ether_setup))) {
+        PRINTM(MSG, "Init ethernet device failed!\n");
+        return NULL;
+    }
+
+    priv = dev->priv;
+
+    /* allocate buffer for wlan_adapter */
+    if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+        PRINTM(MSG, "Allocate buffer for wlan_adapter failed!\n");
+        goto err_kmalloc;
+    }
+
+    /* init wlan_adapter */
+    memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+    priv->wlan_dev.netdev = dev;
+    priv->wlan_dev.card = card;
+    wlanpriv = priv;
+
+    //SET_MODULE_OWNER(dev);
+
+    /* Setup the OS Interface to our functions */
+    dev->open = wlan_open;
+    dev->hard_start_xmit = wlan_hard_start_xmit;
+    dev->stop = wlan_close;
+    dev->do_ioctl = wlan_do_ioctl;
+    dev->set_mac_address = wlan_set_mac_address;
+
+    dev->tx_timeout = wlan_tx_timeout;
+    dev->get_stats = wlan_get_stats;
+    dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+
+#ifdef  WIRELESS_EXT
+    //hufh dev->get_wireless_stats = wlan_get_wireless_stats;
+    dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;
+#endif
+#define NETIF_F_DYNALLOC 16
+    dev->features |= NETIF_F_DYNALLOC;
+    dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+    dev->set_multicast_list = wlan_set_multicast_list;
+
+    init_waitqueue_head(&priv->adapter->ds_awake_q);
+
+#ifdef ENABLE_PM
+    /* register Driver to Linux Power Management system. */
+    if (!driver_register(&wlan_pm_driver)) {
+        /* Register one device to Linux Power Management system. */
+        if (platform_device_register(&wlan_pm_platform_device)) {
+            PRINTM(MSG,
+                   "WiFi driver, wlan_main : error when registering device to Linux Power Managment.\n");
+            driver_unregister(&wlan_pm_driver);
+        } else {
+            PRINTM(INFO,
+                   "WiFi device and driver registered to Linux Power Managment.\n");
+        }
+    } else {
+        PRINTM(MSG,
+               "WiFi driver, wlan_main : error when registering driver to Linux Power Managment.\n");
+    }
+#endif
+
+    INIT_LIST_HEAD(&priv->adapter->CmdFreeQ);
+    INIT_LIST_HEAD(&priv->adapter->CmdPendingQ);
+
+    PRINTM(INFO, "Starting kthread...\n");
+    priv->MainThread.priv = priv;
+    wlan_create_thread(wlan_service_main_thread,
+                       &priv->MainThread, "wlan_main_service");
+
+    ConfigureThreadPriority();
+
+#ifdef REASSOCIATION
+    priv->ReassocThread.priv = priv;
+    wlan_create_thread(wlan_reassociation_thread,
+                       &priv->ReassocThread, "wlan_reassoc_service");
+#endif /* REASSOCIATION */
+
+    /*
+     * Register the device. Fillup the private data structure with
+     * relevant information from the card and request for the required
+     * IRQ. 
+     */
+
+    if (sbi_register_dev(priv) < 0) {
+        PRINTM(FATAL, "Failed to register wlan device!\n");
+        goto err_registerdev;
+    }
+
+    SET_NETDEV_DEV(dev, priv->hotplug_device);
+
+    PRINTM(WARN, "%s: Marvell Wlan 802.11 Adapter "
+           "revision 0x%02X at IRQ %i\n", dev->name,
+           priv->adapter->chip_rev, dev->irq);
+
+#ifdef CONFIG_PROC_FS
+    wlan_proc_entry(priv, dev);
+#ifdef PROC_DEBUG
+    wlan_debug_entry(priv, dev);
+#endif
+#endif /* CPNFIG_PROC_FS */
+
+    /* Get the CIS Table */
+    sbi_get_cis_info(priv);
+
+    /* init FW and HW */
+    if (wlan_init_fw(priv)) {
+        PRINTM(FATAL, "Firmware Init Failed\n");
+        goto err_init_fw;
+    }
+
+    if (register_netdev(dev)) {
+        printk(KERN_ERR "Cannot register network device!\n");
+        goto err_init_fw;
+    }
+
+    LEAVE();
+    return priv;
+
+  err_init_fw:
+    sbi_unregister_dev(priv);
+
+#ifdef CONFIG_PROC_FS
+#ifdef PROC_DEBUG
+    wlan_debug_remove(priv);
+#endif
+    wlan_proc_remove(priv);
+#endif
+
+  err_registerdev:
+    /* Stop the thread servicing the interrupts */
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    wlan_terminate_thread(&priv->MainThread);
+
+#ifdef REASSOCIATION
+    wake_up_interruptible(&priv->ReassocThread.waitQ);
+    wlan_terminate_thread(&priv->ReassocThread);
+#endif /* REASSOCIATION */
+
+  err_kmalloc:
+	// modified by Feng
+	free_netdev(dev);
+    wlan_free_adapter(priv);
+    wlanpriv = NULL;
+
+    LEAVE();
+    return NULL;
+}
+
+/** 
+ *  @brief This function removes the card.
+ *  
+ *  @param priv    A pointer to card
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_remove_card(void *card)
+{
+    wlan_private *priv = wlanpriv;
+    wlan_adapter *Adapter;
+    struct net_device *dev;
+    union iwreq_data wrqu;
+
+    ENTER();
+
+    if (!priv) {
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    Adapter = priv->adapter;
+
+    if (!Adapter) {
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    dev = priv->wlan_dev.netdev;
+
+    wake_up_interruptible(&Adapter->ds_awake_q);
+
+    if (Adapter->CurCmd) {
+        PRINTM(INFO, "Wake up current cmdwait_q\n");
+        wake_up_interruptible(&Adapter->CurCmd->cmdwait_q);
+    }
+
+    Adapter->CurCmd = NULL;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        wlan_clean_txrx(priv);
+        Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
+    }
+
+    if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) {
+        Adapter->PSMode = Wlan802_11PowerModeCAM;
+        PSWakeup(priv, HostCmd_OPTION_WAITFORRSP);
+    }
+    if (Adapter->IsDeepSleep == TRUE) {
+        sbi_exit_deep_sleep(priv);
+        if (Adapter->IsDeepSleep == TRUE) {
+            if (os_wait_interruptible_timeout(Adapter->ds_awake_q,
+                                              !Adapter->IsDeepSleep,
+                                              MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT)
+                == 0) {
+                PRINTM(MSG, "ds_awake_q: timer expired\n");
+            }
+        }
+    }
+
+    memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    /* Disable interrupts on the card as we cannot handle them after RESET */
+    sbi_disable_host_int(priv);
+
+    PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RESET, 0, 0, 0, NULL);
+
+    os_sched_timeout(200);
+
+#ifdef ENABLE_PM
+    /* unregister driver and device from Linux Power Management system. */
+    platform_device_unregister(&wlan_pm_platform_device);
+    driver_unregister(&wlan_pm_driver);
+#endif
+
+    Adapter->SurpriseRemoved = TRUE;
+
+    /* Stop the thread servicing the interrupts */
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+#ifdef REASSOCIATION
+    wake_up_interruptible(&priv->ReassocThread.waitQ);
+#endif /* REASSOCIATION */
+
+#ifdef CONFIG_PROC_FS
+#ifdef PROC_DEBUG
+    wlan_debug_remove(priv);
+#endif
+    wlan_proc_remove(priv);
+#endif
+
+    PRINTM(INFO, "unregester dev\n");
+    sbi_unregister_dev(priv);
+
+    PRINTM(INFO, "Free Adapter\n");
+    wlan_free_adapter(priv);
+
+    /* Last reference is our one */
+    PRINTM(INFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+
+    PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name,
+           (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
+
+    unregister_netdev(dev);
+
+    PRINTM(INFO, "Unregister finish\n");
+
+    priv->wlan_dev.netdev = NULL;
+    free_netdev(dev);
+    wlanpriv = NULL;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+        Global Functions
+********************************************************/
+
+/**
+ * @brief This function sends the rx packets to the os from the skb queue
+ *
+ * @param priv  A pointer to wlan_private structure
+ * @return  n/a
+ */
+void
+wlan_send_rxskbQ(wlan_private * priv)
+{
+    struct sk_buff *skb;
+
+    ENTER();
+    if (priv->adapter) {
+        while ((skb = wlan_pop_rx_skb(&priv->adapter->RxSkbQ))) {
+            if (ProcessRxedPacket(priv, skb) == -ENOMEM)
+                break;
+        }
+    }
+    LEAVE();
+}
+
+/** 
+ *  @brief This function finds the CFP in 
+ *  region_cfp_table based on region and band parameter.
+ *  
+ *  @param region  The region code
+ *  @param band    The band
+ *  @param cfp_no  A pointer to CFP number
+ *  @return        A pointer to CFP
+ */
+CHANNEL_FREQ_POWER *
+wlan_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+{
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < sizeof(region_cfp_table) / sizeof(region_cfp_table_t);
+         i++) {
+        PRINTM(INFO, "region_cfp_table[i].region=%d\n",
+               region_cfp_table[i].region);
+        if (region_cfp_table[i].region == region) {
+            {
+                *cfp_no = region_cfp_table[i].cfp_no_BG;
+                LEAVE();
+                return region_cfp_table[i].cfp_BG;
+            }
+        }
+    }
+
+    LEAVE();
+    return NULL;
+}
+
+/** 
+ *  @brief This function sets region table. 
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param region  The region code
+ *  @param band    The band
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_set_regiontable(wlan_private * priv, u8 region, u8 band)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i = 0;
+
+    CHANNEL_FREQ_POWER *cfp;
+    int cfp_no;
+
+    ENTER();
+
+    memset(Adapter->region_channel, 0, sizeof(Adapter->region_channel));
+
+    {
+        cfp = wlan_get_region_cfp_table(region, band, &cfp_no);
+        if (cfp != NULL) {
+            Adapter->region_channel[i].NrCFP = cfp_no;
+            Adapter->region_channel[i].CFP = cfp;
+        } else {
+            PRINTM(INFO, "wrong region code %#x in Band B-G\n", region);
+            return WLAN_STATUS_FAILURE;
+        }
+        Adapter->region_channel[i].Valid = TRUE;
+        Adapter->region_channel[i].Region = region;
+        Adapter->region_channel[i].Band = band;
+        i++;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the interrupt. it will change PS
+ *  state if applicable. it will wake up main_thread to handle
+ *  the interrupt event as well.
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        n/a
+ */
+void
+wlan_interrupt(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+
+    priv->adapter->IntCounter++;
+
+    PRINTM(INTR, "*\n");
+
+    priv->adapter->WakeupTries = 0;
+    if (priv->adapter->bWakeupDevRequired)
+        sd_set_clock(priv, 0);  /* default clock frequency */
+
+    if (priv->adapter->PSState == PS_STATE_SLEEP) {
+        priv->adapter->PSState = PS_STATE_AWAKE;
+    }
+
+    wake_up_interruptible(&priv->MainThread.waitQ);
+}
+
+/** 
+ *  @brief This function initializes module.
+ *  
+ *  @param     n/a    A pointer to wlan_private structure
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_init_module(void)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (sbi_register(wlan_add_card, wlan_remove_card, NULL) == NULL) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function cleans module
+ *  
+ *  @param priv    n/a
+ *  @return        n/a
+ */
+void
+wlan_cleanup_module(void)
+{
+    ENTER();
+
+    sbi_unregister();
+
+    LEAVE();
+}
+
+module_init(wlan_init_module);
+module_exit(wlan_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_proc.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_proc.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_proc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_proc.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,218 @@
+/** @file wlan_proc.c
+  * @brief This file contains functions for proc fin proc file.
+  * 
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	
+********************************************************/
+#include 	"include.h"
+
+#ifdef CONFIG_PROC_FS
+/********************************************************
+		Local Variables
+********************************************************/
+
+static char *szModes[] = {
+    "Ad-hoc",
+    "Managed",
+    "Auto",
+    "Unknown"
+};
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief proc read function
+ *
+ *  @param page	   pointer to buffer
+ *  @param start   read data starting position
+ *  @param offset  offset
+ *  @param count   counter 
+ *  @param eof     end of file flag
+ *  @param data    data to output
+ *  @return 	   number of output data
+ */
+static int
+wlan_proc_read(char *page, char **start, off_t offset,
+               int count, int *eof, void *data)
+{
+    int i;
+    char *p = page;
+    struct net_device *netdev = data;
+    struct dev_mc_list *mcptr = netdev->mc_list;
+    char fmt[64];
+    wlan_private *priv = netdev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+
+    if (offset != 0) {
+        *eof = 1;
+        goto exit;
+    }
+
+    get_version(Adapter, fmt, sizeof(fmt) - 1);
+
+    p += sprintf(p, "driver_name = " "\"wlan\"\n");
+    p += sprintf(p, "driver_version = %s", fmt);
+    p += sprintf(p, "\nInterfaceName=\"%s\"\n", netdev->name);
+    p += sprintf(p, "Mode=\"%s\"\n", szModes[Adapter->InfrastructureMode]);
+    p += sprintf(p, "State=\"%s\"\n",
+                 ((Adapter->MediaConnectStatus ==
+                   WlanMediaStateDisconnected) ? "Disconnected" :
+                  "Connected"));
+    p += sprintf(p, "MACAddress=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+                 netdev->dev_addr[0], netdev->dev_addr[1],
+                 netdev->dev_addr[2], netdev->dev_addr[3],
+                 netdev->dev_addr[4], netdev->dev_addr[5]);
+
+    p += sprintf(p, "MCCount=\"%d\"\n", netdev->mc_count);
+    p += sprintf(p, "ESSID=\"%s\"\n",
+                 (u8 *) Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
+    p += sprintf(p, "Channel=\"%d\"\n",
+                 Adapter->CurBssParams.BSSDescriptor.Channel);
+    p += sprintf(p, "region_code = \"%02x\"\n", (u32) Adapter->RegionCode);
+
+    /*
+     * Put out the multicast list 
+     */
+    for (i = 0; i < netdev->mc_count; i++) {
+        p += sprintf(p,
+                     "MCAddr[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+                     i,
+                     mcptr->dmi_addr[0], mcptr->dmi_addr[1],
+                     mcptr->dmi_addr[2], mcptr->dmi_addr[3],
+                     mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
+
+        mcptr = mcptr->next;
+    }
+    p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+    p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+    p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+    p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+    p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+    p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+    p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+    p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+    p += sprintf(p, "carrier %s\n",
+                 ((netif_carrier_ok(priv->wlan_dev.netdev)) ? "on" : "off"));
+    p += sprintf(p, "tx queue %s\n",
+                 ((netif_queue_stopped(priv->wlan_dev.netdev)) ? "stopped" :
+                  "started"));
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+    if (Adapter->CurCmd) {
+        HostCmd_DS_COMMAND *CmdPtr =
+            (HostCmd_DS_COMMAND *) Adapter->CurCmd->BufVirtualAddr;
+        p += sprintf(p, "CurCmd ID = 0x%x, 0x%x\n",
+                     wlan_cpu_to_le16(CmdPtr->Command),
+                     wlan_cpu_to_le16(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN)));
+    } else {
+        p += sprintf(p, "CurCmd NULL\n");
+    }
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+  exit:
+    return (p - page);
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief create wlan proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @param dev     pointer net_device
+ *  @return 	   N/A
+ */
+void
+wlan_proc_entry(wlan_private * priv, struct net_device *dev)
+{
+
+    PRINTM(INFO, "Creating Proc Interface\n");
+
+    if (!priv->proc_entry) {
+        priv->proc_entry = proc_mkdir("wlan", init_net.proc_net);
+
+        if (priv->proc_entry) {
+            priv->proc_dev = create_proc_read_entry
+                ("info", 0, priv->proc_entry, wlan_proc_read, dev);
+        }
+    }
+}
+
+/** 
+ *  @brief remove proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @return 	   N/A
+ */
+void
+wlan_proc_remove(wlan_private * priv)
+{
+
+    if (priv->proc_entry) {
+        remove_proc_entry("info", priv->proc_entry);
+    }
+    remove_proc_entry("wlan", init_net.proc_net);
+
+}
+
+/** 
+ *  @brief convert string to number
+ *
+ *  @param s   	   pointer to numbered string
+ *  @return 	   converted number from string s
+ */
+int
+string_to_number(char *s)
+{
+    int r = 0;
+    int base = 0;
+
+    if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0))
+        base = 16;
+    else
+        base = 10;
+    if (base == 16)
+        s += 2;
+    for (s = s; *s != 0; s++) {
+        if ((*s >= 48) && (*s <= 57))
+            r = (r * base) + (*s - 48);
+        else if ((*s >= 65) && (*s <= 70))
+            r = (r * base) + (*s - 55);
+        else if ((*s >= 97) && (*s <= 102))
+            r = (r * base) + (*s - 87);
+        else
+            break;
+    }
+
+    return r;
+}
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_rx.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_rx.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_rx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_rx.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,381 @@
+/** @file wlan_rx.c
+  * @brief This file contains the handling of RX in wlan
+  * driver.
+  * 
+  * (c) Copyright © 2003-2006, Marvell International Ltd.  
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	09/28/05: Add Doxygen format comments
+	12/09/05: ADD Sliding window SNR/NF Average Calculation support
+	
+********************************************************/
+
+#include	"include.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+typedef struct
+{
+    u8 dest_addr[6];
+    u8 src_addr[6];
+    u16 h803_len;
+
+} __ATTRIB_PACK__ Eth803Hdr_t;
+
+typedef struct
+{
+    u8 llc_dsap;
+    u8 llc_ssap;
+    u8 llc_ctrl;
+    u8 snap_oui[3];
+    u16 snap_type;
+
+} __ATTRIB_PACK__ Rfc1042Hdr_t;
+
+typedef struct
+{
+    Eth803Hdr_t eth803_hdr;
+    Rfc1042Hdr_t rfc1042_hdr;
+
+} __ATTRIB_PACK__ RxPacketHdr_t;
+
+typedef struct
+{
+    u8 dest_addr[6];
+    u8 src_addr[6];
+    u16 ethertype;
+
+} __ATTRIB_PACK__ EthII_Hdr_t;
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function computes the AvgSNR .
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   AvgSNR
+ */
+static u8
+wlan_getAvgSNR(wlan_private * priv)
+{
+    u8 i;
+    u16 temp = 0;
+    wlan_adapter *Adapter = priv->adapter;
+    if (Adapter->numSNRNF == 0)
+        return 0;
+    for (i = 0; i < Adapter->numSNRNF; i++)
+        temp += Adapter->rawSNR[i];
+    return (u8) (temp / Adapter->numSNRNF);
+
+}
+
+/** 
+ *  @brief This function computes the AvgNF
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   AvgNF
+ */
+static u8
+wlan_getAvgNF(wlan_private * priv)
+{
+    u8 i;
+    u16 temp = 0;
+    wlan_adapter *Adapter = priv->adapter;
+    if (Adapter->numSNRNF == 0)
+        return 0;
+    for (i = 0; i < Adapter->numSNRNF; i++)
+        temp += Adapter->rawNF[i];
+    return (u8) (temp / Adapter->numSNRNF);
+
+}
+
+/** 
+ *  @brief This function save the raw SNR/NF to our internel buffer
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param pRxPD   A pointer to RxPD structure of received packet
+ *  @return 	   n/a
+ */
+static void
+wlan_save_rawSNRNF(wlan_private * priv, RxPD * pRxPD)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    if (Adapter->numSNRNF < Adapter->data_avg_factor)
+        Adapter->numSNRNF++;
+    Adapter->rawSNR[Adapter->nextSNRNF] = pRxPD->SNR;
+    Adapter->rawNF[Adapter->nextSNRNF] = pRxPD->NF;
+    Adapter->nextSNRNF++;
+    if (Adapter->nextSNRNF >= Adapter->data_avg_factor)
+        Adapter->nextSNRNF = 0;
+    return;
+}
+
+#define DATA_RSSI_LOW_BIT		0x01
+#define DATA_SNR_LOW_BIT		0x02
+#define DATA_RSSI_HIGH_BIT		0x04
+#define DATA_SNR_HIGH_BIT		0x08
+/** 
+ *  @brief This function computes the RSSI in received packet.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+static void
+wlan_check_subscribe_event(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int temp;
+    if (Adapter->subevent.EventsBitmap == 0)
+        return;
+    if ((Adapter->subevent.EventsBitmap & DATA_RSSI_LOW_BIT) ||
+        (Adapter->subevent.EventsBitmap & DATA_RSSI_HIGH_BIT)) {
+        temp =
+            -CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                      Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+        if (Adapter->subevent.EventsBitmap & DATA_RSSI_LOW_BIT) {
+            if (temp > Adapter->subevent.Rssi_low.value) {
+                if (!Adapter->subevent.Rssi_low.Freq) {
+                    Adapter->subevent.EventsBitmap &= ~DATA_RSSI_LOW_BIT;
+                    send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+                } else {
+                    Adapter->subevent.Rssi_low_count++;
+                    if (Adapter->subevent.Rssi_low_count >=
+                        Adapter->subevent.Rssi_low.Freq) {
+                        Adapter->subevent.Rssi_low_count = 0;
+                        send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+                    }
+                }
+            } else
+                Adapter->subevent.Rssi_low_count = 0;
+        }
+        if (Adapter->subevent.EventsBitmap & DATA_RSSI_HIGH_BIT) {
+            if (temp < Adapter->subevent.Rssi_high.value) {
+                if (!Adapter->subevent.Rssi_high.Freq) {
+                    Adapter->subevent.EventsBitmap &= ~DATA_RSSI_HIGH_BIT;
+                    send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
+                } else {
+                    Adapter->subevent.Rssi_high_count++;
+                    if (Adapter->subevent.Rssi_high_count >=
+                        Adapter->subevent.Rssi_high.Freq) {
+                        Adapter->subevent.Rssi_high_count = 0;
+                        send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
+                    }
+                }
+            } else
+                Adapter->subevent.Rssi_high_count = 0;
+        }
+    }
+    if ((Adapter->subevent.EventsBitmap & DATA_SNR_LOW_BIT) ||
+        (Adapter->subevent.EventsBitmap & DATA_SNR_HIGH_BIT)) {
+        temp = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        if (Adapter->subevent.EventsBitmap & DATA_SNR_LOW_BIT) {
+            if (temp < Adapter->subevent.Snr_low.value) {
+                if (!Adapter->subevent.Snr_low.Freq) {
+                    send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+                    Adapter->subevent.EventsBitmap &= ~DATA_SNR_LOW_BIT;
+                } else {
+                    Adapter->subevent.Snr_low_count++;
+                    if (Adapter->subevent.Snr_low_count >=
+                        Adapter->subevent.Snr_low.Freq) {
+                        Adapter->subevent.Snr_low_count = 0;
+                        send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+                    }
+                }
+            } else
+                Adapter->subevent.Snr_low_count = 0;
+        }
+        if (Adapter->subevent.EventsBitmap & DATA_SNR_HIGH_BIT) {
+            if (temp > Adapter->subevent.Snr_high.value) {
+                if (!Adapter->subevent.Snr_high.Freq) {
+                    Adapter->subevent.EventsBitmap &= ~DATA_SNR_HIGH_BIT;
+                    send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+                } else {
+                    Adapter->subevent.Snr_high_count++;
+                    if (Adapter->subevent.Snr_high_count >=
+                        Adapter->subevent.Snr_high.Freq) {
+                        Adapter->subevent.Snr_high_count = 0;
+                        send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+                    }
+                }
+
+            } else
+                Adapter->subevent.Snr_high_count = 0;
+        }
+    }
+    return;
+}
+
+/** 
+ *  @brief This function computes the RSSI in received packet.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param pRxPD   A pointer to RxPD structure of received packet
+ *  @return 	   n/a
+ */
+static void
+wlan_compute_rssi(wlan_private * priv, RxPD * pRxPD)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "RxPD: SNR = %d, NF = %d\n", pRxPD->SNR, pRxPD->NF);
+
+    Adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = pRxPD->SNR;
+    Adapter->NF[TYPE_RXPD][TYPE_NOAVG] = pRxPD->NF;
+    wlan_save_rawSNRNF(priv, pRxPD);
+
+    Adapter->RxPDAge = os_time_get();
+    Adapter->RxPDRate = pRxPD->RxRate;
+
+    Adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getAvgSNR(priv) * AVG_SCALE;
+    Adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getAvgNF(priv) * AVG_SCALE;
+    PRINTM(INFO, "SNR-avg = %d, NF-avg = %d\n",
+           Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+           Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+    Adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+                 Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+
+    Adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                 Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+    wlan_check_subscribe_event(priv);
+    LEAVE();
+}
+
+/********************************************************
+		Global functions
+********************************************************/
+
+/**
+ *  @brief This function processes received packet and forwards it
+ *  to kernel/upper layer
+ *  
+ *  @param priv    A pointer to wlan_private
+ *  @param skb     A pointer to skb which includes the received packet
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+ProcessRxedPacket(wlan_private * priv, struct sk_buff *skb)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    RxPacketHdr_t *pRxPkt;
+    RxPD *pRxPD;
+
+    int hdrChop;
+    EthII_Hdr_t *pEthHdr;
+    u32 u32SkbLen = skb->len;
+
+    const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+    ENTER();
+
+    pRxPD = (RxPD *) skb->data;
+    pRxPkt = (RxPacketHdr_t *) ((u8 *) pRxPD + pRxPD->PktOffset);
+
+    DBG_HEXDUMP(DAT_D, "Rx", skb->data, MIN(skb->len, MAX_DATA_DUMP_LEN));
+
+    endian_convert_RxPD(pRxPD);
+
+    if (skb->len < (ETH_HLEN + 8 + pRxPD->PktOffset)) {
+        PRINTM(ERROR, "RX Error: FRAME RECEIVED WITH BAD LENGTH\n");
+        priv->stats.rx_length_errors++;
+        ret = WLAN_STATUS_SUCCESS;
+        kfree_skb(skb);
+        goto done;
+    }
+
+    PRINTM(INFO, "RX Data: skb->len - pRxPD->PktOffset = %d - %d = %d\n",
+           skb->len, pRxPD->PktOffset, skb->len - pRxPD->PktOffset);
+
+    HEXDUMP("RX Data: Dest", pRxPkt->eth803_hdr.dest_addr,
+            sizeof(pRxPkt->eth803_hdr.dest_addr));
+    HEXDUMP("RX Data: Src", pRxPkt->eth803_hdr.src_addr,
+            sizeof(pRxPkt->eth803_hdr.src_addr));
+
+    if (memcmp(&pRxPkt->rfc1042_hdr,
+               rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+        /* 
+         *  Replace the 803 header and rfc1042 header (llc/snap) with an 
+         *    EthernetII header, keep the src/dst and snap_type (ethertype)
+         *
+         *  The firmware only passes up SNAP frames converting
+         *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+         *
+         *  To create the Ethernet II, just move the src, dst address right
+         *    before the snap_type.
+         */
+        pEthHdr = (EthII_Hdr_t *)
+            ((u8 *) & pRxPkt->eth803_hdr
+             + sizeof(pRxPkt->eth803_hdr) + sizeof(pRxPkt->rfc1042_hdr)
+             - sizeof(pRxPkt->eth803_hdr.dest_addr)
+             - sizeof(pRxPkt->eth803_hdr.src_addr)
+             - sizeof(pRxPkt->rfc1042_hdr.snap_type));
+
+        memcpy(pEthHdr->src_addr, pRxPkt->eth803_hdr.src_addr,
+               sizeof(pEthHdr->src_addr));
+        memcpy(pEthHdr->dest_addr, pRxPkt->eth803_hdr.dest_addr,
+               sizeof(pEthHdr->dest_addr));
+
+        /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
+         *   that was removed 
+         */
+        hdrChop = (u8 *) pEthHdr - (u8 *) pRxPD;
+    } else {
+        HEXDUMP("RX Data: LLC/SNAP",
+                (u8 *) & pRxPkt->rfc1042_hdr, sizeof(pRxPkt->rfc1042_hdr));
+
+        /* Chop off the RxPD */
+        hdrChop = (u8 *) & pRxPkt->eth803_hdr - (u8 *) pRxPD;
+    }
+
+    /* Chop off the leading header bytes so the skb points to the start of 
+     *   either the reconstructed EthII frame or the 802.2/llc/snap frame
+     */
+    skb_pull(skb, hdrChop);
+
+    u32SkbLen = skb->len;
+    wlan_compute_rssi(priv, pRxPD);
+
+    if (os_upload_rx_packet(priv, skb)) {
+        PRINTM(ERROR, "RX Error: os_upload_rx_packet" " returns failure\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    priv->stats.rx_bytes += u32SkbLen;
+    priv->stats.rx_packets++;
+
+    PRINTM(DATA, "Data => kernel\n");
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+
+    return (ret);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_scan.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_scan.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_scan.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_scan.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,3217 @@
+/** @file wlan_scan.c
+ *
+ *  @brief Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ *  IOCTL handlers as well as command preperation and response routines
+ *   for sending scan commands to the firmware.
+ *
+ *  (c) Copyright © 2003-2007, Marvell International Ltd.  
+ *   
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change Log:
+    01/11/06: Initial revision. New scan code, relocate related functions
+    01/19/06: Update specific scan routines to discard old results for adhoc
+    01/31/06: Add support for selectively enabling the FW Scan channel filter
+
+************************************************************/
+
+#include    "include.h"
+
+/********************************************************
+    Local Constants
+********************************************************/
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
+                             + MRVDRV_MAX_SSID_LENGTH   \
+                             + IW_EV_UINT_LEN           \
+                             + IW_EV_FREQ_LEN           \
+                             + IW_EV_QUAL_LEN           \
+                             + MRVDRV_MAX_SSID_LENGTH   \
+                             + IW_EV_PARAM_LEN          \
+                             + 40)      /* 40 for WPAIE */
+
+//! Memory needed to store a max sized Channel List TLV for a firmware scan
+#define CHAN_TLV_MAX_SIZE  (sizeof(MrvlIEtypesHeader_t)         \
+                            + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
+                               * sizeof(ChanScanParamSet_t)))
+
+//! Memory needed to store a max number/size SSID TLV for a firmware scan
+#define SSID_TLV_MAX_SIZE  (1 * sizeof(MrvlIEtypes_SsIdParamSet_t))
+
+//! WPS TLV MAX size is MAX IE size plus 2 bytes for u16 MRVL TLV extension
+#define WPS_TLV_MAX_SIZE   (sizeof(IEEEtypes_VendorSpecific_t) + 2)
+
+//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config)        \
+                            + sizeof(MrvlIEtypes_NumProbes_t)   \
+                            + CHAN_TLV_MAX_SIZE                 \
+                            + SSID_TLV_MAX_SIZE                 \
+                            + WPS_TLV_MAX_SIZE)
+
+//! The maximum number of channels the firmware can scan per command
+#define MRVDRV_MAX_CHANNELS_PER_SCAN   14
+
+/**
+ * @brief Number of channels to scan per firmware scan command issuance.
+ *
+ *  Number restricted to prevent hitting the limit on the amount of scan data
+ *  returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD   4
+
+//! Macro to enable/disable SSID checking before storing a scan table
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.Ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) TRUE
+#endif
+
+/********************************************************
+    Local Variables and Types
+********************************************************/
+
+/**
+ * @brief Interally used to send a configured scan cmd between driver routines
+ */
+typedef union
+{
+    wlan_scan_cmd_config config;        //!< Scan configuration (variable length)
+    u8 configAllocBuf[MAX_SCAN_CFG_ALLOC];      //!< Max allocated block
+} wlan_scan_cmd_config_tlv;
+
+/**
+ *  @brief Check if a scanned network compatible with the driver settings
+ *
+ *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
+ * enabled enabled  enabled   AES     mode   Privacy  WPA  WPA2  Compatible
+ *    0       0        0       0      NONE      0      0    0   yes No security
+ *    0       1        0       0       x        1x     1    x   yes WPA
+ *    0       0        1       0       x        1x     x    1   yes WPA2
+ *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
+ *
+ *    1       0        0       0      NONE      1      0    0   yes Static WEP
+ *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
+ *
+ *
+ *  @param Adapter A pointer to wlan_adapter
+ *  @param index   Index in ScanTable to check against current driver settings
+ *  @param mode    Network mode: Infrastructure or IBSS
+ *
+ *  @return        Index in ScanTable, or error code if negative
+ */
+static int
+IsNetworkCompatible(wlan_adapter * Adapter, int index, int mode)
+{
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    pBSSDesc = &Adapter->ScanTable[index];
+
+    /* Don't check for compatibility if roaming */
+    if ((Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        && (Adapter->InfrastructureMode == Wlan802_11Infrastructure)
+        && (pBSSDesc->InfrastructureMode == Wlan802_11Infrastructure)) {
+        LEAVE();
+        return index;
+    }
+
+    if (Adapter->wps.SessionEnable == TRUE) {
+        PRINTM(INFO, "Return success directly in WPS period\n");
+        LEAVE();
+        return index;
+    }
+
+    if (pBSSDesc->InfrastructureMode == mode) {
+        if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+            && !Adapter->SecInfo.WPAEnabled
+            && !Adapter->SecInfo.WPA2Enabled
+            && pBSSDesc->wpaIE.VendHdr.ElementId != WPA_IE
+            && pBSSDesc->rsnIE.IeeeHdr.ElementId != RSN_IE
+            && !Adapter->AdhocAESEnabled
+            && Adapter->SecInfo.EncryptionMode == CIPHER_NONE
+            && !pBSSDesc->Privacy) {
+            /* no security */
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && !Adapter->AdhocAESEnabled && pBSSDesc->Privacy) {
+            /* static WEP enabled */
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && (pBSSDesc->wpaIE.VendHdr.ElementId == WPA_IE)
+                   && !Adapter->AdhocAESEnabled
+                   /* Privacy bit may NOT be set in some APs like LinkSys WRT54G
+                      && pBSSDesc->Privacy */
+            ) {
+            /* WPA enabled */
+            PRINTM(INFO, "IsNetworkCompatible() WPA: index=%d wpa_ie=%#x "
+                   "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+                   "privacy=%#x\n",
+                   index,
+                   pBSSDesc->wpaIE.VendHdr.ElementId,
+                   pBSSDesc->rsnIE.IeeeHdr.ElementId,
+                   (Adapter->SecInfo.WEPStatus ==
+                    Wlan802_11WEPEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
+                   Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && Adapter->SecInfo.WPA2Enabled
+                   && (pBSSDesc->rsnIE.IeeeHdr.ElementId == RSN_IE)
+                   && !Adapter->AdhocAESEnabled
+                   /* Privacy bit may NOT be set in some APs like LinkSys WRT54G
+                      && pBSSDesc->Privacy */
+            ) {
+            /* WPA2 enabled */
+            PRINTM(INFO, "IsNetworkCompatible() WPA2: index=%d wpa_ie=%#x "
+                   "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+                   "privacy=%#x\n",
+                   index,
+                   pBSSDesc->wpaIE.VendHdr.ElementId,
+                   pBSSDesc->rsnIE.IeeeHdr.ElementId,
+                   (Adapter->SecInfo.WEPStatus ==
+                    Wlan802_11WEPEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
+                   Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && (pBSSDesc->wpaIE.VendHdr.ElementId != WPA_IE)
+                   && (pBSSDesc->rsnIE.IeeeHdr.ElementId != RSN_IE)
+                   && Adapter->AdhocAESEnabled
+                   && Adapter->SecInfo.EncryptionMode == CIPHER_NONE
+                   && pBSSDesc->Privacy) {
+            /* Ad-hoc AES enabled */
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && (pBSSDesc->wpaIE.VendHdr.ElementId != WPA_IE)
+                   && (pBSSDesc->rsnIE.IeeeHdr.ElementId != RSN_IE)
+                   && !Adapter->AdhocAESEnabled
+                   && Adapter->SecInfo.EncryptionMode != CIPHER_NONE
+                   && pBSSDesc->Privacy) {
+            /* dynamic WEP enabled */
+            PRINTM(INFO, "IsNetworkCompatible() dynamic WEP: index=%d "
+                   "wpa_ie=%#x wpa2_ie=%#x EncMode=%#x privacy=%#x\n",
+                   index,
+                   pBSSDesc->wpaIE.VendHdr.ElementId,
+                   pBSSDesc->rsnIE.IeeeHdr.ElementId,
+                   Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+            LEAVE();
+            return index;
+        }
+
+        /* security doesn't match */
+        PRINTM(INFO, "IsNetworkCompatible() FAILED: index=%d wpa_ie=%#x "
+               "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+               index,
+               pBSSDesc->wpaIE.VendHdr.ElementId,
+               pBSSDesc->rsnIE.IeeeHdr.ElementId,
+               (Adapter->SecInfo.WEPStatus ==
+                Wlan802_11WEPEnabled) ? "e" : "d",
+               (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
+               (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
+               Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+        LEAVE();
+        return -ECONNREFUSED;
+    }
+
+    /* mode doesn't match */
+    LEAVE();
+    return -ENETUNREACH;
+}
+
+/**
+ *  @brief This function validates a SSID as being able to be printed
+ *
+ *  @param pSsid   SSID structure to validate
+ *
+ *  @return        TRUE or FALSE
+ */
+static BOOLEAN
+ssid_valid(WLAN_802_11_SSID * pSsid)
+{
+    int ssidIdx;
+
+    for (ssidIdx = 0; ssidIdx < pSsid->SsidLength; ssidIdx++) {
+        if (!isprint(pSsid->Ssid[ssidIdx])) {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+/**
+ *  @brief Post process the scan table after a new scan command has completed
+ *
+ *  Inspect each entry of the scan table and try to find an entry that
+ *    matches our current associated/joined network from the scan.  If
+ *    one is found, update the stored copy of the BSSDescriptor for our
+ *    current network.
+ *
+ *  Debug dump the current scan table contents if compiled accordingly.
+ *
+ *  @param priv   A pointer to wlan_private structure
+ *
+ *  @return       void
+ */
+static void
+wlan_scan_process_results(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    int foundCurrent;
+
+    foundCurrent = FALSE;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        Adapter->CurBssParams.BSSDescriptor.pBeaconBuf = NULL;
+        Adapter->CurBssParams.BSSDescriptor.beaconBufSize = 0;
+        Adapter->CurBssParams.BSSDescriptor.beaconBufSizeMax = 0;
+        i = FindSSIDInList(Adapter,
+                           &Adapter->CurBssParams.BSSDescriptor.Ssid,
+                           Adapter->CurBssParams.BSSDescriptor.MacAddress,
+                           Adapter->InfrastructureMode);
+
+        if (i >= 0) {
+            PRINTM(INFO, "Found current ssid/bssid in list @ index #%d\n", i);
+            /* Make a copy of current BSSID descriptor */
+            memcpy(&Adapter->CurBssParams.BSSDescriptor,
+                   &Adapter->ScanTable[i],
+                   sizeof(Adapter->CurBssParams.BSSDescriptor));
+        }
+    }
+
+    for (i = 0; i < Adapter->NumInScanTable; i++) {
+        PRINTM(INFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+               "RSSI[%03d], SSID[%s]\n",
+               i,
+               Adapter->ScanTable[i].MacAddress[0],
+               Adapter->ScanTable[i].MacAddress[1],
+               Adapter->ScanTable[i].MacAddress[2],
+               Adapter->ScanTable[i].MacAddress[3],
+               Adapter->ScanTable[i].MacAddress[4],
+               Adapter->ScanTable[i].MacAddress[5],
+               (s32) Adapter->ScanTable[i].Rssi,
+               Adapter->ScanTable[i].Ssid.Ssid);
+    }
+}
+
+/**
+ *  @brief Create a channel list for the driver to scan based on region info
+ *
+ *  Use the driver region/band information to construct a comprehensive list
+ *    of channels to scan.  This routine is used for any scan that is not
+ *    provided a specific channel list to scan.
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param scanChanList  Output parameter: Resulting channel list to scan
+ *  @param filteredScan  Flag indicating whether or not a BSSID or SSID filter
+ *                       is being sent in the command to firmware.  Used to 
+ *                       increase the number of channels sent in a scan
+ *                       command and to disable the firmware channel scan
+ *                       filter.
+ *
+ *  @return              void
+ */
+static void
+wlan_scan_create_channel_list(wlan_private * priv,
+                              ChanScanParamSet_t * scanChanList,
+                              BOOLEAN filteredScan)
+{
+
+    wlan_adapter *Adapter = priv->adapter;
+    REGION_CHANNEL *scanRegion;
+    CHANNEL_FREQ_POWER *cfp;
+    int rgnIdx;
+    int chanIdx;
+    int nextChan;
+    u8 scanType;
+
+    chanIdx = 0;
+
+    /* Set the default scan type to the user specified type, will later
+     *   be changed to passive on a per channel basis if restricted by
+     *   regulatory requirements (11d or 11h)
+     */
+    scanType = Adapter->ScanType;
+
+    for (rgnIdx = 0; rgnIdx < NELEMENTS(Adapter->region_channel); rgnIdx++) {
+        if (wlan_get_state_11d(priv) == ENABLE_11D &&
+            Adapter->MediaConnectStatus != WlanMediaStateConnected) {
+            /* Scan all the supported chan for the first scan */
+            if (!Adapter->universal_channel[rgnIdx].Valid)
+                continue;
+            scanRegion = &Adapter->universal_channel[rgnIdx];
+
+            /* clear the parsed_region_chan for the first scan */
+            memset(&Adapter->parsed_region_chan, 0x00,
+                   sizeof(Adapter->parsed_region_chan));
+        } else {
+            if (!Adapter->region_channel[rgnIdx].Valid)
+                continue;
+            scanRegion = &Adapter->region_channel[rgnIdx];
+        }
+
+        for (nextChan = 0;
+             nextChan < scanRegion->NrCFP; nextChan++, chanIdx++) {
+
+            cfp = scanRegion->CFP + nextChan;
+
+            if (wlan_get_state_11d(priv) == ENABLE_11D) {
+                scanType =
+                    wlan_get_scan_type_11d(cfp->Channel,
+                                           &Adapter->parsed_region_chan);
+            }
+
+            switch (scanRegion->Band) {
+            case BAND_B:
+            case BAND_G:
+            default:
+                scanChanList[chanIdx].RadioType = HostCmd_SCAN_RADIO_TYPE_BG;
+                break;
+            }
+
+            if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
+                scanChanList[chanIdx].MaxScanTime =
+                    wlan_cpu_to_le16(Adapter->PassiveScanTime);
+                scanChanList[chanIdx].ChanScanMode.PassiveScan = TRUE;
+            } else {
+                scanChanList[chanIdx].MaxScanTime =
+                    wlan_cpu_to_le16(Adapter->ActiveScanTime);
+                scanChanList[chanIdx].ChanScanMode.PassiveScan = FALSE;
+            }
+
+            scanChanList[chanIdx].ChanNumber = cfp->Channel;
+
+            if (filteredScan) {
+                scanChanList[chanIdx].MaxScanTime =
+                    wlan_cpu_to_le16(Adapter->SpecificScanTime);
+                scanChanList[chanIdx].ChanScanMode.DisableChanFilt = TRUE;
+            }
+        }
+    }
+}
+
+static void
+wlan_add_wps_probe_request_ie(wlan_private * priv, u8 ** ppTlvOut)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypesHeader_t *tlv;
+
+    if (Adapter->wps.wpsIe.VendHdr.Len) {
+        tlv = (MrvlIEtypesHeader_t *) * ppTlvOut;
+        tlv->Type = wlan_cpu_to_le16(TLV_TYPE_WPS_ENROLLEE_PROBE_REQ_TLV);
+        tlv->Len = wlan_cpu_to_le16(Adapter->wps.wpsIe.VendHdr.Len);
+        *ppTlvOut += sizeof(MrvlIEtypesHeader_t);
+        memcpy(*ppTlvOut,
+               Adapter->wps.wpsIe.VendHdr.Oui,
+               Adapter->wps.wpsIe.VendHdr.Len);
+        *ppTlvOut += (Adapter->wps.wpsIe.VendHdr.Len
+                      + sizeof(MrvlIEtypesHeader_t));
+    }
+}
+
+/**
+ *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+ *
+ *  Application layer or other functions can invoke wlan_scan_networks
+ *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ *    This structure is used as the basis of one or many wlan_scan_cmd_config
+ *    commands that are sent to the command processing module and sent to
+ *    firmware.
+ *
+ *  Create a wlan_scan_cmd_config based on the following user supplied
+ *    parameters (if present):
+ *             - SSID filter
+ *             - BSSID filter
+ *             - Number of Probes to be sent
+ *             - Channel list
+ *
+ *  If the SSID or BSSID filter is not present, disable/clear the filter.
+ *  If the number of probes is not set, use the adapter default setting
+ *  Qualify the channel
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param pUserScanIn      NULL or pointer to scan configuration parameters
+ *  @param pScanCfgOut      Output parameter: Resulting scan configuration
+ *  @param ppChanTlvOut     Output parameter: Pointer to the start of the
+ *                          channel TLV portion of the output scan config
+ *  @param pScanChanList    Output parameter: Pointer to the resulting channel
+ *                          list to scan
+ *  @param pMaxChanPerScan  Output parameter: Number of channels to scan for
+ *                          each issuance of the firmware scan command
+ *  @param pFilteredScan    Output parameter: Flag indicating whether or not
+ *                          a BSSID or SSID filter is being sent in the
+ *                          command to firmware.  Used to increase the number
+ *                          of channels sent in a scan command and to 
+ *                          disable the firmware channel scan filter.
+ *  @param pScanCurrentOnly Output parameter: Flag indicating whether or not
+ *                          we are only scanning our current active channel
+ *
+ *  @return                 void
+ */
+static void
+wlan_scan_setup_scan_config(wlan_private * priv,
+                            const wlan_ioctl_user_scan_cfg * pUserScanIn,
+                            wlan_scan_cmd_config * pScanCfgOut,
+                            MrvlIEtypes_ChanListParamSet_t ** ppChanTlvOut,
+                            ChanScanParamSet_t * pScanChanList,
+                            int *pMaxChanPerScan,
+                            BOOLEAN * pFilteredScan,
+                            BOOLEAN * pScanCurrentOnly)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    const u8 zeroMac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+    MrvlIEtypes_NumProbes_t *pNumProbesTlv;
+    u8 *pTlvPos;
+    u16 numProbes;
+    u16 ssidLen;
+    int chanIdx;
+    int scanType;
+    int scanDur;
+    int channel;
+    int radioType;
+    int ssidIdx;
+    BOOLEAN ssidFilter;
+
+    MrvlIEtypes_WildCardSsIdParamSet_t *pWildCardSsidTlv;
+
+    /* The tlvBufferLen is calculated for each scan command.  The TLVs added
+     *   in this routine will be preserved since the routine that sends
+     *   the command will append channelTLVs at *ppChanTlvOut.  The difference
+     *   between the *ppChanTlvOut and the tlvBuffer start will be used
+     *   to calculate the size of anything we add in this routine.
+     */
+    pScanCfgOut->tlvBufferLen = 0;
+
+    /* Running tlv pointer.  Assigned to ppChanTlvOut at end of function
+     *  so later routines know where channels can be added to the command buf
+     */
+    pTlvPos = pScanCfgOut->tlvBuffer;
+
+    /*
+     * Set the initial scan paramters for progressive scanning.  If a specific
+     *   BSSID or SSID is used, the number of channels in the scan command
+     *   will be increased to the absolute maximum
+     */
+    *pMaxChanPerScan = MRVDRV_MAX_CHANNELS_PER_SCAN;
+
+    /* Initialize the scan as un-filtered; the flag is later set to
+     *   TRUE below if a SSID or BSSID filter is sent in the command
+     */
+    *pFilteredScan = FALSE;
+
+    /* Initialize the scan as not being only on the current channel.  If
+     *   the channel list is customized, only contains one channel, and
+     *   is the active channel, this is set true and data flow is not halted.
+     */
+    *pScanCurrentOnly = FALSE;
+
+    if (pUserScanIn) {
+
+        /* Default the ssidFilter flag to TRUE, set false under certain 
+         *   wildcard conditions and qualified by the existence of an SSID 
+         *   list before marking the scan as filtered
+         */
+        ssidFilter = TRUE;
+
+        /* Set the bss type scan filter, use Adapter setting if unset */
+        pScanCfgOut->bssType = (pUserScanIn->bssType ? pUserScanIn->bssType :
+                                Adapter->ScanMode);
+
+        /* Set the number of probes to send, use Adapter setting if unset */
+        numProbes = (pUserScanIn->numProbes ? pUserScanIn->numProbes :
+                     Adapter->ScanProbes);
+
+        /*
+         * Set the BSSID filter to the incoming configuration,
+         *   if non-zero.  If not set, it will remain disabled (all zeros).
+         */
+        memcpy(pScanCfgOut->specificBSSID,
+               pUserScanIn->specificBSSID,
+               sizeof(pScanCfgOut->specificBSSID));
+
+        for (ssidIdx = 0; ((ssidIdx < NELEMENTS(pUserScanIn->ssidList))
+                           && (*pUserScanIn->ssidList[ssidIdx].ssid
+                               || pUserScanIn->ssidList[ssidIdx].maxLen));
+             ssidIdx++) {
+
+            ssidLen = strlen(pUserScanIn->ssidList[ssidIdx].ssid) + 1;
+
+            pWildCardSsidTlv = (MrvlIEtypes_WildCardSsIdParamSet_t *) pTlvPos;
+            pWildCardSsidTlv->Header.Type
+                = wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+            pWildCardSsidTlv->Header.Len
+                = ssidLen + sizeof(pWildCardSsidTlv->MaxSsidLength);
+            pWildCardSsidTlv->MaxSsidLength
+                = pUserScanIn->ssidList[ssidIdx].maxLen;
+
+            memcpy(pWildCardSsidTlv->SsId,
+                   pUserScanIn->ssidList[ssidIdx].ssid, ssidLen);
+
+            pTlvPos += (sizeof(pWildCardSsidTlv->Header)
+                        + pWildCardSsidTlv->Header.Len);
+
+            pWildCardSsidTlv->Header.Len
+                = wlan_cpu_to_le16(pWildCardSsidTlv->Header.Len);
+
+            PRINTM(INFO, "Scan: ssidList[%d]: %s, %d\n",
+                   ssidIdx,
+                   pWildCardSsidTlv->SsId, pWildCardSsidTlv->MaxSsidLength);
+
+            /* Empty wildcard ssid with a maxlen will match many or potentially
+             *   all SSIDs (maxlen == 32), therefore do not treat the scan
+             *   as filtered.
+             */
+            if ((ssidLen == 0) && pWildCardSsidTlv->MaxSsidLength) {
+                ssidFilter = FALSE;
+            }
+        }
+
+        /*
+         *  The default number of channels sent in the command is low to
+         *    ensure the response buffer from the firmware does not truncate
+         *    scan results.  That is not an issue with an SSID or BSSID
+         *    filter applied to the scan results in the firmware.
+         */
+        if ((ssidIdx && ssidFilter)
+            || memcmp(pScanCfgOut->specificBSSID, &zeroMac, sizeof(zeroMac))) {
+            *pFilteredScan = TRUE;
+        }
+
+    } else {
+        pScanCfgOut->bssType = Adapter->ScanMode;
+        numProbes = Adapter->ScanProbes;
+    }
+
+    /* If the input config or adapter has the number of Probes set, add tlv */
+    if (numProbes) {
+
+        PRINTM(INFO, "Scan: numProbes = %d\n", numProbes);
+
+        pNumProbesTlv = (MrvlIEtypes_NumProbes_t *) pTlvPos;
+        pNumProbesTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+        pNumProbesTlv->Header.Len = sizeof(pNumProbesTlv->NumProbes);
+        pNumProbesTlv->NumProbes = wlan_cpu_to_le16(numProbes);
+
+        pTlvPos += sizeof(pNumProbesTlv->Header) + pNumProbesTlv->Header.Len;
+
+        pNumProbesTlv->Header.Len =
+            wlan_cpu_to_le16(pNumProbesTlv->Header.Len);
+    }
+
+    wlan_add_wps_probe_request_ie(priv, &pTlvPos);
+
+    /*
+     * Set the output for the channel TLV to the address in the tlv buffer
+     *   past any TLVs that were added in this fuction (SSID, numProbes).
+     *   Channel TLVs will be added past this for each scan command, preserving
+     *   the TLVs that were previously added.
+     */
+    *ppChanTlvOut = (MrvlIEtypes_ChanListParamSet_t *) pTlvPos;
+
+    if (pUserScanIn && pUserScanIn->chanList[0].chanNumber) {
+
+        PRINTM(INFO, "Scan: Using supplied channel list\n");
+
+        for (chanIdx = 0;
+             chanIdx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+             && pUserScanIn->chanList[chanIdx].chanNumber; chanIdx++) {
+
+            channel = pUserScanIn->chanList[chanIdx].chanNumber;
+            (pScanChanList + chanIdx)->ChanNumber = channel;
+
+            radioType = pUserScanIn->chanList[chanIdx].radioType;
+            (pScanChanList + chanIdx)->RadioType = radioType;
+
+            scanType = pUserScanIn->chanList[chanIdx].scanType;
+
+            if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
+                (pScanChanList + chanIdx)->ChanScanMode.PassiveScan = TRUE;
+            } else {
+                (pScanChanList + chanIdx)->ChanScanMode.PassiveScan = FALSE;
+            }
+
+            if (pUserScanIn->chanList[chanIdx].scanTime) {
+                scanDur = pUserScanIn->chanList[chanIdx].scanTime;
+            } else {
+                if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
+                    scanDur = Adapter->PassiveScanTime;
+                } else if (*pFilteredScan) {
+                    scanDur = Adapter->SpecificScanTime;
+                } else {
+                    scanDur = Adapter->ActiveScanTime;
+                }
+            }
+
+            (pScanChanList + chanIdx)->MinScanTime =
+                wlan_cpu_to_le16(scanDur);
+            (pScanChanList + chanIdx)->MaxScanTime =
+                wlan_cpu_to_le16(scanDur);
+        }
+
+        /* Check if we are only scanning the current channel */
+        if ((chanIdx == 1)
+            && (pUserScanIn->chanList[0].chanNumber
+                == priv->adapter->CurBssParams.BSSDescriptor.Channel)) {
+            *pScanCurrentOnly = TRUE;
+            PRINTM(INFO, "Scan: Scanning current channel only");
+        }
+
+    } else {
+        PRINTM(INFO, "Scan: Creating full region channel list\n");
+        wlan_scan_create_channel_list(priv, pScanChanList, *pFilteredScan);
+    }
+}
+
+/**
+ *  @brief Construct and send multiple scan config commands to the firmware
+ *
+ *  Previous routines have created a wlan_scan_cmd_config with any requested
+ *   TLVs.  This function splits the channel TLV into maxChanPerScan lists
+ *   and sends the portion of the channel TLV along with the other TLVs
+ *   to the wlan_cmd routines for execution in the firmware.
+ *
+ *  @param priv            A pointer to wlan_private structure
+ *  @param maxChanPerScan  Maximum number channels to be included in each
+ *                         scan command sent to firmware
+ *  @param filteredScan    Flag indicating whether or not a BSSID or SSID
+ *                         filter is being used for the firmware command
+ *                         scan command sent to firmware
+ *  @param pScanCfgOut     Scan configuration used for this scan.
+ *  @param pChanTlvOut     Pointer in the pScanCfgOut where the channel TLV
+ *                         should start.  This is past any other TLVs that
+ *                         must be sent down in each firmware command.
+ *  @param pScanChanList   List of channels to scan in maxChanPerScan segments
+ *
+ *  @return                WLAN_STATUS_SUCCESS or error return otherwise
+ */
+static int
+wlan_scan_channel_list(wlan_private * priv,
+                       int maxChanPerScan,
+                       BOOLEAN filteredScan,
+                       wlan_scan_cmd_config * pScanCfgOut,
+                       MrvlIEtypes_ChanListParamSet_t * pChanTlvOut,
+                       ChanScanParamSet_t * pScanChanList)
+{
+    ChanScanParamSet_t *pTmpChan;
+    ChanScanParamSet_t *pStartChan;
+    u8 scanBand;
+    int doneEarly;
+    int tlvIdx;
+    int totalscantime;
+    int ret;
+
+    ENTER();
+
+    if (pScanCfgOut == 0 || pChanTlvOut == 0 || pScanChanList == 0) {
+        PRINTM(INFO, "Scan: Null detect: %p, %p, %p\n",
+               pScanCfgOut, pChanTlvOut, pScanChanList);
+        return WLAN_STATUS_FAILURE;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    pChanTlvOut->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+
+    /* Set the temp channel struct pointer to the start of the desired list */
+    pTmpChan = pScanChanList;
+
+    /* Loop through the desired channel list, sending a new firmware scan
+     *   commands for each maxChanPerScan channels (or for 1,6,11 individually
+     *   if configured accordingly)
+     */
+    while (pTmpChan->ChanNumber) {
+
+        tlvIdx = 0;
+        totalscantime = 0;
+        pChanTlvOut->Header.Len = 0;
+        scanBand = pTmpChan->RadioType;
+        pStartChan = pTmpChan;
+        doneEarly = FALSE;
+
+        /* Construct the Channel TLV for the scan command.  Continue to
+         *  insert channel TLVs until:
+         *    - the tlvIdx hits the maximum configured per scan command
+         *    - the next channel to insert is 0 (end of desired channel list)
+         *    - doneEarly is set (controlling individual scanning of 1,6,11)
+         */
+        while (tlvIdx < maxChanPerScan && pTmpChan->ChanNumber && !doneEarly) {
+
+            PRINTM(INFO, "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n",
+                   pTmpChan->ChanNumber,
+                   pTmpChan->RadioType,
+                   pTmpChan->ChanScanMode.PassiveScan,
+                   pTmpChan->ChanScanMode.DisableChanFilt,
+                   pTmpChan->MaxScanTime);
+
+            /* Copy the current channel TLV to the command being prepared */
+            memcpy(pChanTlvOut->ChanScanParam + tlvIdx,
+                   pTmpChan, sizeof(pChanTlvOut->ChanScanParam));
+
+            /* Increment the TLV header length by the size appended */
+            pChanTlvOut->Header.Len += sizeof(pChanTlvOut->ChanScanParam);
+
+            /*
+             *  The tlv buffer length is set to the number of bytes of the
+             *    between the channel tlv pointer and the start of the
+             *    tlv buffer.  This compensates for any TLVs that were appended
+             *    before the channel list.
+             */
+            pScanCfgOut->tlvBufferLen = ((u8 *) pChanTlvOut
+                                         - pScanCfgOut->tlvBuffer);
+
+            /*  Add the size of the channel tlv header and the data length */
+            pScanCfgOut->tlvBufferLen += (sizeof(pChanTlvOut->Header)
+                                          + pChanTlvOut->Header.Len);
+
+            /* Increment the index to the channel tlv we are constructing */
+            tlvIdx++;
+
+            /* Count the total scan time per command */
+            totalscantime += pTmpChan->MaxScanTime;
+
+            doneEarly = FALSE;
+
+            /* Stop the loop if the *current* channel is in the 1,6,11 set
+             *   and we are not filtering on a BSSID or SSID.
+             */
+            if (!filteredScan && (pTmpChan->ChanNumber == 1
+                                  || pTmpChan->ChanNumber == 6
+                                  || pTmpChan->ChanNumber == 11)) {
+                doneEarly = TRUE;
+            }
+
+            /* Increment the tmp pointer to the next channel to be scanned */
+            pTmpChan++;
+
+            /* Stop the loop if the *next* channel is in the 1,6,11 set.
+             *  This will cause it to be the only channel scanned on the next
+             *  interation
+             */
+            if (!filteredScan && (pTmpChan->ChanNumber == 1
+                                  || pTmpChan->ChanNumber == 6
+                                  || pTmpChan->ChanNumber == 11)) {
+                doneEarly = TRUE;
+            }
+        }
+
+        /* The total scan time should be less than scan command timeout value */
+        if (totalscantime > MRVDRV_MAX_TOTAL_SCAN_TIME) {
+            PRINTM(MSG,
+                   "Total scan time %d ms is over limit (%d ms), scan skipped\n",
+                   totalscantime, MRVDRV_MAX_TOTAL_SCAN_TIME);
+            ret = WLAN_STATUS_FAILURE;
+            break;
+        }
+
+        pChanTlvOut->Header.Len = wlan_cpu_to_le16(pChanTlvOut->Header.Len);
+
+        /* Send the scan command to the firmware with the specified cfg */
+        ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SCAN, 0,
+                                    HostCmd_OPTION_WAITFORRSP, 0,
+                                    pScanCfgOut);
+    }
+
+    LEAVE();
+
+    if (ret) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Internal function used to start a scan based on an input config
+ *
+ *  Use the input user scan configuration information when provided in
+ *    order to send the appropriate scan commands to firmware to populate or
+ *    update the internal driver scan table
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param pUserScanIn   Pointer to the input configuration for the requested
+ *                       scan.
+ *
+ *  @return              WLAN_STATUS_SUCCESS or < 0 if error
+ */
+static int
+wlan_scan_networks(wlan_private * priv,
+                   const wlan_ioctl_user_scan_cfg * pUserScanIn)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypes_ChanListParamSet_t *pChanTlvOut;
+
+    ChanScanParamSet_t scanChanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+    wlan_scan_cmd_config_tlv scanCfgOut;
+    BOOLEAN keepPreviousScan;
+    BOOLEAN filteredScan;
+    BOOLEAN scanCurrentChanOnly;
+    int maxChanPerScan;
+    int ret;
+    BOOLEAN bBgScan;
+
+    ENTER();
+
+    memset(scanChanList, 0x00, sizeof(scanChanList));
+    memset(&scanCfgOut, 0x00, sizeof(scanCfgOut));
+
+    keepPreviousScan = FALSE;
+
+    wlan_scan_setup_scan_config(priv,
+                                pUserScanIn,
+                                &scanCfgOut.config,
+                                &pChanTlvOut,
+                                scanChanList,
+                                &maxChanPerScan,
+                                &filteredScan, &scanCurrentChanOnly);
+
+    if (pUserScanIn) {
+        keepPreviousScan = pUserScanIn->keepPreviousScan;
+    }
+
+    if (keepPreviousScan == FALSE) {
+        memset(Adapter->ScanTable, 0x00,
+               sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+        Adapter->NumInScanTable = 0;
+        Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
+    }
+
+    /* Keep the data path active if we are only scanning our current channel */
+    if (!scanCurrentChanOnly) {
+        PRINTM(INFO, "Scan: WMM Queue stop\n");
+        priv->wlan_dev.netdev->watchdog_timeo = MRVDRV_SCAN_WATCHDOG_TIMEOUT;
+        /* If WMM queues are in use, only stop the internal data queues */
+        wmm_stop_queue(priv);
+    }
+
+    bBgScan = priv->adapter->bgScanConfig->Enable;
+    if (priv->adapter->bgScanConfig->Enable == TRUE) {
+        wlan_bg_scan_enable(priv, FALSE);
+    }
+
+    ret = wlan_scan_channel_list(priv,
+                                 maxChanPerScan,
+                                 filteredScan,
+                                 &scanCfgOut.config,
+                                 pChanTlvOut, scanChanList);
+
+    /*  Process the resulting scan table:
+     *    - Remove any bad ssids
+     *    - Update our current BSS information from scan data
+     */
+    wlan_scan_process_results(priv);
+
+    if (bBgScan == TRUE) {
+        wlan_bg_scan_enable(priv, TRUE);
+    }
+
+    PRINTM(INFO, "Scan: WMM Queue start\n");
+
+    priv->wlan_dev.netdev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        wmm_start_queue(priv);
+    }
+    os_carrier_on(priv);
+    os_start_queue(priv);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Create a brief scan resp to relay basic BSS info to the app layer
+ *
+ *  When the beacon/probe response has not been buffered, use the saved BSS
+ *    information available to provide a minimum response for the application
+ *    ioctl retrieval routines.  Include:
+ *        - Timestamp
+ *        - Beacon Period
+ *        - Capabilities (including WMM Element if available)
+ *        - SSID
+ *
+ *  @param ppBuffer  Output parameter: Buffer used to create basic scan rsp
+ *  @param pBSSDesc  Pointer to a BSS entry in the scan table to create
+ *                   scan response from for delivery to the application layer
+ *
+ *  @return          void
+ */
+static void
+wlan_scan_create_brief_table_entry(u8 ** ppBuffer, BSSDescriptor_t * pBSSDesc)
+{
+    u8 *pTmpBuf = *ppBuffer;
+    u8 tmpSSIDHdr[2];
+    u8 ieLen;
+
+    if (copy_to_user(pTmpBuf, pBSSDesc->TimeStamp,
+                     sizeof(pBSSDesc->TimeStamp))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(pBSSDesc->TimeStamp);
+
+    if (copy_to_user(pTmpBuf, &pBSSDesc->BeaconPeriod,
+                     sizeof(pBSSDesc->BeaconPeriod))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(pBSSDesc->BeaconPeriod);
+
+    if (copy_to_user(pTmpBuf, &pBSSDesc->Cap, sizeof(pBSSDesc->Cap))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(pBSSDesc->Cap);
+
+    tmpSSIDHdr[0] = 0;          /* Element ID for SSID is zero */
+    tmpSSIDHdr[1] = pBSSDesc->Ssid.SsidLength;
+    if (copy_to_user(pTmpBuf, tmpSSIDHdr, sizeof(tmpSSIDHdr))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(tmpSSIDHdr);
+
+    if (copy_to_user(pTmpBuf, pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += pBSSDesc->Ssid.SsidLength;
+
+    if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
+        ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->wmmIE.VendHdr.Len;
+        if (copy_to_user(pTmpBuf, &pBSSDesc->wmmIE, ieLen)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return;
+        }
+
+        pTmpBuf += ieLen;
+    }
+
+    if (pBSSDesc->wpaIE.VendHdr.ElementId == WPA_IE) {
+        ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->wpaIE.VendHdr.Len;
+        if (copy_to_user(pTmpBuf, &pBSSDesc->wpaIE, ieLen)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return;
+        }
+
+        pTmpBuf += ieLen;
+    }
+
+    if (pBSSDesc->rsnIE.IeeeHdr.ElementId == RSN_IE) {
+        ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->rsnIE.IeeeHdr.Len;
+        if (copy_to_user(pTmpBuf, &pBSSDesc->rsnIE, ieLen)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return;
+        }
+
+        pTmpBuf += ieLen;
+    }
+
+    *ppBuffer = pTmpBuf;
+}
+
+/**
+ *  @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ *  TLVs can be included at the end of the scan response BSS information.
+ *    Parse the data in the buffer for pointers to TLVs that can potentially
+ *    be passed back in the response
+ *
+ *  @param pTlv        Pointer to the start of the TLV buffer to parse
+ *  @param tlvBufSize  Size of the TLV buffer
+ *  @param ppTsfTlv    Output parameter: Pointer to the TSF TLV if found
+ *
+ *  @return            void
+ */
+static void
+wlan_ret_802_11_scan_get_tlv_ptrs(MrvlIEtypes_Data_t * pTlv,
+                                  int tlvBufSize,
+                                  MrvlIEtypes_TsfTimestamp_t ** ppTsfTlv)
+{
+    MrvlIEtypes_Data_t *pCurrentTlv;
+    int tlvBufLeft;
+    u16 tlvType;
+    u16 tlvLen;
+
+    pCurrentTlv = pTlv;
+    tlvBufLeft = tlvBufSize;
+    *ppTsfTlv = NULL;
+
+    PRINTM(INFO, "SCAN_RESP: tlvBufSize = %d\n", tlvBufSize);
+    HEXDUMP("SCAN_RESP: TLV Buf", (u8 *) pTlv, tlvBufSize);
+
+    while (tlvBufLeft >= sizeof(MrvlIEtypesHeader_t)) {
+        tlvType = wlan_le16_to_cpu(pCurrentTlv->Header.Type);
+        tlvLen = wlan_le16_to_cpu(pCurrentTlv->Header.Len);
+
+        switch (tlvType) {
+        case TLV_TYPE_TSFTIMESTAMP:
+            PRINTM(INFO, "SCAN_RESP: TSF Timestamp TLV, len = %d\n", tlvLen);
+            *ppTsfTlv = (MrvlIEtypes_TsfTimestamp_t *) pCurrentTlv;
+            break;
+
+        default:
+            PRINTM(INFO, "SCAN_RESP: Unhandled TLV = %d\n", tlvType);
+            /* Give up, this seems corrupted */
+            return;
+        }                       /* switch */
+
+        tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen);
+        pCurrentTlv = (MrvlIEtypes_Data_t *) (pCurrentTlv->Data + tlvLen);
+    }                           /* while */
+}
+
+/**
+ *  @brief Interpret a BSS scan response returned from the firmware
+ *
+ *  Parse the various fixed fields and IEs passed back for a a BSS probe
+ *   response or beacon from the scan command.  Record information as needed
+ *   in the scan table BSSDescriptor_t for that entry.
+ *
+ *  @param pBSSIDEntry  Output parameter: Pointer to the BSS Entry
+ *
+ *  @return             WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+InterpretBSSDescriptionWithIE(BSSDescriptor_t * pBSSEntry,
+                              u8 ** pBeaconInfo, int *bytesLeft)
+{
+    IEEEtypes_ElementId_e elemID;
+    IEEEtypes_FhParamSet_t *pFH;
+    IEEEtypes_DsParamSet_t *pDS;
+    IEEEtypes_CfParamSet_t *pCF;
+    IEEEtypes_IbssParamSet_t *pIbss;
+    IEEEtypes_CapInfo_t *pCap;
+    WLAN_802_11_FIXED_IEs fixedIE;
+    u8 *pCurrentPtr;
+    u8 *pRate;
+    u8 elemLen;
+    u16 totalIeLen;
+    u8 bytesToCopy;
+    u8 rateSize;
+    u16 beaconSize;
+    BOOLEAN foundDataRateIE;
+    int bytesLeftForCurrentBeacon;
+    IEEEtypes_ERPInfo_t *pERPInfo;
+
+    IEEEtypes_VendorSpecific_t *pVendorIe;
+    const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+    const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+    const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
+
+    IEEEtypes_CountryInfoSet_t *pcountryinfo;
+
+    ENTER();
+
+    foundDataRateIE = FALSE;
+    rateSize = 0;
+    beaconSize = 0;
+
+    if (*bytesLeft >= sizeof(beaconSize)) {
+        /* Extract & convert beacon size from the command buffer */
+        memcpy(&beaconSize, *pBeaconInfo, sizeof(beaconSize));
+        beaconSize = wlan_le16_to_cpu(beaconSize);
+        *bytesLeft -= sizeof(beaconSize);
+        *pBeaconInfo += sizeof(beaconSize);
+    }
+
+    if (beaconSize == 0 || beaconSize > *bytesLeft) {
+
+        *pBeaconInfo += *bytesLeft;
+        *bytesLeft = 0;
+
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /* Initialize the current working beacon pointer for this BSS iteration */
+    pCurrentPtr = *pBeaconInfo;
+
+    /* Advance the return beacon pointer past the current beacon */
+    *pBeaconInfo += beaconSize;
+    *bytesLeft -= beaconSize;
+
+    bytesLeftForCurrentBeacon = beaconSize;
+
+    memcpy(pBSSEntry->MacAddress, pCurrentPtr, MRVDRV_ETH_ADDR_LEN);
+    PRINTM(INFO, "InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x\n",
+           pBSSEntry->MacAddress[0], pBSSEntry->MacAddress[1],
+           pBSSEntry->MacAddress[2], pBSSEntry->MacAddress[3],
+           pBSSEntry->MacAddress[4], pBSSEntry->MacAddress[5]);
+
+    pCurrentPtr += MRVDRV_ETH_ADDR_LEN;
+    bytesLeftForCurrentBeacon -= MRVDRV_ETH_ADDR_LEN;
+
+    if (bytesLeftForCurrentBeacon < 12) {
+        PRINTM(INFO, "InterpretIE: Not enough bytes left\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /*
+     * next 4 fields are RSSI, time stamp, beacon interval,
+     *   and capability information
+     */
+
+    /* RSSI is 1 byte long */
+    pBSSEntry->Rssi = wlan_le32_to_cpu((LONG) (*pCurrentPtr));
+    PRINTM(INFO, "InterpretIE: RSSI=%02X\n", *pCurrentPtr);
+    pCurrentPtr += 1;
+    bytesLeftForCurrentBeacon -= 1;
+
+    /*
+     *  The RSSI is not part of the beacon/probe response.  After we have
+     *    advanced pCurrentPtr past the RSSI field, save the remaining
+     *    data for use at the application layer
+     */
+    pBSSEntry->pBeaconBuf = pCurrentPtr;
+    pBSSEntry->beaconBufSize = bytesLeftForCurrentBeacon;
+
+    /* time stamp is 8 bytes long */
+    memcpy(fixedIE.Timestamp, pCurrentPtr, 8);
+    memcpy(pBSSEntry->TimeStamp, pCurrentPtr, 8);
+    pCurrentPtr += 8;
+    bytesLeftForCurrentBeacon -= 8;
+
+    /* beacon interval is 2 bytes long */
+    memcpy(&fixedIE.BeaconInterval, pCurrentPtr, 2);
+    pBSSEntry->BeaconPeriod = wlan_le16_to_cpu(fixedIE.BeaconInterval);
+    pCurrentPtr += 2;
+    bytesLeftForCurrentBeacon -= 2;
+
+    /* capability information is 2 bytes long */
+    memcpy(&fixedIE.Capabilities, pCurrentPtr, 2);
+    PRINTM(INFO, "InterpretIE: fixedIE.Capabilities=0x%X\n",
+           fixedIE.Capabilities);
+    fixedIE.Capabilities = wlan_le16_to_cpu(fixedIE.Capabilities);
+    pCap = (IEEEtypes_CapInfo_t *) & fixedIE.Capabilities;
+    memcpy(&pBSSEntry->Cap, pCap, sizeof(IEEEtypes_CapInfo_t));
+    pCurrentPtr += 2;
+    bytesLeftForCurrentBeacon -= 2;
+
+    /* rest of the current buffer are IE's */
+    PRINTM(INFO, "InterpretIE: IELength for this AP = %d\n",
+           bytesLeftForCurrentBeacon);
+
+    HEXDUMP("InterpretIE: IE info", (u8 *) pCurrentPtr,
+            bytesLeftForCurrentBeacon);
+
+    if (pCap->Privacy) {
+        PRINTM(INFO, "InterpretIE: AP WEP enabled\n");
+        pBSSEntry->Privacy = Wlan802_11PrivFilter8021xWEP;
+    } else {
+        pBSSEntry->Privacy = Wlan802_11PrivFilterAcceptAll;
+    }
+
+    if (pCap->Ibss == 1) {
+        pBSSEntry->InfrastructureMode = Wlan802_11IBSS;
+    } else {
+        pBSSEntry->InfrastructureMode = Wlan802_11Infrastructure;
+    }
+
+    /* process variable IE */
+    while (bytesLeftForCurrentBeacon >= 2) {
+        elemID = (IEEEtypes_ElementId_e) (*((u8 *) pCurrentPtr));
+        elemLen = *((u8 *) pCurrentPtr + 1);
+        totalIeLen = elemLen + sizeof(IEEEtypes_Header_t);
+
+        if (bytesLeftForCurrentBeacon < elemLen) {
+            PRINTM(INFO, "InterpretIE: Error in processing IE, "
+                   "bytes left < IE length\n");
+            bytesLeftForCurrentBeacon = 0;
+            continue;
+        }
+
+        switch (elemID) {
+
+        case SSID:
+            pBSSEntry->Ssid.SsidLength = elemLen;
+            memcpy(pBSSEntry->Ssid.Ssid, (pCurrentPtr + 2), elemLen);
+            PRINTM(INFO, "InterpretIE: Ssid: %-32s\n", pBSSEntry->Ssid.Ssid);
+            break;
+
+        case SUPPORTED_RATES:
+            memcpy(pBSSEntry->DataRates, pCurrentPtr + 2, elemLen);
+            memcpy(pBSSEntry->SupportedRates, pCurrentPtr + 2, elemLen);
+            HEXDUMP("InterpretIE: SupportedRates:",
+                    pBSSEntry->SupportedRates, elemLen);
+            rateSize = elemLen;
+            foundDataRateIE = TRUE;
+            break;
+
+        case EXTRA_IE:
+            PRINTM(INFO, "InterpretIE: EXTRA_IE Found!\n");
+            pBSSEntry->extra_ie = 1;
+            break;
+
+        case FH_PARAM_SET:
+            pFH = (IEEEtypes_FhParamSet_t *) pCurrentPtr;
+            pBSSEntry->NetworkTypeInUse = Wlan802_11FH;
+            memcpy(&pBSSEntry->PhyParamSet.FhParamSet, pFH,
+                   sizeof(IEEEtypes_FhParamSet_t));
+            pBSSEntry->PhyParamSet.FhParamSet.DwellTime
+                =
+                wlan_le16_to_cpu(pBSSEntry->PhyParamSet.FhParamSet.DwellTime);
+            break;
+
+        case DS_PARAM_SET:
+            pDS = (IEEEtypes_DsParamSet_t *) pCurrentPtr;
+
+            pBSSEntry->NetworkTypeInUse = Wlan802_11DS;
+            pBSSEntry->Channel = pDS->CurrentChan;
+
+            memcpy(&pBSSEntry->PhyParamSet.DsParamSet, pDS,
+                   sizeof(IEEEtypes_DsParamSet_t));
+            break;
+
+        case CF_PARAM_SET:
+            pCF = (IEEEtypes_CfParamSet_t *) pCurrentPtr;
+            memcpy(&pBSSEntry->SsParamSet.CfParamSet, pCF,
+                   sizeof(IEEEtypes_CfParamSet_t));
+            break;
+
+        case IBSS_PARAM_SET:
+            pIbss = (IEEEtypes_IbssParamSet_t *) pCurrentPtr;
+            pBSSEntry->ATIMWindow = wlan_le32_to_cpu(pIbss->AtimWindow);
+            memcpy(&pBSSEntry->SsParamSet.IbssParamSet, pIbss,
+                   sizeof(IEEEtypes_IbssParamSet_t));
+            break;
+
+            /* Handle Country Info IE */
+        case COUNTRY_INFO:
+            pcountryinfo = (IEEEtypes_CountryInfoSet_t *) pCurrentPtr;
+
+            if (pcountryinfo->Len < sizeof(pcountryinfo->CountryCode)
+                || pcountryinfo->Len > 254) {
+                PRINTM(INFO, "InterpretIE: 11D- Err "
+                       "CountryInfo len =%d min=%d max=254\n",
+                       pcountryinfo->Len, sizeof(pcountryinfo->CountryCode));
+                LEAVE();
+                return WLAN_STATUS_FAILURE;
+            }
+
+            memcpy(&pBSSEntry->CountryInfo,
+                   pcountryinfo, pcountryinfo->Len + 2);
+            HEXDUMP("InterpretIE: 11D- CountryInfo:",
+                    (u8 *) pcountryinfo, (u32) (pcountryinfo->Len + 2));
+            break;
+        case ERP_INFO:
+            pERPInfo = (IEEEtypes_ERPInfo_t *) pCurrentPtr;
+            pBSSEntry->ERPFlags = pERPInfo->ERPFlags;
+            break;
+        case EXTENDED_SUPPORTED_RATES:
+            /*
+             * only process extended supported rate
+             * if data rate is already found.
+             * data rate IE should come before
+             * extended supported rate IE
+             */
+            if (foundDataRateIE) {
+                if ((elemLen + rateSize) > WLAN_SUPPORTED_RATES) {
+                    bytesToCopy = (WLAN_SUPPORTED_RATES - rateSize);
+                } else {
+                    bytesToCopy = elemLen;
+                }
+
+                pRate = (u8 *) pBSSEntry->DataRates;
+                pRate += rateSize;
+                memcpy(pRate, pCurrentPtr + 2, bytesToCopy);
+
+                pRate = (u8 *) pBSSEntry->SupportedRates;
+                pRate += rateSize;
+                memcpy(pRate, pCurrentPtr + 2, bytesToCopy);
+            }
+            HEXDUMP("InterpretIE: ExtSupportedRates:",
+                    pBSSEntry->SupportedRates, elemLen + rateSize);
+            break;
+
+        case VENDOR_SPECIFIC_221:
+            pVendorIe = (IEEEtypes_VendorSpecific_t *) pCurrentPtr;
+
+            if ((!memcmp
+                 (pVendorIe->VendHdr.Oui, wpa_oui,
+                  sizeof(pVendorIe->VendHdr.Oui)))
+                && (pVendorIe->VendHdr.OuiType == wpa_oui[3])) {
+                pBSSEntry->wpaIE.VendHdr.Len
+                    = (MIN(totalIeLen, sizeof(pBSSEntry->wpaIE))
+                       - sizeof(IEEEtypes_Header_t));
+
+                memcpy(&pBSSEntry->wpaIE,
+                       pCurrentPtr,
+                       (pBSSEntry->wpaIE.VendHdr.Len
+                        + sizeof(IEEEtypes_Header_t)));
+
+                HEXDUMP("InterpretIE: Resp WPA_IE",
+                        (u8 *) & pBSSEntry->wpaIE,
+                        (pBSSEntry->wpaIE.VendHdr.Len
+                         + sizeof(IEEEtypes_Header_t)));
+            } else
+                if ((!memcmp
+                     (pVendorIe->VendHdr.Oui, wmm_oui,
+                      sizeof(pVendorIe->VendHdr.Oui)))
+                    && (pVendorIe->VendHdr.OuiType == wmm_oui[3])) {
+                if (totalIeLen == sizeof(IEEEtypes_WmmParameter_t)
+                    || totalIeLen == sizeof(IEEEtypes_WmmInfo_t)) {
+
+                    /* Only accept and copy the WMM IE if it matches
+                     *  the size expected for the WMM Info IE or the
+                     *  WMM Parameter IE.
+                     */
+                    memcpy((u8 *) & pBSSEntry->wmmIE, pCurrentPtr,
+                           totalIeLen);
+                    HEXDUMP("InterpretIE: Resp WMM_IE",
+                            (u8 *) & pBSSEntry->wmmIE, totalIeLen);
+                }
+            } else
+                if ((!memcmp
+                     (pVendorIe->VendHdr.Oui, wps_oui,
+                      sizeof(pVendorIe->VendHdr.Oui)))
+                    && (pVendorIe->VendHdr.OuiType == wps_oui[3])) {
+                memcpy((u8 *) & pBSSEntry->wpsIE, pCurrentPtr, totalIeLen);
+                HEXDUMP("InterpretIE: Resp WPS_IE",
+                        (u8 *) & pBSSEntry->wpsIE, totalIeLen);
+            }
+            break;
+        case RSN_IE:
+            pBSSEntry->rsnIE.IeeeHdr.Len
+                = (MIN(totalIeLen, sizeof(pBSSEntry->rsnIE))
+                   - sizeof(IEEEtypes_Header_t));
+
+            memcpy(&pBSSEntry->rsnIE,
+                   pCurrentPtr,
+                   pBSSEntry->rsnIE.IeeeHdr.Len + sizeof(IEEEtypes_Header_t));
+
+            HEXDUMP("InterpretIE: Resp RSN_IE",
+                    (u8 *) & pBSSEntry->rsnIE,
+                    pBSSEntry->rsnIE.IeeeHdr.Len +
+                    sizeof(IEEEtypes_Header_t));
+            break;
+        }
+
+        pCurrentPtr += elemLen + 2;
+
+        /* need to account for IE ID and IE Len */
+        bytesLeftForCurrentBeacon -= (elemLen + 2);
+
+    }                           /* while (bytesLeftForCurrentBeacon > 2) */
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0--ssid is same, otherwise is different
+ */
+int
+SSIDcmp(WLAN_802_11_SSID * ssid1, WLAN_802_11_SSID * ssid2)
+{
+    if (!ssid1 || !ssid2)
+        return -1;
+
+    if (ssid1->SsidLength != ssid2->SsidLength)
+        return -1;
+
+    return memcmp(ssid1->Ssid, ssid2->Ssid, ssid1->SsidLength);
+}
+
+/**
+ *  @brief This function finds a specific compatible BSSID in the scan list
+ *
+ *  @param Adapter  A pointer to wlan_adapter
+ *  @param bssid    BSSID to find in the scan list
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list, or error return code (< 0)
+ */
+int
+FindBSSIDInList(wlan_adapter * Adapter, u8 * bssid, int mode)
+{
+    int ret = -ENETUNREACH;
+    int i;
+
+    if (!bssid)
+        return -EFAULT;
+
+    PRINTM(INFO, "FindBSSID: Num of BSSIDs = %d\n", Adapter->NumInScanTable);
+
+    /* Look through the scan table for a compatible match. The ret return
+     *   variable will be equal to the index in the scan table (greater
+     *   than zero) if the network is compatible.  The loop will continue
+     *   past a matched bssid that is not compatible in case there is an
+     *   AP with multiple SSIDs assigned to the same BSSID
+     */
+    for (i = 0; ret < 0 && i < Adapter->NumInScanTable; i++) {
+        if (!memcmp(Adapter->ScanTable[i].MacAddress, bssid, ETH_ALEN)) {
+            switch (mode) {
+            case Wlan802_11Infrastructure:
+            case Wlan802_11IBSS:
+                ret = IsNetworkCompatible(Adapter, i, mode);
+                break;
+            default:
+                ret = i;
+                break;
+            }
+        }
+    }
+
+    if (ret >= 0) {
+        if (find_cfp_by_band_and_channel
+            (Adapter, 0, Adapter->ScanTable[ret].Channel) == NULL) {
+            ret = -ENETUNREACH;
+        }
+    }
+    return ret;
+}
+
+/**
+ *  @brief This function finds ssid in ssid list.
+ *
+ *  @param Adapter      A pointer to wlan_adapter
+ *  @param ssid         SSID to find in the list
+ *  @param bssid        BSSID to qualify the SSID selection (if provided)
+ *  @param mode         Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list
+ */
+int
+FindSSIDInList(wlan_adapter * Adapter, WLAN_802_11_SSID * ssid,
+               u8 * bssid, int mode)
+{
+    int net = -ENETUNREACH;
+    u8 bestrssi = 0;
+    int i, j;
+
+    PRINTM(INFO, "Num of Entries in Table = %d\n", Adapter->NumInScanTable);
+
+    /* Loop through the table until the maximum is reached or until a match
+     *   is found based on the bssid field comparison 
+     */
+    for (i = 0;
+         i < Adapter->NumInScanTable && (bssid == NULL || (bssid && net < 0));
+         i++) {
+
+        if (!SSIDcmp(&Adapter->ScanTable[i].Ssid, ssid) && ((bssid == NULL)
+                                                            ||
+                                                            !memcmp(Adapter->
+                                                                    ScanTable
+                                                                    [i].
+                                                                    MacAddress,
+                                                                    bssid,
+                                                                    ETH_ALEN)))
+        {
+            switch (mode) {
+            case Wlan802_11Infrastructure:
+            case Wlan802_11IBSS:
+                j = IsNetworkCompatible(Adapter, i, mode);
+
+                if (j >= 0) {
+                    if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                        bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                        net = i;
+                    }
+                } else {
+                    if (net == -ENETUNREACH) {
+                        net = j;
+                    }
+                }
+                break;
+            case Wlan802_11AutoUnknown:
+            default:
+                /* Do not check compatibility if the mode requested is 
+                 *   AutoUnknown.  Allows generic find to work without 
+                 *   verifying against the Adapter security settings
+                 */
+                if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                    bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                    net = i;
+                }
+                break;
+            }
+        }
+    }
+    if (net >= 0) {
+        if (find_cfp_by_band_and_channel
+            (Adapter, 0, Adapter->ScanTable[net].Channel) == NULL) {
+            net = -ENETUNREACH;
+        }
+    }
+    return net;
+}
+
+/**
+ *  @brief This function finds the best SSID in the Scan List
+ *
+ *  Search the scan table for the best SSID that also matches the current
+ *   adapter network preference (infrastructure or adhoc)
+ *
+ *  @param Adapter  A pointer to wlan_adapter
+ *
+ *  @return         index in BSSID list
+ */
+int
+FindBestSSIDInList(wlan_adapter * Adapter)
+{
+    int mode = Adapter->InfrastructureMode;
+    int bestnet = -ENETUNREACH;
+    u8 bestrssi = 0;
+    int i;
+
+    ENTER();
+
+    PRINTM(INFO, "Num of BSSIDs = %d\n", Adapter->NumInScanTable);
+
+    for (i = 0; i < Adapter->NumInScanTable; i++) {
+        switch (mode) {
+        case Wlan802_11Infrastructure:
+        case Wlan802_11IBSS:
+            if (IsNetworkCompatible(Adapter, i, mode) >= 0) {
+                if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                    bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                    bestnet = i;
+                }
+            }
+            break;
+        case Wlan802_11AutoUnknown:
+        default:
+            if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                bestnet = i;
+            }
+            break;
+        }
+    }
+
+    LEAVE();
+    return bestnet;
+}
+
+/**
+ *  @brief Find the AP with specific ssid in the scan list
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pSSID        A pointer to AP's ssid
+ *
+ *  @return             WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+FindBestNetworkSsid(wlan_private * priv, WLAN_802_11_SSID * pSSID)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    BSSDescriptor_t *pReqBSSID;
+    int i;
+
+    ENTER();
+
+    memset(pSSID, 0, sizeof(WLAN_802_11_SSID));
+
+    wlan_scan_networks(priv, NULL);
+
+    i = FindBestSSIDInList(Adapter);
+
+    if (i >= 0) {
+
+        pReqBSSID = &Adapter->ScanTable[i];
+        memcpy(pSSID, &pReqBSSID->Ssid, sizeof(WLAN_802_11_SSID));
+
+        /* Make sure we are in the right mode */
+        if (Adapter->InfrastructureMode == Wlan802_11AutoUnknown) {
+            Adapter->InfrastructureMode = pReqBSSID->InfrastructureMode;
+
+            ret = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_802_11_SNMP_MIB,
+                                        HostCmd_ACT_SET,
+                                        HostCmd_OPTION_WAITFORRSP,
+                                        OID_802_11_INFRASTRUCTURE_MODE, NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+        }
+    }
+
+    if (!pSSID->SsidLength) {
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Delete a specific indexed entry from the scan table.
+ *
+ *  Delete the scan table entry indexed by tableIdx.  Compact the remaining
+ *    entries and adjust any buffering of beacon/probe response data
+ *    if needed.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param tableIdx   Scan table entry index to delete from the table
+ *
+ *  @return           void
+ *
+ *  @pre              tableIdx must be an index to a valid entry
+ */
+static void
+wlan_scan_delete_table_entry(wlan_private * priv, int tableIdx)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int delIdx;
+    uint beaconBufAdj;
+    u8 *pBeaconBuf;
+
+    /* Shift the saved beacon buffer data for the scan table back over the
+     *   entry being removed.  Update the end of buffer pointer.  Save the 
+     *   deleted buffer allocation size for pointer adjustments for entries
+     *   compacted after the deleted index.
+     */
+    beaconBufAdj = Adapter->ScanTable[tableIdx].beaconBufSizeMax;
+
+    PRINTM(INFO, "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
+           tableIdx, beaconBufAdj);
+
+    /* Check if the table entry had storage allocated for its beacon */
+    if (beaconBufAdj) {
+        pBeaconBuf = Adapter->ScanTable[tableIdx].pBeaconBuf;
+
+        /* Remove the entry's buffer space, decrement the table end pointer
+         *   by the amount we are removing 
+         */
+        Adapter->pBeaconBufEnd -= beaconBufAdj;
+
+        PRINTM(INFO,
+               "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
+               tableIdx,
+               pBeaconBuf,
+               pBeaconBuf + beaconBufAdj,
+               Adapter->pBeaconBufEnd - pBeaconBuf);
+
+        /* Compact data storage.  Copy all data after the deleted entry's
+         *   end address (pBeaconBuf + beaconBufAdj) back to the original
+         *   start address (pBeaconBuf).
+         *
+         * Scan table entries affected by the move will have their entry
+         *   pointer adjusted below.
+         *
+         * Use memmove since the dest/src memory regions overlap.
+         */
+        memmove(pBeaconBuf,
+                pBeaconBuf + beaconBufAdj,
+                Adapter->pBeaconBufEnd - pBeaconBuf);
+    }
+
+    PRINTM(INFO, "Scan: Delete Entry %d, NumInScanTable = %d\n",
+           tableIdx, Adapter->NumInScanTable);
+
+    /* Shift all of the entries after the tableIdx back by one, compacting
+     *   the table and removing the requested entry
+     */
+    for (delIdx = tableIdx; (delIdx + 1) < Adapter->NumInScanTable; delIdx++) {
+        /* Copy the next entry over this one */
+        memcpy(Adapter->ScanTable + delIdx,
+               Adapter->ScanTable + delIdx + 1, sizeof(BSSDescriptor_t));
+
+        /* Adjust this entry's pointer to its beacon buffer based on the 
+         *   removed/compacted entry from the deleted index.  Don't decrement
+         *   if the buffer pointer is NULL (no data stored for this entry).
+         */
+        if (Adapter->ScanTable[delIdx].pBeaconBuf) {
+            Adapter->ScanTable[delIdx].pBeaconBuf -= beaconBufAdj;
+        }
+    }
+
+    /* The last entry is invalid now that it has been deleted or moved back */
+    memset(Adapter->ScanTable + Adapter->NumInScanTable - 1,
+           0x00, sizeof(BSSDescriptor_t));
+
+    Adapter->NumInScanTable--;
+}
+
+/**
+ *  @brief Delete all occurrences of a given SSID from the scan table
+ *
+ *  Iterate through the scan table and delete all entries that match a given
+ *    SSID.  Compact the remaining scan table entries.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param pDelSSID   Pointer to an SSID struct to use in deleting all
+ *                    matching SSIDs from the scan table
+ *
+ *  @return           WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ */
+static int
+wlan_scan_delete_ssid_table_entry(wlan_private * priv,
+                                  WLAN_802_11_SSID * pDelSSID)
+{
+    int tableIdx;
+    int retval = WLAN_STATUS_FAILURE;
+
+    ENTER();
+
+    PRINTM(INFO, "Scan: Delete Ssid Entry: %-32s\n", pDelSSID->Ssid);
+
+    /* If the requested SSID is found in the table, delete it.  Then keep
+     *   searching the table for multiple entires for the SSID until no
+     *   more are found 
+     */
+    while ((tableIdx = FindSSIDInList(priv->adapter,
+                                      pDelSSID,
+                                      NULL, Wlan802_11AutoUnknown)) >= 0) {
+        PRINTM(INFO, "Scan: Delete Ssid Entry: Found Idx = %d\n", tableIdx);
+        retval = WLAN_STATUS_SUCCESS;
+        wlan_scan_delete_table_entry(priv, tableIdx);
+    }
+
+    LEAVE();
+
+    return retval;
+}
+
+/**
+ *  @brief Scan Network
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param vwrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_scan(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    union iwreq_data wrqu;
+#if WIRELESS_EXT >= 18
+    struct iw_scan_req *req;
+    struct iw_point *dwrq = (struct iw_point *) vwrq;
+    wlan_ioctl_user_scan_cfg scanCfg;
+#endif
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_set_scan\n");
+        return -EBUSY;
+    }
+#endif
+#if WIRELESS_EXT >= 18
+    if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
+        (dwrq->length == sizeof(struct iw_scan_req))) {
+        req = (struct iw_scan_req *) extra;
+        if (req->essid_len <= WLAN_MAX_SSID_LENGTH) {
+            memset(&scanCfg, 0x00, sizeof(scanCfg));
+            memcpy(scanCfg.ssidList[0].ssid, (u8 *) req->essid,
+                   req->essid_len);
+            if (!wlan_scan_networks(priv, &scanCfg)) {
+                memset(&wrqu, 0, sizeof(union iwreq_data));
+                wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                    NULL);
+            }
+        }
+    } else {
+#endif
+
+        if (!wlan_scan_networks(priv, NULL)) {
+            memset(&wrqu, 0, sizeof(union iwreq_data));
+            wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                NULL);
+        }
+#if WIRELESS_EXT >= 18
+    }
+#endif
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+
+    if (Adapter->SurpriseRemoved)
+        return WLAN_STATUS_FAILURE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Send a scan command for all available channels filtered on a spec
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param pRequestedSSID   A pointer to AP's ssid
+ *
+ *  @return                WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+SendSpecificSSIDScan(wlan_private * priv, WLAN_802_11_SSID * pRequestedSSID)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_user_scan_cfg scanCfg;
+
+    ENTER();
+
+    if (pRequestedSSID == NULL) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    wlan_scan_delete_ssid_table_entry(priv, pRequestedSSID);
+
+    memset(&scanCfg, 0x00, sizeof(scanCfg));
+
+    memcpy(scanCfg.ssidList[0].ssid,
+           pRequestedSSID->Ssid, pRequestedSSID->SsidLength);
+    scanCfg.keepPreviousScan = TRUE;
+
+    wlan_scan_networks(priv, &scanCfg);
+
+    if (Adapter->SurpriseRemoved)
+        return WLAN_STATUS_FAILURE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief scan an AP with specific BSSID
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param bssid     A pointer to AP's bssid
+ *
+ *  @return          WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+SendSpecificBSSIDScan(wlan_private * priv, u8 * bssid)
+{
+    wlan_ioctl_user_scan_cfg scanCfg;
+
+    ENTER();
+
+    if (bssid == NULL) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memset(&scanCfg, 0x00, sizeof(scanCfg));
+    memcpy(scanCfg.specificBSSID, bssid, sizeof(scanCfg.specificBSSID));
+    scanCfg.keepPreviousScan = TRUE;
+
+    wlan_scan_networks(priv, &scanCfg);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_scan(struct net_device *dev, struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    char *current_ev = extra;
+    char *end_buf = extra + IW_SCAN_MAX_DATA;
+    CHANNEL_FREQ_POWER *cfp;
+    BSSDescriptor_t *pScanTable;
+    char *current_val;          /* For rates */
+    struct iw_event iwe;        /* Temporary buffer */
+    int i;
+    int j;
+    int rate;
+
+    u8 buf[16 + 256 * 2];
+    u8 *ptr;
+    u8 *pRawData;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        PRINTM(INFO, "Current Ssid: %-32s\n",
+               Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
+    }
+
+    PRINTM(INFO, "Scan: Get: NumInScanTable = %d\n", Adapter->NumInScanTable);
+
+#if WIRELESS_EXT > 13
+    /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
+     * The new API using SIOCGIWSCAN is only limited by buffer size
+     * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
+     * which is 4096.
+     */
+    for (i = 0; i < Adapter->NumInScanTable; i++) {
+        if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+            PRINTM(INFO, "i=%d break out: current_ev=%p end_buf=%p "
+                   "MAX_SCAN_CELL_SIZE=%d\n",
+                   i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+            break;
+        }
+
+        pScanTable = &Adapter->ScanTable[i];
+
+        PRINTM(INFO, "i=%d  Ssid: %-32s\n", i, pScanTable->Ssid.Ssid);
+
+        cfp =
+            find_cfp_by_band_and_channel(Adapter, 0,
+                                         (u16) pScanTable->Channel);
+        if (!cfp) {
+            PRINTM(INFO, "Invalid channel number %d\n", pScanTable->Channel);
+            continue;
+        }
+
+        if (ssid_valid(&Adapter->ScanTable[i].Ssid) == FALSE) {
+            continue;
+        }
+
+        /* First entry *MUST* be the AP MAC address */
+        iwe.cmd = SIOCGIWAP;
+        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+        memcpy(iwe.u.ap_addr.sa_data,
+               &Adapter->ScanTable[i].MacAddress, ETH_ALEN);
+
+        iwe.len = IW_EV_ADDR_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        //Add the ESSID
+        iwe.u.data.length = Adapter->ScanTable[i].Ssid.SsidLength;
+
+        if (iwe.u.data.length > 32) {
+            iwe.u.data.length = 32;
+        }
+
+        iwe.cmd = SIOCGIWESSID;
+        iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
+        iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                          (s8 *) Adapter->ScanTable[i].Ssid.
+                                          Ssid);
+
+        //Add mode
+        iwe.cmd = SIOCGIWMODE;
+        iwe.u.mode = Adapter->ScanTable[i].InfrastructureMode + 1;
+        iwe.len = IW_EV_UINT_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        //frequency
+        iwe.cmd = SIOCGIWFREQ;
+        iwe.u.freq.m = (long) cfp->Freq * 100000;
+        iwe.u.freq.e = 1;
+        iwe.len = IW_EV_FREQ_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        /* Add quality statistics */
+        iwe.cmd = IWEVQUAL;
+        iwe.u.qual.level = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+        iwe.u.qual.qual = 0;
+        if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+            iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+        } else {
+            iwe.u.qual.noise = CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+        }
+        if ((Adapter->InfrastructureMode == Wlan802_11IBSS) &&
+            !SSIDcmp(&Adapter->CurBssParams.BSSDescriptor.Ssid,
+                     &Adapter->ScanTable[i].Ssid)
+            && Adapter->AdhocCreate) {
+            ret = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_802_11_RSSI,
+                                        0, HostCmd_OPTION_WAITFORRSP, 0,
+                                        NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+            iwe.u.qual.level =
+                CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                         Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+        }
+
+        iwe.len = IW_EV_QUAL_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        /* Add encryption capability */
+        iwe.cmd = SIOCGIWENCODE;
+        if (Adapter->ScanTable[i].Privacy) {
+            iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+        } else {
+            iwe.u.data.flags = IW_ENCODE_DISABLED;
+        }
+        iwe.u.data.length = 0;
+        iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
+
+        current_val = current_ev + IW_EV_LCP_LEN;
+
+        iwe.cmd = SIOCGIWRATE;
+
+        iwe.u.bitrate.fixed = 0;
+        iwe.u.bitrate.disabled = 0;
+        iwe.u.bitrate.value = 0;
+
+        /* Bit rate given in 500 kb/s units (+ 0x80) */
+        for (j = 0; j < sizeof(Adapter->ScanTable[i].SupportedRates); j++) {
+            if (Adapter->ScanTable[i].SupportedRates[j] == 0) {
+                break;
+            }
+            rate = (Adapter->ScanTable[i].SupportedRates[j] & 0x7F) * 500000;
+            if (rate > iwe.u.bitrate.value) {
+                iwe.u.bitrate.value = rate;
+            }
+
+            iwe.u.bitrate.value = (Adapter->ScanTable[i].SupportedRates[j]
+                                   & 0x7f) * 500000;
+            iwe.len = IW_EV_PARAM_LEN;
+            current_ev =
+                iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+                                     iwe.len);
+
+        }
+        if ((Adapter->ScanTable[i].InfrastructureMode == Wlan802_11IBSS) &&
+            !SSIDcmp(&Adapter->CurBssParams.BSSDescriptor.Ssid,
+                     &Adapter->ScanTable[i].Ssid)
+            && Adapter->AdhocCreate) {
+            iwe.u.bitrate.value = 22 * 500000;
+        }
+        iwe.len = IW_EV_PARAM_LEN;
+        current_ev = iwe_stream_add_value(current_ev, current_val, end_buf,
+                                          &iwe, iwe.len);
+
+        /* Add new value to event */
+        current_val = current_ev + IW_EV_LCP_LEN;
+
+        if (Adapter->ScanTable[i].rsnIE.IeeeHdr.ElementId == RSN_IE) {
+            pRawData = (u8 *) & Adapter->ScanTable[i].rsnIE;
+            memset(&iwe, 0, sizeof(iwe));
+            memset(buf, 0, sizeof(buf));
+            ptr = buf;
+#if WIRELESS_EXT >= 18
+            memcpy(buf, pRawData,
+                   Adapter->ScanTable[i].rsnIE.IeeeHdr.Len + 2);
+            iwe.cmd = IWEVGENIE;
+            iwe.u.data.length = Adapter->ScanTable[i].rsnIE.IeeeHdr.Len + 2;
+#else
+            ptr += sprintf(ptr, "rsn_ie=");
+
+            for (j = 0;
+                 j < (Adapter->ScanTable[i].rsnIE.IeeeHdr.Len
+                      + sizeof(IEEEtypes_Header_t)); j++) {
+                ptr += sprintf(ptr, "%02x", *(pRawData + j));
+            }
+            iwe.u.data.length = strlen(buf);
+
+            PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+            PRINTM(INFO, "WPA2 BUF: %s \n", buf);
+
+            iwe.cmd = IWEVCUSTOM;
+#endif
+            iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+            current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+        }
+        if (Adapter->ScanTable[i].wpaIE.VendHdr.ElementId == WPA_IE) {
+            pRawData = (u8 *) & Adapter->ScanTable[i].wpaIE;
+            memset(&iwe, 0, sizeof(iwe));
+            memset(buf, 0, sizeof(buf));
+            ptr = buf;
+#if WIRELESS_EXT >= 18
+            memcpy(buf, pRawData,
+                   Adapter->ScanTable[i].wpaIE.VendHdr.Len + 2);
+            iwe.cmd = IWEVGENIE;
+            iwe.u.data.length = Adapter->ScanTable[i].wpaIE.VendHdr.Len + 2;
+#else
+            ptr += sprintf(ptr, "wpa_ie=");
+
+            for (j = 0;
+                 j < (Adapter->ScanTable[i].wpaIE.VendHdr.Len
+                      + sizeof(IEEEtypes_Header_t)); j++) {
+                ptr += sprintf(ptr, "%02x", *(pRawData + j));
+            }
+            iwe.u.data.length = strlen(buf);
+
+            PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+            PRINTM(INFO, "WPA BUF: %s \n", buf);
+
+            iwe.cmd = IWEVCUSTOM;
+#endif
+            iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+            current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+        }
+        if (Adapter->ScanTable[i].wpsIE.VendHdr.ElementId == WPS_IE) {
+            pRawData = (u8 *) & Adapter->ScanTable[i].wpsIE;
+            memset(&iwe, 0, sizeof(iwe));
+            memset(buf, 0, sizeof(buf));
+            ptr = buf;
+            ptr += sprintf(ptr, "wps_ie=");
+
+            for (j = 0;
+                 j < (Adapter->ScanTable[i].wpsIE.VendHdr.Len
+                      + sizeof(IEEEtypes_Header_t)); j++) {
+                ptr += sprintf(ptr, "%02x", *(pRawData + j));
+            }
+            iwe.u.data.length = strlen(buf);
+
+            PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+            PRINTM(INFO, "WPS BUF: %s \n", buf);
+
+            iwe.cmd = IWEVCUSTOM;
+            iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+            current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+        }
+
+#if WIRELESS_EXT > 14
+
+        if (Adapter->ScanTable[i].extra_ie != 0) {
+            memset(&iwe, 0, sizeof(iwe));
+            memset(buf, 0, sizeof(buf));
+            ptr = buf;
+            ptr += sprintf(ptr, "extra_ie");
+            iwe.u.data.length = strlen(buf);
+
+            PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+            PRINTM(INFO, "BUF: %s \n", buf);
+
+            iwe.cmd = IWEVCUSTOM;
+            iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+            current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+        }
+#endif
+
+        current_val = current_ev + IW_EV_LCP_LEN;
+
+        /*
+         * Check if we added any event
+         */
+        if ((current_val - current_ev) > IW_EV_LCP_LEN)
+            current_ev = current_val;
+    }
+
+    dwrq->length = (current_ev - extra);
+    dwrq->flags = 0;
+
+    LEAVE();
+#endif
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS 
+ *         Descriptor for inclusion in the ioctl response to the user space
+ *         application.
+ *
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param pBSSDesc  Pointer to a BSS entry in the scan table to form
+ *                   scan response from for delivery to the application layer
+ *  @param ppBuffer  Output parameter: Buffer used to output scan return struct
+ *  @param pSpaceLeft Output parameter: Number of bytes available in the 
+ *                    response buffer.
+ *
+ *  @return WLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
+ */
+static int
+wlan_get_scan_table_ret_entry(wlan_private * priv,
+                              BSSDescriptor_t * pBSSDesc,
+                              u8 ** ppBuffer, int *pSpaceLeft)
+{
+    wlan_adapter *Adapter;
+    wlan_ioctl_get_scan_table_entry *pRspEntry;
+    wlan_ioctl_get_scan_table_entry tmpRspEntry;
+    int spaceNeeded;
+    u8 *pCurrent;
+    int variableSize;
+
+    const int fixedSize = (sizeof(tmpRspEntry.fixedFieldLength)
+                           + sizeof(tmpRspEntry.fixedFields)
+                           + sizeof(tmpRspEntry.bssInfoLength));
+
+    ENTER();
+
+    Adapter = priv->adapter;
+    pCurrent = *ppBuffer;
+
+    /* The variable size returned is the stored beacon size */
+    variableSize = pBSSDesc->beaconBufSize;
+
+    /* If we stored a beacon and its size was zero, set the variable
+     *  size return value to the size of the brief scan response 
+     *  wlan_scan_create_brief_table_entry creates.  Also used if 
+     *  we are not configured to store beacons in the first place
+     */
+    if (variableSize == 0) {
+        variableSize = pBSSDesc->Ssid.SsidLength + 2;
+        variableSize += (sizeof(pBSSDesc->BeaconPeriod)
+                         + sizeof(pBSSDesc->TimeStamp)
+                         + sizeof(pBSSDesc->Cap));
+        if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
+            variableSize += (sizeof(IEEEtypes_Header_t)
+                             + pBSSDesc->wmmIE.VendHdr.Len);
+        }
+
+        if (pBSSDesc->wpaIE.VendHdr.ElementId == WPA_IE) {
+            variableSize += (sizeof(IEEEtypes_Header_t)
+                             + pBSSDesc->wpaIE.VendHdr.Len);
+        }
+
+        if (pBSSDesc->rsnIE.IeeeHdr.ElementId == RSN_IE) {
+            variableSize += (sizeof(IEEEtypes_Header_t)
+                             + pBSSDesc->rsnIE.IeeeHdr.Len);
+        }
+    }
+
+    spaceNeeded = fixedSize + variableSize;
+
+    PRINTM(INFO, "GetScanTable: need(%d), left(%d)\n",
+           spaceNeeded, *pSpaceLeft);
+
+    if (spaceNeeded >= *pSpaceLeft) {
+        *pSpaceLeft = 0;
+        LEAVE();
+        return -E2BIG;
+    }
+
+    *pSpaceLeft -= spaceNeeded;
+
+    tmpRspEntry.fixedFieldLength = sizeof(pRspEntry->fixedFields);
+
+    memcpy(tmpRspEntry.fixedFields.bssid,
+           pBSSDesc->MacAddress, sizeof(pRspEntry->fixedFields.bssid));
+
+    tmpRspEntry.fixedFields.rssi = pBSSDesc->Rssi;
+    tmpRspEntry.fixedFields.channel = pBSSDesc->Channel;
+    tmpRspEntry.fixedFields.networkTSF = pBSSDesc->networkTSF;
+    tmpRspEntry.bssInfoLength = variableSize;
+
+    /*
+     *  Copy fixed fields to user space
+     */
+    if (copy_to_user(pCurrent, &tmpRspEntry, fixedSize)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    pCurrent += fixedSize;
+
+    if (pBSSDesc->pBeaconBuf) {
+        /*
+         *  Copy variable length elements to user space
+         */
+        if (copy_to_user(pCurrent, pBSSDesc->pBeaconBuf,
+                         pBSSDesc->beaconBufSize)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        pCurrent += pBSSDesc->beaconBufSize;
+    } else {
+        wlan_scan_create_brief_table_entry(&pCurrent, pBSSDesc);
+    }
+
+    *ppBuffer = pCurrent;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Retrieve the scan response/beacon table
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter;
+    BSSDescriptor_t *pBSSDesc;
+    wlan_ioctl_get_scan_table_info *pRspInfo;
+    int retcode;
+    int retlen;
+    int spaceLeft;
+    u8 *pCurrent;
+    u8 *pBufferEnd;
+    u32 scanStart;
+    u32 numScansDone;
+
+    numScansDone = 0;
+    retcode = WLAN_STATUS_SUCCESS;
+    Adapter = priv->adapter;
+
+    if (copy_from_user(&scanStart,
+                       wrq->u.data.pointer, sizeof(scanStart)) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "GetScanTable: copy from user failed\n");
+        return -EFAULT;
+    }
+
+    pRspInfo = (wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer;
+    pCurrent = pRspInfo->scan_table_entry_buffer;
+    pBufferEnd = wrq->u.data.pointer + wrq->u.data.length - 1;
+    spaceLeft = pBufferEnd - pCurrent;
+
+    PRINTM(INFO, "GetScanTable: scanStart req = %d\n", scanStart);
+    PRINTM(INFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
+
+    if (scanStart == 0) {
+        PRINTM(INFO, "GetScanTable: get current BSS Descriptor\n");
+
+        /* Use to get current association saved descriptor */
+        pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
+
+        retcode = wlan_get_scan_table_ret_entry(priv,
+                                                pBSSDesc,
+                                                &pCurrent, &spaceLeft);
+
+        if (retcode == WLAN_STATUS_SUCCESS) {
+            numScansDone = 1;
+        }
+
+    } else {
+        scanStart--;
+
+        while (spaceLeft
+               && (scanStart + numScansDone < Adapter->NumInScanTable)
+               && (retcode == WLAN_STATUS_SUCCESS)) {
+
+            pBSSDesc = &Adapter->ScanTable[scanStart + numScansDone];
+
+            PRINTM(INFO, "GetScanTable: get current BSS Descriptor [%d]\n",
+                   scanStart + numScansDone);
+
+            retcode = wlan_get_scan_table_ret_entry(priv,
+                                                    pBSSDesc,
+                                                    &pCurrent, &spaceLeft);
+
+            if (retcode == WLAN_STATUS_SUCCESS) {
+                numScansDone++;
+            }
+        }
+    }
+
+    pRspInfo->scanNumber = numScansDone;
+    retlen = pCurrent - (u8 *) wrq->u.data.pointer;
+
+    wrq->u.data.length = retlen;
+
+    /* Return retcode (EFAULT or E2BIG) in the case where no scan results were
+     *   successfully encoded.
+     */
+    return (numScansDone ? WLAN_STATUS_SUCCESS : retcode);
+}
+
+/**
+ *  @brief Update the scan entry TSF timestamps to reflect a new association
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pNewBssDesc  A pointer to the newly associated AP's scan table entry
+ *
+ *  @return             void
+ */
+void
+wlan_scan_update_tsf_timestamps(wlan_private * priv,
+                                BSSDescriptor_t * pNewBssDesc)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int tableIdx;
+    u64 newTsfBase;
+    s64 tsfDelta;
+
+    memcpy(&newTsfBase, pNewBssDesc->TimeStamp, sizeof(newTsfBase));
+
+    tsfDelta = newTsfBase - pNewBssDesc->networkTSF;
+
+    PRINTM(INFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
+           pNewBssDesc->networkTSF, newTsfBase);
+
+    for (tableIdx = 0; tableIdx < Adapter->NumInScanTable; tableIdx++) {
+        Adapter->ScanTable[tableIdx].networkTSF += tsfDelta;
+    }
+}
+
+/**
+ *  @brief Private IOCTL entry to perform an app configured immediate scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure containing the
+ *                      wlan_ioctl_user_scan_cfg requesting this scan
+ *
+ *  @return             0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_user_scan_cfg scanReq;
+    int retcode;
+    union iwreq_data wrqu;
+
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&priv->adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_extscan_ioctl\n");
+        return -EBUSY;
+    }
+#endif
+
+    memset(&scanReq, 0x00, sizeof(scanReq));
+
+    if (copy_from_user(&scanReq,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(scanReq))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "SetUserScan: copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        retcode = wlan_scan_networks(priv, &scanReq);
+
+        memset(&wrqu, 0x00, sizeof(union iwreq_data));
+        wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+    }
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&priv->adapter->ReassocSem);
+#endif
+
+    return retcode;
+}
+
+/**
+ *  @brief Prepare a scan command to be sent to the firmware
+ *
+ *  Use the wlan_scan_cmd_config sent to the command processing module in
+ *   the PrepareAndSendCommand to configure a HostCmd_DS_802_11_SCAN command
+ *   struct to send to firmware.
+ *
+ *  The fixed fields specifying the BSS type and BSSID filters as well as a
+ *   variable number/length of TLVs are sent in the command to firmware.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param cmd        A pointer to HostCmd_DS_COMMAND structure to be sent to
+ *                    firmware with the HostCmd_DS_801_11_SCAN structure
+ *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
+ *                    to set the fields/TLVs for the command sent to firmware
+ *
+ *  @return           WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ *  @sa wlan_scan_create_channel_list
+ */
+int
+wlan_cmd_802_11_scan(wlan_private * priv,
+                     HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_802_11_SCAN *pScan = &cmd->params.scan;
+    wlan_scan_cmd_config *pScanCfg;
+
+    ENTER();
+
+    pScanCfg = (wlan_scan_cmd_config *) pdata_buf;
+
+    /* Set fixed field variables in scan command */
+    pScan->BSSType = pScanCfg->bssType;
+    memcpy(pScan->BSSID, pScanCfg->specificBSSID, sizeof(pScan->BSSID));
+    memcpy(pScan->TlvBuffer, pScanCfg->tlvBuffer, pScanCfg->tlvBufferLen);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+    /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+    cmd->Size = wlan_cpu_to_le16(sizeof(pScan->BSSType)
+                                 + sizeof(pScan->BSSID)
+                                 + pScanCfg->tlvBufferLen + S_DS_GEN);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Store a beacon or probe response for a BSS returned in the scan
+ *  
+ *  Store a new scan response or an update for a previous scan response.  New
+ *    entries need to verify that they do not exceed the total amount of 
+ *    memory allocated for the table.
+
+ *  Replacement entries need to take into consideration the amount of space 
+ *    currently allocated for the beacon/probe response and adjust the entry
+ *    as needed.  
+ *
+ *  A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ *    for an entry in case it is a beacon since a probe response for the
+ *    network will by larger per the standard.  This helps to reduce the 
+ *    amount of memory copying to fit a new probe response into an entry 
+ *    already occupied by a network's previously stored beacon.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param beaconIdx  Index in the scan table to store this entry; may be
+ *                    replacing an older duplicate entry for this BSS
+ *  @param numInTable Number of entries currently in the table
+ *  @param pNewBeacon Pointer to the new beacon/probe response to save
+ *
+ *  @return           void
+ */
+void
+wlan_ret_802_11_scan_store_beacon(wlan_private * priv,
+                                  int beaconIdx,
+                                  int numInTable,
+                                  BSSDescriptor_t * pNewBeacon)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u8 *pBcnStore;
+    int newBcnSize;
+    int oldBcnSize;
+    int bcnSpace;
+    int adjIdx;
+
+    if (Adapter->ScanTable[beaconIdx].pBeaconBuf != NULL) {
+
+        newBcnSize = pNewBeacon->beaconBufSize;
+        oldBcnSize = Adapter->ScanTable[beaconIdx].beaconBufSize;
+        bcnSpace = Adapter->ScanTable[beaconIdx].beaconBufSizeMax;
+        pBcnStore = Adapter->ScanTable[beaconIdx].pBeaconBuf;
+
+        /* Set the max to be the same as current entry unless changed below */
+        pNewBeacon->beaconBufSizeMax = bcnSpace;
+
+        if (newBcnSize == oldBcnSize) {
+            /*
+             * Beacon is the same size as the previous entry.
+             *   Replace the previous contents with the scan result
+             */
+            memcpy(pBcnStore,
+                   pNewBeacon->pBeaconBuf, pNewBeacon->beaconBufSize);
+
+        } else if (newBcnSize <= bcnSpace) {
+            /*
+             * New beacon size will fit in the amount of space
+             *   we have previously allocated for it
+             */
+
+            /* Copy the new beacon buffer entry over the old one */
+            memcpy(pBcnStore, pNewBeacon->pBeaconBuf, newBcnSize);
+
+            /* If the old beacon size was less than the maximum
+             *  we had alloted for the entry, and the new entry
+             *  is even smaller, reset the max size to the old beacon
+             *  entry and compress the storage space (leaving a new
+             *  pad space of (oldBcnSize - newBcnSize).
+             */
+            if (oldBcnSize < bcnSpace && newBcnSize != bcnSpace) {
+                /*
+                 * Old Beacon size is smaller than the alloted storage size.
+                 *   Shrink the alloted storage space.
+                 */
+                PRINTM(INFO, "AppControl: Smaller Duplicate Beacon (%d), "
+                       "old = %d, new = %d, space = %d, left = %d\n",
+                       beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
+                       (sizeof(Adapter->beaconBuffer) -
+                        (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+                /* memmove (since the memory overlaps) the data
+                 *  after the beacon we just stored to the end of
+                 *  the current beacon.  This cleans up any unused
+                 *  space the old larger beacon was using in the buffer
+                 */
+                memmove(pBcnStore + oldBcnSize,
+                        pBcnStore + bcnSpace,
+                        Adapter->pBeaconBufEnd - (pBcnStore + bcnSpace));
+
+                /* Decrement the end pointer by the difference between
+                 *  the old larger size and the new smaller size since
+                 *  we are using less space due to the new beacon being
+                 *  smaller
+                 */
+                Adapter->pBeaconBufEnd -= (bcnSpace - oldBcnSize);
+
+                /* Set the maximum storage size to the old beacon size */
+                pNewBeacon->beaconBufSizeMax = oldBcnSize;
+
+                /* Adjust beacon buffer pointers that are past the current */
+                for (adjIdx = 0; adjIdx < numInTable; adjIdx++) {
+                    if (Adapter->ScanTable[adjIdx].pBeaconBuf > pBcnStore) {
+                        Adapter->ScanTable[adjIdx].pBeaconBuf
+                            -= (bcnSpace - oldBcnSize);
+                    }
+                }
+            }
+        } else if (Adapter->pBeaconBufEnd + (newBcnSize - bcnSpace)
+                   < (Adapter->beaconBuffer + sizeof(Adapter->beaconBuffer))) {
+            /*
+             * Beacon is larger than space previously allocated (bcnSpace)
+             *   and there is enough space left in the beaconBuffer to store
+             *   the additional data
+             */
+            PRINTM(INFO, "AppControl: Larger Duplicate Beacon (%d), "
+                   "old = %d, new = %d, space = %d, left = %d\n",
+                   beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+            /* memmove (since the memory overlaps) the data
+             *  after the beacon we just stored to the end of
+             *  the current beacon.  This moves the data for
+             *  the beacons after this further in memory to
+             *  make space for the new larger beacon we are
+             *  about to copy in.
+             */
+            memmove(pBcnStore + newBcnSize,
+                    pBcnStore + bcnSpace,
+                    Adapter->pBeaconBufEnd - (pBcnStore + bcnSpace));
+
+            /* Copy the new beacon buffer entry over the old one */
+            memcpy(pBcnStore, pNewBeacon->pBeaconBuf, newBcnSize);
+
+            /* Move the beacon end pointer by the amount of new
+             *  beacon data we are adding
+             */
+            Adapter->pBeaconBufEnd += (newBcnSize - bcnSpace);
+
+            /* This entry is bigger than the alloted max space
+             *  previously reserved.  Increase the max space to
+             *  be equal to the new beacon size
+             */
+            pNewBeacon->beaconBufSizeMax = newBcnSize;
+
+            /* Adjust beacon buffer pointers that are past the current */
+            for (adjIdx = 0; adjIdx < numInTable; adjIdx++) {
+                if (Adapter->ScanTable[adjIdx].pBeaconBuf > pBcnStore) {
+                    Adapter->ScanTable[adjIdx].pBeaconBuf
+                        += (newBcnSize - bcnSpace);
+                }
+            }
+        } else {
+            /*
+             * Beacon is larger than the previously allocated space, but
+             *   there is not enough free space to store the additional data
+             */
+            PRINTM(INFO,
+                   "AppControl: Failed: Larger Duplicate Beacon (%d),"
+                   " old = %d, new = %d, space = %d, left = %d\n",
+                   beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+            /* Storage failure, keep old beacon intact */
+            pNewBeacon->beaconBufSize = oldBcnSize;
+        }
+
+        /* Point the new entry to its permanent storage space */
+        pNewBeacon->pBeaconBuf = pBcnStore;
+
+    } else {
+        /* No existing beacon data exists for this entry, check to see
+         *   if we can fit it in the remaining space
+         */
+        if (Adapter->pBeaconBufEnd + pNewBeacon->beaconBufSize +
+            SCAN_BEACON_ENTRY_PAD < (Adapter->beaconBuffer +
+                                     sizeof(Adapter->beaconBuffer))) {
+
+            /* Copy the beacon buffer data from the local entry to the
+             *   adapter dev struct buffer space used to store the raw
+             *   beacon data for each entry in the scan table
+             */
+            memcpy(Adapter->pBeaconBufEnd, pNewBeacon->pBeaconBuf,
+                   pNewBeacon->beaconBufSize);
+
+            /* Update the beacon ptr to point to the table save area */
+            pNewBeacon->pBeaconBuf = Adapter->pBeaconBufEnd;
+            pNewBeacon->beaconBufSizeMax = (pNewBeacon->beaconBufSize
+                                            + SCAN_BEACON_ENTRY_PAD);
+
+            /* Increment the end pointer by the size reserved */
+            Adapter->pBeaconBufEnd += pNewBeacon->beaconBufSizeMax;
+
+            PRINTM(INFO, "AppControl: Beacon[%02d] sz=%03d,"
+                   " used = %04d, left = %04d\n",
+                   beaconIdx,
+                   pNewBeacon->beaconBufSize,
+                   (Adapter->pBeaconBufEnd - Adapter->beaconBuffer),
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+        } else {
+            /*
+             * No space for new beacon
+             */
+            PRINTM(INFO, "AppControl: No space beacon (%d): "
+                   "%02x:%02x:%02x:%02x:%02x:%02x; sz=%03d, left=%03d\n",
+                   beaconIdx,
+                   pNewBeacon->MacAddress[0], pNewBeacon->MacAddress[1],
+                   pNewBeacon->MacAddress[2], pNewBeacon->MacAddress[3],
+                   pNewBeacon->MacAddress[4], pNewBeacon->MacAddress[5],
+                   pNewBeacon->beaconBufSize,
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+            /* Storage failure; clear storage records for this bcn */
+            pNewBeacon->pBeaconBuf = NULL;
+            pNewBeacon->beaconBufSize = 0;
+            pNewBeacon->beaconBufSizeMax = 0;
+        }
+    }
+}
+
+/**
+ *  @brief This function handles the command response of scan
+ *
+ *   The response buffer for the scan command has the following
+ *      memory layout:
+ *
+ *     .-----------------------------------------------------------.
+ *     |  Header (4 * sizeof(u16)):  Standard command response hdr |
+ *     .-----------------------------------------------------------.
+ *     |  BufSize (u16) : sizeof the BSS Description data          |
+ *     .-----------------------------------------------------------.
+ *     |  NumOfSet (u8) : Number of BSS Descs returned             |
+ *     .-----------------------------------------------------------.
+ *     |  BSSDescription data (variable, size given in BufSize)    |
+ *     .-----------------------------------------------------------.
+ *     |  TLV data (variable, size calculated using Header->Size,  |
+ *     |            BufSize and sizeof the fixed fields above)     |
+ *     .-----------------------------------------------------------.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_scan(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_SCAN_RSP *pScan;
+    BSSDescriptor_t newBssEntry;
+    MrvlIEtypes_Data_t *pTlv;
+    MrvlIEtypes_TsfTimestamp_t *pTsfTlv;
+    u8 *pBssInfo;
+    u16 scanRespSize;
+    int bytesLeft;
+    int numInTable;
+    int bssIdx;
+    int idx;
+    int tlvBufSize;
+    u64 tsfVal;
+    BOOLEAN bgScanResp;
+
+    ENTER();
+
+    bgScanResp = (resp->Command == HostCmd_RET_802_11_BG_SCAN_QUERY);
+    if (bgScanResp) {
+        pScan = &resp->params.bgscanqueryresp.scanresp;
+    } else {
+        pScan = &resp->params.scanresp;
+    }
+
+    if (pScan->NumberOfSets > MRVDRV_MAX_BSSID_LIST) {
+        PRINTM(INFO, "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+               pScan->NumberOfSets);
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    bytesLeft = wlan_le16_to_cpu(pScan->BSSDescriptSize);
+    PRINTM(INFO, "SCAN_RESP: BSSDescriptSize %d\n", bytesLeft);
+
+    scanRespSize = resp->Size;
+
+    PRINTM(CMND, "SCAN_RESP: returned %d APs before parsing\n",
+           pScan->NumberOfSets);
+
+    numInTable = Adapter->NumInScanTable;
+    pBssInfo = pScan->BssDescAndTlvBuffer;
+
+    /* The size of the TLV buffer is equal to the entire command response
+     *   size (scanRespSize) minus the fixed fields (sizeof()'s), the
+     *   BSS Descriptions (BSSDescriptSize as bytesLef) and the command
+     *   response header (S_DS_GEN)
+     */
+    tlvBufSize = scanRespSize - (bytesLeft + sizeof(pScan->BSSDescriptSize)
+                                 + sizeof(pScan->NumberOfSets)
+                                 + S_DS_GEN);
+
+    pTlv = (MrvlIEtypes_Data_t *) (pScan->BssDescAndTlvBuffer + bytesLeft);
+
+    /* Search the TLV buffer space in the scan response for any valid TLVs */
+    wlan_ret_802_11_scan_get_tlv_ptrs(pTlv, tlvBufSize, &pTsfTlv);
+
+    /*
+     *  Process each scan response returned (pScan->NumberOfSets).  Save
+     *    the information in the newBssEntry and then insert into the
+     *    driver scan table either as an update to an existing entry
+     *    or as an addition at the end of the table
+     */
+    for (idx = 0; idx < pScan->NumberOfSets && bytesLeft; idx++) {
+        /* Zero out the newBssEntry we are about to store info in */
+        memset(&newBssEntry, 0x00, sizeof(newBssEntry));
+
+        /* Process the data fields and IEs returned for this BSS */
+        if ((InterpretBSSDescriptionWithIE(&newBssEntry,
+                                           &pBssInfo,
+                                           &bytesLeft) == WLAN_STATUS_SUCCESS)
+            && CHECK_SSID_IS_VALID(&newBssEntry.Ssid)) {
+
+            PRINTM(INFO, "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   newBssEntry.MacAddress[0], newBssEntry.MacAddress[1],
+                   newBssEntry.MacAddress[2], newBssEntry.MacAddress[3],
+                   newBssEntry.MacAddress[4], newBssEntry.MacAddress[5]);
+
+            /*
+             * Search the scan table for the same bssid
+             */
+            for (bssIdx = 0; bssIdx < numInTable; bssIdx++) {
+                if (memcmp(newBssEntry.MacAddress,
+                           Adapter->ScanTable[bssIdx].MacAddress,
+                           sizeof(newBssEntry.MacAddress)) == 0) {
+                    /*
+                     * If the SSID matches as well, it is a duplicate of
+                     *   this entry.  Keep the bssIdx set to this
+                     *   entry so we replace the old contents in the table
+                     */
+                    if ((newBssEntry.Ssid.SsidLength ==
+                         Adapter->ScanTable[bssIdx].Ssid.SsidLength)
+                        && (memcmp(newBssEntry.Ssid.Ssid,
+                                   Adapter->ScanTable[bssIdx].Ssid.Ssid,
+                                   newBssEntry.Ssid.SsidLength) == 0)) {
+                        PRINTM(INFO, "SCAN_RESP: Duplicate of index: %d\n",
+                               bssIdx);
+                        break;
+                    }
+                }
+            }
+            /*
+             * If the bssIdx is equal to the number of entries in the table,
+             *   the new entry was not a duplicate; append it to the scan
+             *   table
+             */
+            if (bssIdx == numInTable) {
+                /* Range check the bssIdx, keep it limited to the last entry */
+                if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
+                    bssIdx--;
+                } else {
+                    numInTable++;
+                }
+            }
+
+            /*
+             * Save the beacon/probe response returned for later application
+             *   retrieval.  Duplicate beacon/probe responses are updated if
+             *   possible
+             */
+            wlan_ret_802_11_scan_store_beacon(priv,
+                                              bssIdx,
+                                              numInTable, &newBssEntry);
+            /*
+             * If the TSF TLV was appended to the scan results, save
+             *   this entry's TSF value in the networkTSF field.  The
+             *   networkTSF is the firmware's TSF value at the time the
+             *   beacon or probe response was received.
+             */
+            if (pTsfTlv) {
+                memcpy(&tsfVal, &pTsfTlv->tsfTable[idx], sizeof(tsfVal));
+                tsfVal = wlan_le64_to_cpu(tsfVal);
+
+                memcpy(&newBssEntry.networkTSF,
+                       &tsfVal, sizeof(newBssEntry.networkTSF));
+            }
+
+            /* Copy the locally created newBssEntry to the scan table */
+            memcpy(&Adapter->ScanTable[bssIdx],
+                   &newBssEntry, sizeof(Adapter->ScanTable[bssIdx]));
+
+        } else {
+
+            /* Error parsing/interpreting the scan response, skipped */
+            PRINTM(INFO, "SCAN_RESP: "
+                   "InterpretBSSDescriptionWithIE returned ERROR\n");
+        }
+    }
+
+    PRINTM(CMND, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+           pScan->NumberOfSets, numInTable - Adapter->NumInScanTable,
+           numInTable);
+
+    /* Update the total number of BSSIDs in the scan table */
+    Adapter->NumInScanTable = numInTable;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief scan network with specific ssid
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_extscan_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_SSID Ext_Scan_SSID;
+    wlan_ioctl_user_scan_cfg scanCfg;
+    union iwreq_data wrqu;
+
+    ENTER();
+
+    if (copy_from_user(&Ext_Scan_SSID, req->ifr_data, sizeof(Ext_Scan_SSID))) {
+        PRINTM(INFO, "copy of SSID for ext scan from user failed \n");
+        LEAVE();
+        return -EFAULT;
+    }
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_extscan_ioctl\n");
+        return -EBUSY;
+    }
+#endif
+
+    memset(&scanCfg, 0x00, sizeof(scanCfg));
+
+    memcpy(scanCfg.ssidList[0].ssid, Ext_Scan_SSID.Ssid,
+           Ext_Scan_SSID.SsidLength);
+
+    wlan_scan_networks(priv, &scanCfg);
+
+    memset(&wrqu, 0, sizeof(union iwreq_data));
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+
+    if (Adapter->SurpriseRemoved)
+        return WLAN_STATUS_FAILURE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function sends BG_SCAN query command to firmware.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sendBgScanQueryCmd(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* Clear the previous scan result */
+    memset(Adapter->ScanTable, 0x00,
+           sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+    Adapter->NumInScanTable = 0;
+    Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
+
+    return PrepareAndSendCommand(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
+                                 0, 0, 0, NULL);
+}
+
+/**
+ *  @brief Enable/Disable BG Scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param enable       TRUE-enable, FALSE-disable
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_bg_scan_enable(wlan_private * priv, BOOLEAN enable)
+{
+    int ret;
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, &enable);
+    return ret;
+}
+
+/**
+ *  @brief config BGSCAN parameter
+
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_do_bg_scan_config_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 action;
+    u8 *buf = NULL;
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *tmp;
+
+    ENTER();
+
+    action = *((u8 *) req->ifr_data + SKIP_CMDNUM + SKIP_SIZE);
+    PRINTM(INFO, "Action = %d\n", action);
+
+    switch (action) {
+    case HostCmd_ACT_GEN_GET:
+        buf = kmalloc(Adapter->bgScanConfigSize + SKIP_TYPE_SIZE, GFP_KERNEL);
+        if (!buf) {
+            PRINTM(MSG, "kmalloc no memory !!\n");
+            return -ENOMEM;
+        }
+        memcpy(buf, &Adapter->bgScanConfigSize, SKIP_SIZE);
+        memcpy(buf + SKIP_TYPE_SIZE, Adapter->bgScanConfig,
+               Adapter->bgScanConfigSize);
+
+        if (copy_to_user(req->ifr_data, buf,
+                         Adapter->bgScanConfigSize + SKIP_TYPE_SIZE)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            kfree(buf);
+            return -EFAULT;
+        }
+
+        kfree(buf);
+
+        break;
+
+    case HostCmd_ACT_GEN_SET:
+        Adapter->bgScanConfigSize = *(u16 *) (req->ifr_data + SKIP_CMDNUM);
+        PRINTM(INFO, "bgscanConfigSize = %d\n", Adapter->bgScanConfigSize);
+
+        if (!(tmp = kmalloc(Adapter->bgScanConfigSize, GFP_KERNEL))) {
+            PRINTM(MSG, "kmalloc no memory !!\n");
+            Adapter->bgScanConfigSize = 0;
+            return -ENOMEM;
+        }
+
+        HEXDUMP("treq", req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
+                Adapter->bgScanConfigSize);
+
+        if (copy_from_user(tmp, req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
+                           Adapter->bgScanConfigSize)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            kfree(tmp);
+            return -EFAULT;
+        }
+
+        if (Adapter->bgScanConfig) {
+            tmp->Enable = Adapter->bgScanConfig->Enable;
+            buf = (u8 *) Adapter->bgScanConfig;
+        }
+        Adapter->bgScanConfig = tmp;
+        if (buf)
+            kfree(buf);
+
+        break;
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief This function prepares command of bg_scan_config.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf    A pointer to data buffer
+ *
+ *  @return             WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_bg_scan_config(wlan_private * priv,
+                               HostCmd_DS_COMMAND * cmd,
+                               int cmd_action, void *pdata_buf)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *bgcfg = &cmd->params.bgscancfg;
+    BOOLEAN enable = *((BOOLEAN *) pdata_buf);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+    cmd->Size =
+        wlan_cpu_to_le16((priv->adapter->bgScanConfigSize) + S_DS_GEN);
+
+    Adapter->bgScanConfig->Enable = enable;
+
+    memcpy(bgcfg, Adapter->bgScanConfig, Adapter->bgScanConfigSize);
+
+    bgcfg->Action = wlan_cpu_to_le16(bgcfg->Action);
+    bgcfg->ScanInterval = wlan_cpu_to_le32(bgcfg->ScanInterval);
+    bgcfg->StoreCondition = wlan_cpu_to_le32(bgcfg->StoreCondition);
+    bgcfg->ReportConditions = wlan_cpu_to_le32(bgcfg->ReportConditions);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function prepares command of bg_scan_query.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_bg_scan_query(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    HostCmd_DS_802_11_BG_SCAN_QUERY *bgquery = &cmd->params.bgscanquery;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) + S_DS_GEN);
+
+    bgquery->Flush = 1;
+
+    return WLAN_STATUS_SUCCESS;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_scan.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_scan.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_scan.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_scan.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,296 @@
+/** @file wlan_scan.h
+ *
+ *  @brief Interface for the wlan network scan routines
+ *
+ *  Driver interface functions and type declarations for the scan module
+ *    implemented in wlan_scan.c.
+ *
+ *  (c) Copyright © 2003-2006, Marvell International Ltd.  
+ *   
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    01/11/06: Initial revision. New scan code, relocate related functions
+
+************************************************************/
+
+#ifndef _WLAN_SCAN_H
+#define _WLAN_SCAN_H
+
+//! Infrastructure BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_BSS         1
+
+//! Adhoc BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_IBSS        2
+
+//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+#define WLAN_SCAN_BSS_TYPE_ANY         3
+
+/** @brief Maximum buffer space for beacons retrieved from scan responses
+ *    4000 has successfully stored up to 40 beacons
+ *    6000 has successfully stored the max scan results (max 64)
+ */
+#define MAX_SCAN_BEACON_BUFFER         6000
+
+/**
+ * @brief Buffer pad space for newly allocated beacons/probe responses
+ *
+ * Beacons are typically 6 bytes longer than an equivalent probe response.
+ *  For each scan response stored, allocate an extra byte pad at the end to
+ *  allow easy expansion to store a beacon in the same memory a probe reponse
+ *  previously contained
+ */
+#define SCAN_BEACON_ENTRY_PAD          6
+
+//! Scan time specified in the channel TLV for each channel for passive scans
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME  100
+
+//! Scan time specified in the channel TLV for each channel for active scans
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
+
+//! Scan time specified in the channel TLV for each channel for specific scans
+#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 100
+
+//! Max passive scan time for each channel in milliseconds
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME   2000
+
+//! Max active scan time for each channel in milliseconds 
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME    500
+
+/**
+ * Max total scan time in milliseconds
+ * The total scan time should be less than scan command timeout value (10s)
+ */
+#define MRVDRV_MAX_TOTAL_SCAN_TIME     (MRVDRV_TIMER_10S - MRVDRV_TIMER_1S)
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+ *   scan command prepared by wlan_cmd_802_11_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+typedef struct
+{
+    /**
+     *  @brief BSS Type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  Valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+    u8 bssType;
+
+    /**
+     *  @brief Specific BSSID used to filter scan results in the firmware
+     */
+    u8 specificBSSID[MRVDRV_ETH_ADDR_LEN];
+
+    /**
+     *  @brief Length of TLVs sent in command starting at tlvBuffer
+     */
+    int tlvBufferLen;
+
+    /**
+     *  @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+     *
+     *  @sa TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
+     *  @sa TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
+     */
+    u8 tlvBuffer[1];            //!< SSID TLV(s) and ChanList TLVs are stored here
+} wlan_scan_cmd_config;
+
+/**
+ *  @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ *  Fixed field information returned for the scan response in the IOCTL
+ *    response.
+ */
+typedef struct
+{
+    u8 bssid[6];                //!< BSSID of this network
+    u8 channel;                 //!< Channel this beacon/probe response was detected
+    u8 rssi;                    //!< RSSI for the received packet
+    u64 networkTSF;             //!< TSF value from the firmware at packet reception
+} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_fixed;
+
+/**
+ *  @brief Structure passed in the wlan_ioctl_get_scan_table_info for each
+ *         BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ *
+ *  @sa wlan_get_scan_table_ioctl
+ */
+typedef struct
+{
+
+    /**
+     *  @brief Fixed field length included in the response.
+     *
+     *  Length value is included so future fixed fields can be added to the
+     *   response without breaking backwards compatibility.  Use the length
+     *   to find the offset for the bssInfoLength field, not a sizeof() calc.
+     */
+    u32 fixedFieldLength;
+
+    /**
+     *  @brief Always present, fixed length data fields for the BSS
+     */
+    wlan_ioctl_get_scan_table_fixed fixedFields;
+
+    /**
+     *  @brief Length of the BSS Information (probe resp or beacon) that
+     *         follows starting at bssInfoBuffer
+     */
+    u32 bssInfoLength;
+
+    /**
+     *  @brief Probe response or beacon scanned for the BSS.
+     *
+     *  Field layout:
+     *   - TSF              8 octets
+     *   - Beacon Interval  2 octets
+     *   - Capability Info  2 octets
+     *
+     *   - IEEE Infomation Elements; variable number & length per 802.11 spec
+     */
+    u8 bssInfoBuffer[1];
+} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_entry;
+
+/**
+ *  @brief WLAN_GET_SCAN_RESP private IOCTL struct to retrieve the scan table
+ *
+ *  @sa wlan_get_scan_table_ioctl
+ */
+typedef struct
+{
+
+    /**
+     *  - Zero based scan entry to start retrieval in command request
+     *  - Number of scans entires returned in command response
+     */
+    u32 scanNumber;
+
+     /**
+      * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+      *   Each struct is padded to the nearest 32 bit boundary.
+      */
+    u8 scan_table_entry_buffer[1];
+
+} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_info;
+
+/**
+ *  @brief Structure used to store information for each beacon/probe response
+ */
+typedef struct
+{
+    WLAN_802_11_MAC_ADDRESS MacAddress;
+
+    WLAN_802_11_SSID Ssid;
+
+    /* WEP encryption requirement */
+    u32 Privacy;
+
+    /* receive signal strength in dBm */
+    WLAN_802_11_RSSI Rssi;
+
+    u32 Channel;
+
+    u16 BeaconPeriod;
+
+    u32 ATIMWindow;
+    u8 ERPFlags;
+
+    WLAN_802_11_NETWORK_TYPE NetworkTypeInUse;
+    WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+    WLAN_802_11_RATES SupportedRates;
+    IEEEtypes_WmmParameter_t wmmIE;
+
+    int extra_ie;
+
+    u8 TimeStamp[8];            //!< TSF value included in the beacon/probe response
+
+    IEEEtypes_PhyParamSet_t PhyParamSet;
+    IEEEtypes_SsParamSet_t SsParamSet;
+    IEEEtypes_CapInfo_t Cap;
+
+    u8 DataRates[WLAN_SUPPORTED_RATES];
+
+    u64 networkTSF;             //!< TSF timestamp from the current firmware TSF
+
+    IEEEtypes_CountryInfoFullSet_t CountryInfo;
+
+    IEEEtypes_VendorSpecific_t wpaIE;
+    IEEEtypes_Generic_t rsnIE;
+
+    IEEEtypes_VendorSpecific_t wpsIE;
+
+    u8 *pBeaconBuf;             //!< Pointer to the returned scan response
+    uint beaconBufSize;         //!< Length of the stored scan response
+    uint beaconBufSizeMax;      //!< Max allocated size for updated scan response
+
+} BSSDescriptor_t;
+
+extern int SSIDcmp(WLAN_802_11_SSID * ssid1, WLAN_802_11_SSID * ssid2);
+extern int FindSSIDInList(wlan_adapter * Adapter, WLAN_802_11_SSID * ssid,
+                          u8 * bssid, int mode);
+extern int FindBestSSIDInList(wlan_adapter * Adapter);
+extern int FindBSSIDInList(wlan_adapter * Adapter, u8 * bssid, int mode);
+
+extern int FindBestNetworkSsid(wlan_private * priv, WLAN_802_11_SSID * pSSID);
+
+extern int SendSpecificSSIDScan(wlan_private * priv,
+                                WLAN_802_11_SSID * pRequestedSSID);
+extern int SendSpecificBSSIDScan(wlan_private * priv, u8 * bssid);
+
+extern int wlan_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+extern int wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
+
+extern int wlan_cmd_802_11_scan(wlan_private * priv,
+                                HostCmd_DS_COMMAND * cmd, void *pdata_buf);
+
+extern void wlan_scan_update_tsf_timestamps(wlan_private * priv,
+                                            BSSDescriptor_t * pNewBssDesc);
+
+extern int wlan_ret_802_11_scan(wlan_private * priv,
+                                HostCmd_DS_COMMAND * resp);
+
+extern int wlan_extscan_ioctl(wlan_private * priv, struct ifreq *req);
+
+extern int sendBgScanQueryCmd(wlan_private * priv);
+extern int wlan_bg_scan_enable(wlan_private * priv, BOOLEAN enable);
+extern int wlan_do_bg_scan_config_ioctl(wlan_private * priv,
+                                        struct ifreq *req);
+extern int wlan_cmd_802_11_bg_scan_config(wlan_private * priv,
+                                          HostCmd_DS_COMMAND * cmd,
+                                          int cmd_action, void *pdata_buf);
+extern int wlan_cmd_802_11_bg_scan_query(wlan_private * priv,
+                                         HostCmd_DS_COMMAND * cmd);
+
+#ifdef __KERNEL__
+extern int wlan_get_scan(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_point *dwrq, char *extra);
+extern int wlan_set_scan(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra);
+#endif
+
+#endif /* _WLAN_SCAN_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_tx.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_tx.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_tx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_tx.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,300 @@
+/** @file wlan_tx.c
+  * @brief This file contains the handling of TX in wlan
+  * driver.
+  *    
+  *  (c) Copyright © 2003-2006, Marvell International Ltd.  
+  *   
+  *  This software file (the "File") is distributed by Marvell International 
+  *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  *  (the "License").  You may use, redistribute and/or modify this File in 
+  *  accordance with the terms and conditions of the License, a copy of which 
+  *  is available along with the File in the gpl.txt file or by writing to 
+  *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  *  this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	09/28/05: Add Doxygen format comments
+	12/13/05: Add Proprietary periodic sleep support
+	01/05/06: Add kernel 2.6.x support	
+	04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+********************************************************/
+
+#include	"include.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function processes a single packet and sends
+ *  to IF layer
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param skb     A pointer to skb which includes TX packet
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    TxPD LocalTxPD;
+    TxPD *pLocalTxPD = &LocalTxPD;
+    u8 *ptr = Adapter->TmpTxBuf;
+
+    ENTER();
+
+    if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+        PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n",
+               skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    memset(pLocalTxPD, 0, sizeof(TxPD));
+
+    pLocalTxPD->TxPacketLength = skb->len;
+
+    if (Adapter->wmm.enabled) {
+        /* 
+         * original skb->priority has been overwritten 
+         * by wmm_map_and_add_skb()
+         */
+        pLocalTxPD->Priority = (u8) skb->priority;
+
+        pLocalTxPD->PktDelay_2ms = wmm_compute_driver_packet_delay(skb);
+    }
+
+    if (pLocalTxPD->Priority < NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
+        /* 
+         * Set the priority specific TxControl field, setting of 0 will
+         *   cause the default value to be used later in this function
+         */
+        pLocalTxPD->TxControl
+            = Adapter->wmm.userPriPktTxCtrl[pLocalTxPD->Priority];
+    }
+
+    if (Adapter->PSState != PS_STATE_FULL_POWER) {
+        if (TRUE == CheckLastPacketIndication(priv)) {
+            Adapter->TxLockFlag = TRUE;
+            pLocalTxPD->Flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+        }
+    }
+
+    /* offset of actual data */
+    pLocalTxPD->TxPacketLocation = sizeof(TxPD);
+
+    if (pLocalTxPD->TxControl == 0) {
+        /* TxCtrl set by user or default */
+        pLocalTxPD->TxControl = Adapter->PktTxCtrl;
+    }
+
+    endian_convert_TxPD(pLocalTxPD);
+
+    memcpy((u8 *) pLocalTxPD->TxDestAddr, skb->data, MRVDRV_ETH_ADDR_LEN);
+
+    ptr += SDIO_HEADER_LEN;
+    memcpy(ptr, pLocalTxPD, sizeof(TxPD));
+
+    ptr += sizeof(TxPD);
+
+    memcpy(ptr, skb->data, skb->len);
+
+    ret = sbi_host_to_card(priv, MVMS_DAT, Adapter->TmpTxBuf,
+                           skb->len + sizeof(TxPD));
+    if (ret) {
+        PRINTM(ERROR,
+               "SendSinglePacket Error: sbi_host_to_card failed: 0x%X\n",
+               ret);
+        Adapter->dbg.num_tx_host_to_card_failure++;
+        goto done;
+    }
+
+    PRINTM(DATA, "Data => FW\n");
+    DBG_HEXDUMP(DAT_D, "Tx", ptr - sizeof(TxPD),
+                MIN(skb->len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+
+    wmm_process_fw_iface_tx_xfer_start(priv);
+
+  done:
+    if (!ret) {
+        priv->stats.tx_packets++;
+        priv->stats.tx_bytes += skb->len;
+    } else {
+        priv->stats.tx_dropped++;
+        priv->stats.tx_errors++;
+    }
+
+    /* need to be freed in all cases */
+    os_free_tx_packet(priv);
+
+    LEAVE();
+    return ret;
+}
+
+/********************************************************
+		Global functions
+********************************************************/
+
+/** 
+ *  @brief This function checks the conditions and sends packet to IF
+ *  layer if everything is ok.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void
+wlan_process_tx(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    if (priv->wlan_dev.dnld_sent) {
+        PRINTM(MSG, "TX Error: dnld_sent = %d, not sending\n",
+               priv->wlan_dev.dnld_sent);
+        goto done;
+    }
+
+    SendSinglePacket(priv, Adapter->CurrentTxSkb);
+    OS_INT_DISABLE;
+    priv->adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
+    OS_INT_RESTORE;
+
+  done:
+    LEAVE();
+}
+
+/** 
+ *  @brief This function queues the packet received from
+ *  kernel/upper layer and wake up the main thread to handle it.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+  * @param skb     A pointer to skb which includes TX packet
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_tx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+    ulong flags;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    HEXDUMP("TX Data", skb->data, MIN(skb->len, 100));
+
+    spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
+
+    wmm_map_and_add_skb(priv, skb);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief This function tells firmware to send a NULL data packet.
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *  @param flags    Trasnit Pkt Flags
+ *  @return 	    n/a
+ */
+int
+SendNullPacket(wlan_private * priv, u8 flags)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    TxPD txpd = { 0 };
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 *ptr = Adapter->TmpTxBuf;
+
+    ENTER();
+
+    if (Adapter->SurpriseRemoved == TRUE) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    memset(&txpd, 0, sizeof(TxPD));
+
+    txpd.TxControl = Adapter->PktTxCtrl;
+    txpd.Flags = flags;
+    txpd.Priority = WMM_HIGHEST_PRIORITY;
+    txpd.TxPacketLocation = sizeof(TxPD);
+
+    endian_convert_TxPD(&txpd);
+
+    ptr += SDIO_HEADER_LEN;
+    memcpy(ptr, &txpd, sizeof(TxPD));
+
+    ret = sbi_host_to_card(priv, MVMS_DAT, Adapter->TmpTxBuf, sizeof(TxPD));
+
+    if (ret != 0) {
+        PRINTM(ERROR, "TX Error: SendNullPacket failed!\n");
+        Adapter->dbg.num_tx_host_to_card_failure++;
+        goto done;
+    }
+    PRINTM(DATA, "Null data => FW\n");
+    DBG_HEXDUMP(DAT_D, "Tx", ptr, sizeof(TxPD));
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function check if we need send last packet indication.
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *
+ *  @return 	   TRUE or FALSE
+ */
+BOOLEAN
+CheckLastPacketIndication(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    BOOLEAN ret = FALSE;
+    BOOLEAN prop_ps = TRUE;
+
+    ENTER();
+
+    if (Adapter->sleep_period.period == 0 || Adapter->gen_null_pkg == FALSE     /* for UPSD certification tests */
+        ) {
+        LEAVE();
+        return ret;
+    }
+
+    if (wmm_lists_empty(priv)) {
+        if (((Adapter->CurBssParams.wmm_uapsd_enabled == TRUE)
+             && (Adapter->wmm.qosinfo != 0)) || prop_ps) {
+            ret = TRUE;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_types.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_types.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_types.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_types.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1055 @@
+/** @file wlan_types.h
+ *  @brief This header file contains definition for global types
+ *
+ *  (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change log:
+	10/11/05: add Doxygen format comments 
+	01/11/06: Add IEEE Association response type. Add TSF TLV information.
+	01/31/06: Add support to selectively enabe the FW Scan channel filter
+	04/10/06: Add power_adapt_cfg_ext command
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	05/03/06: Add auto_tx hostcmd
+	08/28/06: Add LED_CTRL hostcmd
+************************************************************/
+
+#ifndef _WLAN_TYPES_
+#define _WLAN_TYPES_
+
+#ifndef __KERNEL__
+typedef char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed long s32;
+typedef unsigned long u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
+/* Dma addresses are 32-bits wide.  */
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+#endif
+
+typedef long LONG;
+typedef unsigned long long ULONGLONG;
+typedef u32 WLAN_OID;
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE	32
+#define MRVDRV_MAX_CHANNEL_SIZE		14
+#define MRVDRV_ETH_ADDR_LEN             6
+#define MRVDRV_MAX_SSID_LENGTH			32
+#define MRVDRV_MAX_BSS_DESCRIPTS		16
+/** WEP list macros & data structures */
+#define MRVL_KEY_BUFFER_SIZE_IN_BYTE  16
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH     32
+
+#define HOSTCMD_SUPPORTED_RATES G_SUPPORTED_RATES
+
+#define	BAND_B			(0x01)
+#define	BAND_G			(0x02)
+#define ALL_802_11_BANDS	(BAND_B | BAND_G)
+
+#define B_SUPPORTED_RATES		8
+#define G_SUPPORTED_RATES		14
+
+#define	WLAN_SUPPORTED_RATES		14
+#define WLAN_MAX_SSID_LENGTH		32
+
+#define	MAX_POWER_ADAPT_GROUP		5
+
+#define MRVDRV_MAX_SSID_LIST_LENGTH     10
+
+typedef u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+typedef u8 WLAN_802_11_MAC_ADDRESS[ETH_ALEN];
+
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+    Wlan802_11FH,
+    Wlan802_11DS,
+    /*defined as upper bound */
+    Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE, *PWLAN_802_11_NETWORK_TYPE;
+
+/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
+typedef enum _WLAN_802_11_NETWORK_INFRASTRUCTURE
+{
+    Wlan802_11IBSS,
+    Wlan802_11Infrastructure,
+    Wlan802_11AutoUnknown,
+    /*defined as upper bound */
+    Wlan802_11InfrastructureMax
+} WLAN_802_11_NETWORK_INFRASTRUCTURE, *PWLAN_802_11_NETWORK_INFRASTRUCTURE;
+
+#define IEEE_MAX_IE_SIZE  256
+
+/** IEEE Type definitions  */
+typedef enum _IEEEtypes_ElementId_e
+{
+    SSID = 0,
+    SUPPORTED_RATES = 1,
+    FH_PARAM_SET = 2,
+    DS_PARAM_SET = 3,
+    CF_PARAM_SET = 4,
+
+    IBSS_PARAM_SET = 6,
+
+    COUNTRY_INFO = 7,
+
+    ERP_INFO = 42,
+    EXTENDED_SUPPORTED_RATES = 50,
+
+    VENDOR_SPECIFIC_221 = 221,
+    WMM_IE = VENDOR_SPECIFIC_221,
+
+    WPS_IE = VENDOR_SPECIFIC_221,
+
+    WPA_IE = VENDOR_SPECIFIC_221,
+    RSN_IE = 48,
+
+    EXTRA_IE = 133,
+} __ATTRIB_PACK__ IEEEtypes_ElementId_e;
+
+#define CAPINFO_MASK    (~( W_BIT_15 | W_BIT_14 |               \
+                            W_BIT_12 | W_BIT_11 | W_BIT_9) )
+
+typedef struct _IEEEtypes_CapInfo_t
+{
+    u8 Ess:1;
+    u8 Ibss:1;
+    u8 CfPollable:1;
+    u8 CfPollRqst:1;
+    u8 Privacy:1;
+    u8 ShortPreamble:1;
+    u8 Pbcc:1;
+    u8 ChanAgility:1;
+    u8 SpectrumMgmt:1;
+    u8 Rsrvd3:1;
+    u8 ShortSlotTime:1;
+    u8 Apsd:1;
+    u8 Rsvrd2:1;
+    u8 DSSSOFDM:1;
+    u8 Rsrvd1:2;
+} __ATTRIB_PACK__ IEEEtypes_CapInfo_t;
+
+typedef struct
+{
+    u8 ElementId;
+    u8 Len;
+} __ATTRIB_PACK__ IEEEtypes_Header_t;
+
+/** IEEEtypes_CfParamSet_t */
+typedef struct _IEEEtypes_CfParamSet_t
+{
+    u8 ElementId;
+    u8 Len;
+    u8 CfpCnt;
+    u8 CfpPeriod;
+    u16 CfpMaxDuration;
+    u16 CfpDurationRemaining;
+} __ATTRIB_PACK__ IEEEtypes_CfParamSet_t;
+
+typedef struct IEEEtypes_IbssParamSet_t
+{
+    u8 ElementId;
+    u8 Len;
+    u16 AtimWindow;
+} __ATTRIB_PACK__ IEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef union _IEEEtypes_SsParamSet_t
+{
+    IEEEtypes_CfParamSet_t CfParamSet;
+    IEEEtypes_IbssParamSet_t IbssParamSet;
+} __ATTRIB_PACK__ IEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef struct _IEEEtypes_FhParamSet_t
+{
+    u8 ElementId;
+    u8 Len;
+    u16 DwellTime;
+    u8 HopSet;
+    u8 HopPattern;
+    u8 HopIndex;
+} __ATTRIB_PACK__ IEEEtypes_FhParamSet_t;
+
+typedef struct _IEEEtypes_DsParamSet_t
+{
+    u8 ElementId;
+    u8 Len;
+    u8 CurrentChan;
+} __ATTRIB_PACK__ IEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef union IEEEtypes_PhyParamSet_t
+{
+    IEEEtypes_FhParamSet_t FhParamSet;
+    IEEEtypes_DsParamSet_t DsParamSet;
+} __ATTRIB_PACK__ IEEEtypes_PhyParamSet_t;
+
+typedef struct _IEEEtypes_ERPInfo_t
+{
+    u8 ElementId;
+    u8 Len;
+    u8 ERPFlags;
+} __ATTRIB_PACK__ IEEEtypes_ERPInfo_t;
+
+typedef u16 IEEEtypes_AId_t;
+typedef u16 IEEEtypes_StatusCode_t;
+
+typedef struct
+{
+    IEEEtypes_CapInfo_t Capability;
+    IEEEtypes_StatusCode_t StatusCode;
+    IEEEtypes_AId_t AId;
+    u8 IEBuffer[1];
+} __ATTRIB_PACK__ IEEEtypes_AssocRsp_t;
+
+typedef struct
+{
+    u8 ElementId;
+    u8 Len;
+    u8 Oui[3];
+    u8 OuiType;
+    u8 OuiSubtype;
+    u8 Version;
+} __ATTRIB_PACK__ IEEEtypes_VendorHeader_t;
+
+typedef struct
+{
+    IEEEtypes_VendorHeader_t VendHdr;
+
+    /* IE Max - size of previous fields */
+    u8 Data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+
+}
+__ATTRIB_PACK__ IEEEtypes_VendorSpecific_t;
+
+typedef struct
+{
+    IEEEtypes_Header_t IeeeHdr;
+
+    /* IE Max - size of previous fields */
+    u8 Data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+
+}
+__ATTRIB_PACK__ IEEEtypes_Generic_t;
+
+/** TLV  type ID definition */
+#define PROPRIETARY_TLV_BASE_ID		0x0100
+
+/* Terminating TLV Type */
+#define MRVL_TERMINATE_TLV_ID		0xffff
+
+#define TLV_TYPE_SSID				0x0000
+#define TLV_TYPE_RATES				0x0001
+#define TLV_TYPE_PHY_FH				0x0002
+#define TLV_TYPE_PHY_DS				0x0003
+#define TLV_TYPE_CF				    0x0004
+#define TLV_TYPE_IBSS				0x0006
+
+#define TLV_TYPE_DOMAIN				0x0007
+
+#define TLV_TYPE_POWER_CAPABILITY   0x0021
+
+#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
+#define TLV_TYPE_SNR_LOW            (PROPRIETARY_TLV_BASE_ID + 5)
+#define TLV_TYPE_FAILCOUNT          (PROPRIETARY_TLV_BASE_ID + 6)
+#define TLV_TYPE_BCNMISS            (PROPRIETARY_TLV_BASE_ID + 7)
+#define TLV_TYPE_LED_GPIO           (PROPRIETARY_TLV_BASE_ID + 8)
+#define TLV_TYPE_LEDBEHAVIOR        (PROPRIETARY_TLV_BASE_ID + 9)
+#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_POWER_TBL_2_4GHZ   (PROPRIETARY_TLV_BASE_ID + 12)
+#define TLV_TYPE_POWER_TBL_5GHZ     (PROPRIETARY_TLV_BASE_ID + 13)
+#define TLV_TYPE_WMMQSTATUS         (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_POWERADAPTCFGEXT   (PROPRIETARY_TLV_BASE_ID + 20)
+#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
+#define TLV_TYPE_AUTO_TX            (PROPRIETARY_TLV_BASE_ID + 24)
+#define TLV_TYPE_WPS_ENROLLEE_PROBE_REQ_TLV    (PROPRIETARY_TLV_BASE_ID + 27)
+#define TLV_TYPE_STARTBGSCANLATER   (PROPRIETARY_TLV_BASE_ID + 30)
+#define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
+
+/** TLV related data structures*/
+/** MrvlIEtypesHeader_t */
+typedef struct _MrvlIEtypesHeader
+{
+    u16 Type;
+    u16 Len;
+} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef struct _MrvlIEtypes_Data_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 Data[1];
+} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
+
+/** MrvlIEtypes_RatesParamSet_t */
+typedef struct _MrvlIEtypes_RatesParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 Rates[1];
+} __ATTRIB_PACK__ MrvlIEtypes_RatesParamSet_t;
+
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef struct _MrvlIEtypes_SsIdParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 SsId[1];
+} __ATTRIB_PACK__ MrvlIEtypes_SsIdParamSet_t;
+
+/** MrvlIEtypes_WildCardSsIdParamSet_t */
+typedef struct _MrvlIEtypes_WildCardSsIdParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 MaxSsidLength;
+    u8 SsId[1];
+} __ATTRIB_PACK__ MrvlIEtypes_WildCardSsIdParamSet_t;
+
+/** ChanScanMode_t */
+typedef struct
+{
+    u8 PassiveScan:1;
+    u8 DisableChanFilt:1;
+    u8 Reserved_2_7:6;
+} __ATTRIB_PACK__ ChanScanMode_t;
+
+/** ChanScanParamSet_t */
+typedef struct _ChanScanParamSet_t
+{
+    u8 RadioType;
+    u8 ChanNumber;
+    ChanScanMode_t ChanScanMode;
+    u16 MinScanTime;
+    u16 MaxScanTime;
+} __ATTRIB_PACK__ ChanScanParamSet_t;
+
+/** MrvlIEtypes_ChanListParamSet_t */
+typedef struct _MrvlIEtypes_ChanListParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    ChanScanParamSet_t ChanScanParam[1];
+} __ATTRIB_PACK__ MrvlIEtypes_ChanListParamSet_t;
+
+/** CfParamSet_t */
+typedef struct _CfParamSet_t
+{
+    u8 CfpCnt;
+    u8 CfpPeriod;
+    u16 CfpMaxDuration;
+    u16 CfpDurationRemaining;
+} __ATTRIB_PACK__ CfParamSet_t;
+
+/** IbssParamSet_t */
+typedef struct _IbssParamSet_t
+{
+    u16 AtimWindow;
+} __ATTRIB_PACK__ IbssParamSet_t;
+
+/** MrvlIEtypes_SsParamSet_t */
+typedef struct _MrvlIEtypes_SsParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    union
+    {
+        CfParamSet_t CfParamSet[1];
+        IbssParamSet_t IbssParamSet[1];
+    } cf_ibss;
+} __ATTRIB_PACK__ MrvlIEtypes_SsParamSet_t;
+
+/** FhParamSet_t */
+typedef struct _FhParamSet_t
+{
+    u16 DwellTime;
+    u8 HopSet;
+    u8 HopPattern;
+    u8 HopIndex;
+} __ATTRIB_PACK__ FhParamSet_t;
+
+/** DsParamSet_t */
+typedef struct _DsParamSet_t
+{
+    u8 CurrentChan;
+} __ATTRIB_PACK__ DsParamSet_t;
+
+/** MrvlIEtypes_PhyParamSet_t */
+typedef struct _MrvlIEtypes_PhyParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    union
+    {
+        FhParamSet_t FhParamSet[1];
+        DsParamSet_t DsParamSet[1];
+    } fh_ds;
+} __ATTRIB_PACK__ MrvlIEtypes_PhyParamSet_t;
+
+/** MrvlIEtypes_RsnParamSet_t */
+typedef struct _MrvlIEtypes_RsnParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 RsnIE[1];
+} __ATTRIB_PACK__ MrvlIEtypes_RsnParamSet_t;
+
+/** MrvlIEtypes_WmmParamSet_t */
+typedef struct _MrvlIEtypes_WmmParamSet_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 WmmIE[1];
+} __ATTRIB_PACK__ MrvlIEtypes_WmmParamSet_t;
+
+typedef struct
+{
+    MrvlIEtypesHeader_t Header;
+    u8 QueueIndex;
+    u8 Disabled;
+    u8 Reserved1;
+    u8 Reserved2;
+    u8 FlowRequired;
+    u8 FlowCreated;
+    u32 Reserved3;
+} __ATTRIB_PACK__ MrvlIEtypes_WmmQueueStatus_t;
+
+/** Table of TSF values returned in the scan result */
+typedef struct
+{
+    MrvlIEtypesHeader_t Header;
+    u64 tsfTable[1];
+} __ATTRIB_PACK__ MrvlIEtypes_TsfTimestamp_t;
+
+/**  Local Power Capability */
+typedef struct _MrvlIEtypes_PowerCapability_t
+{
+    MrvlIEtypesHeader_t Header;
+    s8 MinPower;
+    s8 MaxPower;
+} __ATTRIB_PACK__ MrvlIEtypes_PowerCapability_t;
+
+/** MrvlIEtypes_RssiParamSet_t */
+typedef struct _MrvlIEtypes_RssiThreshold_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 RSSIValue;
+    u8 RSSIFreq;
+} __ATTRIB_PACK__ MrvlIEtypes_RssiThreshold_t;
+
+/** MrvlIEtypes_SnrThreshold_t */
+typedef struct _MrvlIEtypes_SnrThreshold_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 SNRValue;
+    u8 SNRFreq;
+} __ATTRIB_PACK__ MrvlIEtypes_SnrThreshold_t;
+
+/** MrvlIEtypes_FailureCount_t */
+typedef struct _MrvlIEtypes_FailureCount_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 FailValue;
+    u8 FailFreq;
+} __ATTRIB_PACK__ MrvlIEtypes_FailureCount_t;
+
+/** MrvlIEtypes_BeaconsMissed_t */
+typedef struct _MrvlIEtypes_BeaconsMissed_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 BeaconMissed;
+    u8 Reserved;
+} __ATTRIB_PACK__ MrvlIEtypes_BeaconsMissed_t;
+
+/** MrvlIEtypes_NumProbes_t */
+typedef struct _MrvlIEtypes_NumProbes_t
+{
+    MrvlIEtypesHeader_t Header;
+    u16 NumProbes;
+} __ATTRIB_PACK__ MrvlIEtypes_NumProbes_t;
+
+/** MrvlIEtypes_StartBGScanLater_t */
+typedef struct _MrvlIEtypes_StartBGScanLater_t
+{
+    MrvlIEtypesHeader_t Header;
+    u16 StartLater;
+} __ATTRIB_PACK__ MrvlIEtypes_StartBGScanLater_t;
+
+typedef struct _LedGpio_t
+{
+    u8 LedNum;                  /* LED # mapped to GPIO pin # below */
+    u8 GpioNum;                 /* GPIO pin # used to control LED # above */
+} __ATTRIB_PACK__ LedGpio_t;
+
+/** MrvlIEtypes_LedGpio_t */
+typedef struct _MrvlIEtypes_LedGpio_t
+{
+    MrvlIEtypesHeader_t Header;
+    LedGpio_t LedGpio[1];
+} __ATTRIB_PACK__ MrvlIEtypes_LedGpio_t;
+
+/** MrvlIEtypes_LedBehavior_t */
+typedef struct _MrvlIEtypes_LedBehavior_t
+{
+    MrvlIEtypesHeader_t Header;
+    u8 FirmwareState;           /* Firmware State */
+    u8 LedNum;                  /* LED # */
+    u8 LedState;                /* LED State corresponding to Firmware State */
+    u8 LedArgs;                 /* Arguments for LED State */
+} __ATTRIB_PACK__ MrvlIEtypes_LedBehavior_t;
+
+typedef struct _PA_Group_t
+{
+    u16 PowerAdaptLevel;
+    u16 RateBitmap;
+    u32 Reserved;
+} __ATTRIB_PACK__ PA_Group_t;
+
+/** MrvlIEtypes_PA_Group_t */
+typedef struct _MrvlIEtypes_PowerAdapt_Group_t
+{
+    MrvlIEtypesHeader_t Header;
+    PA_Group_t PA_Group[MAX_POWER_ADAPT_GROUP];
+} __ATTRIB_PACK__ MrvlIEtypes_PowerAdapt_Group_t;
+
+typedef struct _AutoTx_MacFrame_t
+{
+    u16 Interval;               /* in seconds */
+    u8 Priority;                /* User Priority: 0~7, ignored if non-WMM */
+    u8 Reserved;                /* set to 0 */
+    u16 FrameLen;               /* Length of MAC frame payload */
+    u8 DestMacAddr[ETH_ALEN];
+    u8 SrcMacAddr[ETH_ALEN];
+    u8 Payload[];
+} __ATTRIB_PACK__ AutoTx_MacFrame_t;
+
+/** MrvlIEtypes_AutoTx_t */
+typedef struct _MrvlIEtypes_AutoTx_t
+{
+    MrvlIEtypesHeader_t Header;
+    AutoTx_MacFrame_t AutoTx_MacFrame;
+} __ATTRIB_PACK__ MrvlIEtypes_AutoTx_t;
+
+typedef struct
+{
+    u8 value;
+    u8 Freq;
+} Threshold;
+
+typedef struct
+{
+    u16 EventsBitmap;           /* bit 0: RSSI low,  bit 1: SNR low,
+                                 * bit 2: RSSI high, bit 3: SNR high
+                                 */
+    Threshold Rssi_low;
+    Threshold Snr_low;
+    Threshold Rssi_high;
+    Threshold Snr_high;
+    u8 Rssi_low_count;
+    u8 Snr_low_count;
+    u8 Rssi_high_count;
+    u8 Snr_high_count;
+} wlan_subscribe_event;
+
+/** Auth type to be used in the Authentication portion of an Assoc seq */
+typedef struct
+{
+    MrvlIEtypesHeader_t Header;
+    u16 AuthType;
+} __ATTRIB_PACK__ MrvlIEtypes_AuthType_t;
+
+#define MRVDRV_MAX_SUBBAND_802_11D		83
+#define COUNTRY_CODE_LEN			3
+
+/** Data structure for Country IE*/
+typedef struct _IEEEtypes_SubbandSet
+{
+    u8 FirstChan;
+    u8 NoOfChan;
+    u8 MaxTxPwr;
+} __ATTRIB_PACK__ IEEEtypes_SubbandSet_t;
+
+typedef struct _IEEEtypes_CountryInfoSet
+{
+    u8 ElementId;
+    u8 Len;
+    u8 CountryCode[COUNTRY_CODE_LEN];
+    IEEEtypes_SubbandSet_t Subband[1];
+} __ATTRIB_PACK__ IEEEtypes_CountryInfoSet_t;
+
+typedef struct _IEEEtypes_CountryInfoFullSet
+{
+    u8 ElementId;
+    u8 Len;
+    u8 CountryCode[COUNTRY_CODE_LEN];
+    IEEEtypes_SubbandSet_t Subband[MRVDRV_MAX_SUBBAND_802_11D];
+} __ATTRIB_PACK__ IEEEtypes_CountryInfoFullSet_t;
+
+typedef struct _MrvlIEtypes_DomainParamSet
+{
+    MrvlIEtypesHeader_t Header;
+    u8 CountryCode[COUNTRY_CODE_LEN];
+    IEEEtypes_SubbandSet_t Subband[1];
+} __ATTRIB_PACK__ MrvlIEtypes_DomainParamSet_t;
+
+/** Size of a TSPEC.  Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE              63
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES    256
+
+/** Extra TLV bytes allocated in messages for configuring WMM Queues */
+#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** enum of WMM AC_QUEUES */
+typedef enum
+{
+    WMM_AC_BK,
+    WMM_AC_BE,
+    WMM_AC_VI,
+    WMM_AC_VO,
+} __ATTRIB_PACK__ wlan_wmm_ac_e;
+
+/** data structure of WMM QoS information */
+typedef struct
+{
+    u8 ParaSetCount:4;
+    u8 Reserved:3;
+    u8 QosUAPSD:1;
+} __ATTRIB_PACK__ IEEEtypes_WmmQosInfo_t;
+
+typedef struct
+{
+    u8 Aifsn:4;
+    u8 Acm:1;
+    u8 Aci:2;
+    u8 Reserved:1;
+} __ATTRIB_PACK__ IEEEtypes_WmmAciAifsn_t;
+
+/**  data structure of WMM ECW */
+typedef struct
+{
+    u8 EcwMin:4;
+    u8 EcwMax:4;
+} __ATTRIB_PACK__ IEEEtypes_WmmEcw_t;
+
+/** data structure of WMM AC parameters  */
+typedef struct
+{
+    IEEEtypes_WmmAciAifsn_t AciAifsn;
+    IEEEtypes_WmmEcw_t Ecw;
+    u16 TxopLimit;
+} __ATTRIB_PACK__ IEEEtypes_WmmAcParameters_t;
+
+/** data structure of WMM Info IE  */
+typedef struct
+{
+
+    /**
+     * WMM Info IE - Vendor Specific Header:
+     *   ElementId   [221/0xdd]
+     *   Len         [7] 
+     *   Oui         [00:50:f2]
+     *   OuiType     [2]
+     *   OuiSubType  [0]
+     *   Version     [1]
+     */
+    IEEEtypes_VendorHeader_t VendHdr;
+
+    IEEEtypes_WmmQosInfo_t QoSInfo;
+
+} __ATTRIB_PACK__ IEEEtypes_WmmInfo_t;
+
+/** data structure of WMM parameter IE  */
+typedef struct
+{
+    /**
+     * WMM Parameter IE - Vendor Specific Header:
+     *   ElementId   [221/0xdd]
+     *   Len         [24] 
+     *   Oui         [00:50:f2]
+     *   OuiType     [2]
+     *   OuiSubType  [1]
+     *   Version     [1]
+     */
+    IEEEtypes_VendorHeader_t VendHdr;
+
+    IEEEtypes_WmmQosInfo_t QoSInfo;
+    u8 Reserved;
+
+    /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+    IEEEtypes_WmmAcParameters_t AcParams[MAX_AC_QUEUES];
+
+} __ATTRIB_PACK__ IEEEtypes_WmmParameter_t;
+
+/**
+ *  @brief Firmware command structure to retrieve the firmware WMM status.
+ *
+ *  Used to retrieve the status of each WMM AC Queue in TLV 
+ *    format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
+ *    parameter IE advertised by the AP.  
+ *  
+ *  Used in response to a MACREG_INT_CODE_WMM_STATUS_CHANGE event signalling
+ *    a QOS change on one of the ACs or a change in the WMM Parameter in
+ *    the Beacon.
+ *
+ *  TLV based command, byte arrays used for max sizing purpose. There are no 
+ *    arguments sent in the command, the TLVs are returned by the firmware.
+ */
+typedef struct
+{
+    u8 queueStatusTlv[sizeof(MrvlIEtypes_WmmQueueStatus_t) * MAX_AC_QUEUES];
+    u8 wmmParamTlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
+
+}
+__ATTRIB_PACK__ HostCmd_DS_WMM_GET_STATUS;
+
+/**
+ *  @brief Enumeration for the command result from an ADDTS or DELTS command 
+ */
+typedef enum
+{
+    TSPEC_RESULT_SUCCESS = 0,
+    TSPEC_RESULT_EXEC_FAILURE = 1,
+    TSPEC_RESULT_TIMEOUT = 2,
+    TSPEC_RESULT_DATA_INVALID = 3,
+
+} __ATTRIB_PACK__ wlan_wmm_tspec_result_e;
+
+/**
+ *  @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ *    as any additional IEs appended in the ADDTS Action frame.
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;
+    u32 timeout_ms;
+
+    u8 ieeeStatusCode;
+
+    u8 tspecData[WMM_TSPEC_SIZE];
+
+    u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];
+
+} __ATTRIB_PACK__ wlan_ioctl_wmm_addts_req_t;
+
+/**
+ *  @brief IOCTL structure to send a DELTS request.
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Firmware execution result
+
+    u8 ieeeReasonCode;          //!< IEEE reason code sent, unused for WMM 
+
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC to send in the DELTS
+
+} __ATTRIB_PACK__ wlan_ioctl_wmm_delts_req_t;
+
+/**
+ *  @brief Internal command structure used in executing an ADDTS command.
+ *
+ *  Relay information between the IOCTL layer and the firmware command and 
+ *    command response procedures.
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ *  @sa wlan_cmd_wmm_addts_req
+ *  @sa wlan_cmdresp_wmm_addts_req
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;
+    u32 timeout_ms;
+
+    u8 dialogToken;
+    u8 ieeeStatusCode;
+
+    int tspecDataLen;
+    u8 tspecData[WMM_TSPEC_SIZE];
+    u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];
+
+} wlan_cmd_wmm_addts_req_t;
+
+/**
+ *  @brief Internal command structure used in executing an DELTS command.
+ *
+ *  Relay information between the IOCTL layer and the firmware command and 
+ *    command response procedures.
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ *  @sa wlan_cmd_wmm_delts_req
+ *  @sa wlan_cmdresp_wmm_delts_req
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;
+
+    u8 dialogToken;
+
+    u8 ieeeReasonCode;
+
+    int tspecDataLen;
+    u8 tspecData[WMM_TSPEC_SIZE];
+
+} wlan_cmd_wmm_delts_req_t;
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
+ *
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;
+    u32 timeout_ms;
+
+    u8 dialogToken;
+    u8 ieeeStatusCode;
+    u8 tspecData[WMM_TSPEC_SIZE];
+    u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_ADDTS_REQ;
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;
+    u8 dialogToken;
+    u8 ieeeReasonCode;
+    u8 tspecData[WMM_TSPEC_SIZE];
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_DELTS_REQ;
+
+/**
+ *  @brief Enumeration for the action field in the Queue configure command
+ */
+typedef enum
+{
+    WMM_QUEUE_CONFIG_ACTION_GET = 0,
+    WMM_QUEUE_CONFIG_ACTION_SET = 1,
+    WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+
+    WMM_QUEUE_CONFIG_ACTION_MAX
+} __ATTRIB_PACK__ wlan_wmm_queue_config_action_e;
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
+ *
+ *  Set/Get/Default the Queue parameters for a specific AC in the firmware.
+ *
+ */
+typedef struct
+{
+    wlan_wmm_queue_config_action_e action;      //!< Set, Get, or Default
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+
+    /** @brief MSDU lifetime expiry per 802.11e
+     *
+     *   - Ignored if 0 on a set command 
+     *   - Set to the 802.11e specified 500 TUs when defaulted
+     */
+    u16 msduLifetimeExpiry;
+
+    u8 tlvBuffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES];     //!< Not supported yet
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_QUEUE_CONFIG;
+
+/**
+ *  @brief Internal command structure used in executing a queue config command.
+ *
+ *  Relay information between the IOCTL layer and the firmware command and 
+ *    command response procedures.
+ *
+ *  @sa wlan_wmm_queue_config_ioctl
+ *  @sa wlan_cmd_wmm_queue_config
+ *  @sa wlan_cmdresp_wmm_queue_config
+ */
+typedef struct
+{
+    wlan_wmm_queue_config_action_e action;      //!< Set, Get, or Default
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+    u16 msduLifetimeExpiry;     //!< lifetime expiry in TUs
+
+    int tlvBufLen;              //!< Not supported yet
+    u8 tlvBuffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES];     //!< Not supported yet
+
+} wlan_cmd_wmm_queue_config_t;
+
+/**
+ *  @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    get, set, or default the WMM AC queue parameters.
+ *
+ *  - msduLifetimeExpiry is ignored if set to 0 on a set command
+ *
+ *  @sa wlan_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_queue_config_action_e action;      //!< Set, Get, or Default
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+    u16 msduLifetimeExpiry;     //!< lifetime expiry in TUs
+
+    u8 supportedRates[10];      //!< Not supported yet
+
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_config_t;
+
+/**
+ *   @brief Enumeration for the action field in the queue stats command
+ */
+typedef enum
+{
+    WMM_STATS_ACTION_START = 0,
+    WMM_STATS_ACTION_STOP = 1,
+    WMM_STATS_ACTION_GET_CLR = 2,
+    WMM_STATS_ACTION_SET_CFG = 3,       /* Not currently used */
+    WMM_STATS_ACTION_GET_CFG = 4,       /* Not currently used */
+
+    WMM_STATS_ACTION_MAX
+} __ATTRIB_PACK__ wlan_wmm_stats_action_e;
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS  7
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
+ *
+ *  Turn statistical collection on/off for a given AC or retrieve the 
+ *    accumulated stats for an AC and clear them in the firmware.
+ */
+typedef struct
+{
+    wlan_wmm_stats_action_e action;     //!< Start, Stop, or Get 
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+
+    u16 pktCount;               //!< Number of successful packets transmitted
+    u16 pktLoss;                //!< Packets lost; not included in pktCount
+    u32 avgQueueDelay;          //!< Average Queue delay in microseconds
+    u32 avgTxDelay;             //!< Average Transmission delay in microseconds
+    u32 usedTime;               //!< Calculated medium time - Not currently used
+
+    /** @brief Queue Delay Histogram; number of packets per queue delay range
+     * 
+     *  [0] -  0ms <= delay < 5ms
+     *  [1] -  5ms <= delay < 10ms
+     *  [2] - 10ms <= delay < 20ms
+     *  [3] - 20ms <= delay < 30ms
+     *  [4] - 30ms <= delay < 40ms
+     *  [5] - 40ms <= delay < 50ms
+     *  [6] - 50ms <= delay < msduLifetime (TUs)
+     */
+    u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
+
+    u16 reserved_u16_1;
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_QUEUE_STATS;
+
+/**
+ *  @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    start or stop statistical collection for a given AC.  Also used to 
+ *    retrieve and clear the collected stats on a given AC.
+ *
+ *  @sa wlan_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_stats_action_e action;     //!< Start, Stop, or Get 
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+    u16 pktCount;               //!< Number of successful packets transmitted  
+    u16 pktLoss;                //!< Packets lost; not included in pktCount    
+    u32 avgQueueDelay;          //!< Average Queue delay in microseconds
+    u32 avgTxDelay;             //!< Average Transmission delay in microseconds
+    u32 usedTime;               //!< Calculated medium time 
+
+    /** @brief Queue Delay Histogram; number of packets per queue delay range
+     * 
+     *  [0] -  0ms <= delay < 5ms
+     *  [1] -  5ms <= delay < 10ms
+     *  [2] - 10ms <= delay < 20ms
+     *  [3] - 20ms <= delay < 30ms
+     *  [4] - 30ms <= delay < 40ms
+     *  [5] - 40ms <= delay < 50ms
+     *  [6] - 50ms <= delay < msduLifetime (TUs)
+     */
+    u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_stats_t;
+
+/** 
+ *  @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+    u8 wmmAcm;
+    u8 flowRequired;
+    u8 flowCreated;
+    u8 disabled;
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ *  @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ *  IOCTL structure from the application layer to retrieve:
+ *     - ACM bit setting for the AC
+ *     - Firmware status (flow required, flow created, flow disabled)
+ *
+ *  @sa wlan_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+    wlan_ioctl_wmm_queue_status_ac_t acStatus[MAX_AC_QUEUES];
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_status_t;
+
+/** Firmware status for a specific AC */
+typedef struct
+{
+    u8 Disabled;
+    u8 FlowRequired;
+    u8 FlowCreated;
+} WmmAcStatus_t;
+
+#endif /* _WLAN_TYPES_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_version.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_version.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_version.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_version.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,32 @@
+/** @file wlan_version.h
+  * @brief This file contains wlan driver version number.
+  * 
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	
+********************************************************/
+#include "../release_version.h"
+
+const char driver_version[] =
+    "sd8686-%s-" DRIVER_RELEASE_VERSION "-(" "FP" FPNUM ")"
+#ifdef	DEBUG_LEVEL2
+    "-dbg"
+#endif
+    " ";
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wext.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wext.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wext.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wext.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,7848 @@
+/** @file  wlan_wext.c 
+  * @brief This file contains ioctl functions
+  * 
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/10/05: Add Doxygen format comments
+	12/23/05: Modify FindBSSIDInList to search entire table for
+	          duplicate BSSIDs when earlier matches are not compatible
+	12/26/05: Remove errant memcpy in wlanidle_off; overwriting stack space
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join functions.
+	          Update statics/externs.  Move forward decl. from wlan_decl.h
+	04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+	04/10/06: Add hostcmd generic API
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	05/04/06: Add IBSS coalescing related new iwpriv command
+	08/29/06: Add ledgpio private command
+	10/23/06: Validate setbcnavg/setdataavg command parameters and
+	          return error if out of range
+********************************************************/
+
+#include	"include.h"
+
+#include	"wlan_version.h"
+
+#define GETLOG_BUFSIZE  512
+
+#define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
+				MRVDRV_MAX_SSID_LENGTH + \
+				IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+				IW_EV_QUAL_LEN + MRVDRV_MAX_SSID_LENGTH + \
+				IW_EV_PARAM_LEN + 40)   /* 40 for WPAIE */
+
+typedef struct _ioctl_cmd
+{
+    int cmd;
+    int subcmd;
+    BOOLEAN fixsize;
+} ioctl_cmd;
+
+static ioctl_cmd Commands_Allowed_In_DeepSleep[] = {
+    {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLAN_SETONEINT_GETWORDCHAR,.subcmd = WLANVERSION,.fixsize =
+     FALSE},
+    {.cmd = WLAN_SETINT_GETINT,.subcmd = WLANSDIOCLOCK,.fixsize = TRUE},
+    {.cmd = WLAN_SET_GET_2K,.subcmd = WLAN_GET_CFP_TABLE,.fixsize = FALSE},
+#ifdef DEBUG_LEVEL1
+    {.cmd = WLAN_SET_GET_SIXTEEN_INT,.subcmd = WLAN_DRV_DBG,.fixsize = FALSE},
+#endif
+};
+
+static ioctl_cmd Commands_Allowed_In_HostSleep[] = {
+    {.cmd = WLAN_SETONEINT_GETWORDCHAR,.subcmd = WLANVERSION,.fixsize =
+     FALSE},
+    {.cmd = WLANDEEPSLEEP,.subcmd = 1,.fixsize = FALSE},
+    {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLAN_SETINT_GETINT,.subcmd = WLANSDIOCLOCK,.fixsize = TRUE},
+    {.cmd = WLAN_SET_GET_2K,.subcmd = WLAN_GET_CFP_TABLE,.fixsize = FALSE},
+#ifdef DEBUG_LEVEL1
+    {.cmd = WLAN_SET_GET_SIXTEEN_INT,.subcmd = WLAN_DRV_DBG,.fixsize = FALSE},
+#endif
+};
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/********************************************************
+		Global Variables
+********************************************************/
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define	DEFAULT_DEBUG_MASK	(0xffffffff & ~DBG_EVENT)
+#else
+#define DEFAULT_DEBUG_MASK	(DBG_MSG | DBG_FATAL | DBG_ERROR)
+#endif
+u32 drvdbg = DEFAULT_DEBUG_MASK;
+u32 ifdbg = 0;
+#endif
+
+/********************************************************
+		Local Functions
+********************************************************/
+static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra);
+static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra);
+
+static int wlan_get_essid(struct net_device *dev,
+                          struct iw_request_info *info, struct iw_point *dwrq,
+                          char *extra);
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_freq *fwrq, char *extra);
+static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_freq *fwrq, char *extra);
+
+static int wlan_set_mode(struct net_device *dev, struct iw_request_info *info,
+                         u32 * uwrq, char *extra);
+static int wlan_get_mode(struct net_device *dev, struct iw_request_info *info,
+                         u32 * uwrq, char *extra);
+
+static int wlan_set_encode(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct iw_point *dwrq, char *extra);
+static int wlan_get_encode(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct iw_point *dwrq, u8 * extra);
+
+static int wlan_set_txpow(struct net_device *dev,
+                          struct iw_request_info *info, struct iw_param *vwrq,
+                          char *extra);
+static int wlan_get_txpow(struct net_device *dev,
+                          struct iw_request_info *info, struct iw_param *vwrq,
+                          char *extra);
+
+static int wlan_set_coalescing_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+extern CHANNEL_FREQ_POWER *wlan_get_region_cfp_table(u8 region, u8 band,
+                                                     int *cfp_no);
+
+/** 
+ *  @brief This function checks if the commans is allowed
+ *  in deepsleep/hostsleep mode or not.
+ * 
+ *  @param req	       A pointer to ifreq structure 
+ *  @param cmd         the command ID
+ *  @return 	   TRUE or FALSE
+ */
+static BOOLEAN
+Is_Command_Allowed_In_Sleep(struct ifreq *req, int cmd,
+                            ioctl_cmd * allowed_cmds, int count)
+{
+    int subcmd = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (cmd == allowed_cmds[i].cmd) {
+            if (allowed_cmds[i].subcmd == 0)
+                return TRUE;
+            if (allowed_cmds[i].fixsize == TRUE)
+                subcmd = (int) req->ifr_data;
+            else
+                subcmd = wrq->u.data.flags;
+            if (allowed_cmds[i].subcmd == subcmd)
+                return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/** 
+ *  @brief This function checks if the command is allowed.
+ * 
+ *  @param priv		A pointer to wlan_private structure
+ *  @return		TRUE or FALSE
+ */
+BOOLEAN
+Is_Command_Allowed(wlan_private * priv)
+{
+    BOOLEAN ret = TRUE;
+
+    if (priv->adapter->bHostSleepConfigured) {
+        PRINTM(INFO, "IOCTLS called when WLAN access is blocked\n");
+        ret = FALSE;
+    }
+    if (!priv->adapter->IsAutoDeepSleepEnabled) {
+        if ((priv->adapter->IsDeepSleep == TRUE)) {
+            PRINTM(INFO, "IOCTLS called when station is in DeepSleep\n");
+            ret = FALSE;
+        }
+    }
+
+    return ret;
+}
+
+/** 
+ *  @brief Find a character in a string.
+ *   
+ *  @param s	   A pointer to string
+ *  @param c	   Character to be located 
+ *  @param dlen    the length of string
+ *  @return 	   A pointer to the first occurrence of c in string, or NULL if c is not found.
+ */
+static void *
+wlan_memchr(void *s, int c, int n)
+{
+    const u8 *p = s;
+
+    while (n-- != 0) {
+        if ((u8) c == *p++) {
+            return (void *) (p - 1);
+        }
+    }
+    return NULL;
+}
+
+#if WIRELESS_EXT > 14
+/** 
+ *  @brief Convert mw value to dbm value
+ *   
+ *  @param mw	   the value of mw
+ *  @return 	   the value of dbm
+ */
+static int
+mw_to_dbm(int mw)
+{
+    if (mw < 2)
+        return 0;
+    else if (mw < 3)
+        return 3;
+    else if (mw < 4)
+        return 5;
+    else if (mw < 6)
+        return 7;
+    else if (mw < 7)
+        return 8;
+    else if (mw < 8)
+        return 9;
+    else if (mw < 10)
+        return 10;
+    else if (mw < 13)
+        return 11;
+    else if (mw < 16)
+        return 12;
+    else if (mw < 20)
+        return 13;
+    else if (mw < 25)
+        return 14;
+    else if (mw < 32)
+        return 15;
+    else if (mw < 40)
+        return 16;
+    else if (mw < 50)
+        return 17;
+    else if (mw < 63)
+        return 18;
+    else if (mw < 79)
+        return 19;
+    else if (mw < 100)
+        return 20;
+    else
+        return 21;
+}
+
+/** 
+ *  @brief This function sends customized event to application.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @para str	   A pointer to event string
+ *  @return 	   n/a
+ */
+void
+send_iwevcustom_event(wlan_private * priv, s8 * str)
+{
+    union iwreq_data iwrq;
+    u8 buf[50];
+
+    ENTER();
+
+    memset(&iwrq, 0, sizeof(union iwreq_data));
+    memset(buf, 0, sizeof(buf));
+
+    snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+    iwrq.data.pointer = buf;
+    iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+    /* Send Event to upper layer */
+    wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+    PRINTM(INFO, "Wireless event %s is sent to app\n", str);
+
+    LEAVE();
+    return;
+}
+#endif
+
+#define FIRST_VALID_CHANNEL	0xff
+/** 
+ *  @brief Find the channel frequency power info with specific channel
+ *   
+ *  @param adapter 	A pointer to wlan_adapter structure
+ *  @param band		it can be BAND_A, BAND_G or BAND_B
+ *  @param channel      the channel for looking	
+ *  @return 	   	A pointer to CHANNEL_FREQ_POWER structure or NULL if not find.
+ */
+CHANNEL_FREQ_POWER *
+find_cfp_by_band_and_channel(wlan_adapter * adapter, u8 band, u16 channel)
+{
+    CHANNEL_FREQ_POWER *cfp = NULL;
+    REGION_CHANNEL *rc;
+    int count = sizeof(adapter->region_channel) /
+        sizeof(adapter->region_channel[0]);
+    int i, j;
+
+    for (j = 0; !cfp && (j < count); j++) {
+        rc = &adapter->region_channel[j];
+
+        if (adapter->State11D.Enable11D == ENABLE_11D) {
+            rc = &adapter->universal_channel[j];
+        }
+        if (!rc->Valid || !rc->CFP)
+            continue;
+        if (rc->Band != band)
+            continue;
+        if (channel == FIRST_VALID_CHANNEL)
+            cfp = &rc->CFP[0];
+        else {
+            for (i = 0; i < rc->NrCFP; i++) {
+                if (rc->CFP[i].Channel == channel) {
+                    cfp = &rc->CFP[i];
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!cfp && channel)
+        PRINTM(INFO, "find_cfp_by_band_and_channel(): cannot find "
+               "cfp by band %d & channel %d\n", band, channel);
+
+    return cfp;
+}
+
+/** 
+ *  @brief Find the channel frequency power info with specific frequency
+ *   
+ *  @param adapter  A pointer to wlan_adapter structure
+ *  @param band     it can be BAND_A, BAND_G or BAND_B
+ *  @param freq     the frequency for looking   
+ *  @return         Pointer to CHANNEL_FREQ_POWER structure; NULL if not found
+ */
+static CHANNEL_FREQ_POWER *
+find_cfp_by_band_and_freq(wlan_adapter * adapter, u8 band, u32 freq)
+{
+    CHANNEL_FREQ_POWER *cfp = NULL;
+    REGION_CHANNEL *rc;
+    int count = sizeof(adapter->region_channel) /
+        sizeof(adapter->region_channel[0]);
+    int i, j;
+
+    for (j = 0; !cfp && (j < count); j++) {
+        rc = &adapter->region_channel[j];
+
+        if (adapter->State11D.Enable11D == ENABLE_11D) {
+            rc = &adapter->universal_channel[j];
+        }
+
+        if (!rc->Valid || !rc->CFP)
+            continue;
+        if (rc->Band != band)
+            continue;
+        for (i = 0; i < rc->NrCFP; i++) {
+            if (rc->CFP[i].Freq == freq) {
+                cfp = &rc->CFP[i];
+                break;
+            }
+        }
+    }
+
+    if (!cfp && freq)
+        PRINTM(INFO, "find_cfp_by_band_and_freql(): cannot find cfp by "
+               "band %d & freq %d\n", band, freq);
+
+    return cfp;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/** 
+ *  @brief Manufacturing command ioctl function
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq 		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+wlan_mfg_command(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_GEN *pCmdPtr;
+    u8 *mfg_cmd;
+    u16 mfg_cmd_len;
+    int ret;
+
+    ENTER();
+
+    /* allocate MFG command buffer */
+    if (!(mfg_cmd = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
+        PRINTM(INFO, "allocate MFG command buffer failed!\n");
+        return -ENOMEM;
+    }
+
+    /* get MFG command header */
+    if (copy_from_user(mfg_cmd, wrq->u.data.pointer, sizeof(HostCmd_DS_GEN))) {
+        PRINTM(INFO, "copy from user failed: MFG command header\n");
+        ret = -EFAULT;
+        goto mfg_exit;
+    }
+
+    /* get the command size */
+    pCmdPtr = (HostCmd_DS_GEN *) mfg_cmd;
+    mfg_cmd_len = pCmdPtr->Size;
+    PRINTM(INFO, "MFG command len = %d\n", mfg_cmd_len);
+
+    if (mfg_cmd_len > MRVDRV_SIZE_OF_CMD_BUFFER) {
+        ret = -EINVAL;
+        goto mfg_exit;
+    }
+
+    /* get the whole command from user */
+    if (copy_from_user(mfg_cmd, wrq->u.data.pointer, mfg_cmd_len)) {
+        PRINTM(INFO, "copy from user failed: MFG command\n");
+        ret = -EFAULT;
+        goto mfg_exit;
+    }
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_MFG_COMMAND,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, mfg_cmd);
+
+    /* copy the response back to user */
+    if (!ret && pCmdPtr->Size) {
+        mfg_cmd_len = MIN(pCmdPtr->Size, mfg_cmd_len);
+        if (copy_to_user(wrq->u.data.pointer, mfg_cmd, mfg_cmd_len)) {
+            PRINTM(INFO, "copy to user failed: MFG command\n");
+            ret = -EFAULT;
+        }
+        wrq->u.data.length = mfg_cmd_len;
+    }
+
+  mfg_exit:
+    kfree(mfg_cmd);
+    LEAVE();
+    return ret;
+}
+#endif
+
+/** 
+ *  @brief Check if Rate Auto
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @return 	   		TRUE/FALSE
+ */
+BOOLEAN
+Is_Rate_Auto(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    int ratenum = 0;
+    int bitsize = 0;
+    bitsize = sizeof(Adapter->RateBitmap) * 8;
+    for (i = 0; i < bitsize; i++) {
+        if (Adapter->RateBitmap & (1 << i))
+            ratenum++;
+        if (ratenum > 1)
+            break;
+    }
+    if (ratenum > 1)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+/** 
+ *  @brief Covert Rate Bitmap to Rate index
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @return 	   		TRUE/FALSE
+ */
+int
+GetRateIndex(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int bitsize = sizeof(Adapter->RateBitmap) * 8;
+    int i;
+    for (i = 0; i < bitsize; i++) {
+        if (Adapter->RateBitmap & (1 << i))
+            return i;
+    }
+    return 0;
+}
+
+/** 
+ *  @brief Update Current Channel 
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+static int
+UpdateCurrentChannel(wlan_private * priv)
+{
+    int ret;
+
+    /*
+     ** the channel in f/w could be out of sync, get the current channel
+     */
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+                                HostCmd_OPT_802_11_RF_CHANNEL_GET,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    PRINTM(INFO, "Current Channel = %d\n",
+           priv->adapter->CurBssParams.BSSDescriptor.Channel);
+
+    return ret;
+}
+
+/** 
+ *  @brief Set Current Channel 
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @param channel		The channel to be set. 
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+static int
+SetCurrentChannel(wlan_private * priv, int channel)
+{
+    PRINTM(INFO, "Set Channel = %d\n", channel);
+
+    /* 
+     **  Current channel is not set to AdhocChannel requested, set channel
+     */
+    return (PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+                                  HostCmd_OPT_802_11_RF_CHANNEL_SET,
+                                  HostCmd_OPTION_WAITFORRSP, 0, &channel));
+}
+
+/** 
+ *  @brief Change Adhoc Channel
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @param channel		The channel to be set. 
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+static int
+ChangeAdhocChannel(wlan_private * priv, int channel)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    Adapter->AdhocChannel = channel;
+
+    UpdateCurrentChannel(priv);
+
+    if (Adapter->CurBssParams.BSSDescriptor.Channel == Adapter->AdhocChannel) {
+        /* AdhocChannel is set to the current Channel already */
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    PRINTM(INFO, "Updating Channel from %d to %d\n",
+           Adapter->CurBssParams.BSSDescriptor.Channel,
+           Adapter->AdhocChannel);
+
+    SetCurrentChannel(priv, Adapter->AdhocChannel);
+
+    UpdateCurrentChannel(priv);
+
+    if (Adapter->CurBssParams.BSSDescriptor.Channel != Adapter->AdhocChannel) {
+        PRINTM(INFO, "Failed to updated Channel to %d, channel = %d\n",
+               Adapter->AdhocChannel,
+               Adapter->CurBssParams.BSSDescriptor.Channel);
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        int i;
+        WLAN_802_11_SSID curAdhocSsid;
+
+        PRINTM(INFO, "Channel Changed while in an IBSS\n");
+
+        /* Copy the current ssid */
+        memcpy(&curAdhocSsid,
+               &Adapter->CurBssParams.BSSDescriptor.Ssid,
+               sizeof(WLAN_802_11_SSID));
+
+        /* Exit Adhoc mode */
+        PRINTM(INFO, "In ChangeAdhocChannel(): Sending Adhoc Stop\n");
+        ret = StopAdhocNetwork(priv);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+
+        /* Scan for the network */
+        SendSpecificSSIDScan(priv, &curAdhocSsid);
+
+        // find out the BSSID that matches the current SSID 
+        i = FindSSIDInList(Adapter, &curAdhocSsid, NULL, Wlan802_11IBSS);
+
+        if (i >= 0) {
+            PRINTM(INFO, "SSID found at %d in List," "so join\n", i);
+            JoinAdhocNetwork(priv, &Adapter->ScanTable[i]);
+        } else {
+            // else send START command
+            PRINTM(INFO, "SSID not found in list, "
+                   "so creating adhoc with ssid = %s\n", curAdhocSsid.Ssid);
+            StartAdhocNetwork(priv, &curAdhocSsid);
+        }                       // end of else (START command)
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set/Get WPA IE   
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param ie_data_ptr  A pointer to IE
+ *  @param ie_len       Length of the IE
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_wpa_ie_helper(wlan_private * priv, u8 * ie_data_ptr, u16 ie_len)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (ie_len) {
+        if (ie_len > sizeof(Adapter->Wpa_ie)) {
+            PRINTM(INFO, "failed to copy WPA IE, too big \n");
+            return -EFAULT;
+        }
+        if (copy_from_user(Adapter->Wpa_ie, ie_data_ptr, ie_len)) {
+            PRINTM(INFO, "failed to copy WPA IE \n");
+            return -EFAULT;
+        }
+        Adapter->Wpa_ie_len = ie_len;
+        PRINTM(INFO, "Set Wpa_ie_len=%d IE=%#x\n",
+               Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]);
+        HEXDUMP("Wpa_ie", Adapter->Wpa_ie, Adapter->Wpa_ie_len);
+
+        if (Adapter->Wpa_ie[0] == WPA_IE) {
+            Adapter->SecInfo.WPAEnabled = TRUE;
+        } else if (Adapter->Wpa_ie[0] == RSN_IE) {
+            Adapter->SecInfo.WPA2Enabled = TRUE;
+        } else {
+            Adapter->SecInfo.WPAEnabled = FALSE;
+            Adapter->SecInfo.WPA2Enabled = FALSE;
+        }
+    } else {
+        memset(Adapter->Wpa_ie, 0, sizeof(Adapter->Wpa_ie));
+        Adapter->Wpa_ie_len = ie_len;
+        PRINTM(INFO, "Reset Wpa_ie_len=%d IE=%#x\n",
+               Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]);
+        Adapter->SecInfo.WPAEnabled = FALSE;
+        Adapter->SecInfo.WPA2Enabled = FALSE;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set/Get WPA IE
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_wpa_ie_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    return wlan_set_wpa_ie_helper(priv,
+                                  wrq->u.data.pointer, wrq->u.data.length);
+}
+
+/** 
+ *  @brief Set WPA key
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode_wpa(struct net_device *dev,
+                    struct iw_request_info *info,
+                    struct iw_point *dwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    WLAN_802_11_KEY *pKey;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    pKey = (WLAN_802_11_KEY *) extra;
+
+    HEXDUMP("Key buffer: ", extra, dwrq->length);
+
+    // current driver only supports key length of up to 32 bytes
+    if (pKey->KeyLength > MRVL_MAX_WPA_KEY_LENGTH) {
+        PRINTM(INFO, " Error in key length \n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_KEY_MATERIAL,
+                                HostCmd_ACT_SET,
+                                HostCmd_OPTION_WAITFORRSP,
+                                KEY_INFO_ENABLED, pKey);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/*
+ *  iwconfig ethX key on:	WEPEnabled;
+ *  iwconfig ethX key off:	WEPDisabled;
+ *  iwconfig ethX key [x]:	CurrentWepKeyIndex = x; WEPEnabled;
+ *  iwconfig ethX key [x] kstr:	WepKey[x] = kstr;
+ *  iwconfig ethX key kstr:	WepKey[CurrentWepKeyIndex] = kstr;
+ *
+ *  all:			Send command SET_WEP;
+ 				SetMacPacketFilter;
+ */
+
+/** 
+ *  @brief Set WEP key
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode_nonwpa(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_point *dwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    MRVL_WEP_KEY *pWep;
+    int index, PrevAuthMode;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (Adapter->CurrentWepKeyIndex >= MRVL_NUM_WEP_KEY)
+        Adapter->CurrentWepKeyIndex = 0;
+    pWep = &Adapter->WepKey[Adapter->CurrentWepKeyIndex];
+    PrevAuthMode = Adapter->SecInfo.AuthenticationMode;
+
+    index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+    if (index >= 4) {
+        PRINTM(INFO, "Key index #%d out of range.\n", index + 1);
+        return -EINVAL;
+    }
+
+    PRINTM(INFO, "Flags=0x%x, Length=%d Index=%d CurrentWepKeyIndex=%d\n",
+           dwrq->flags, dwrq->length, index, Adapter->CurrentWepKeyIndex);
+
+    if (dwrq->length > 0) {
+        /* iwconfig ethX key [n] xxxxxxxxxxx 
+         * Key has been provided by the user 
+         */
+
+        /*
+         * Check the size of the key 
+         */
+
+        if (dwrq->length > MAX_WEP_KEY_SIZE) {
+            return -EINVAL;
+        }
+
+        /*
+         * Check the index (none -> use current) 
+         */
+
+        if (index < 0 || index > 3)     //invalid index or no index
+            index = Adapter->CurrentWepKeyIndex;
+        else                    //index is given & valid
+            pWep = &Adapter->WepKey[index];
+
+        /*
+         * Check if the key is not marked as invalid 
+         */
+        if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
+            /* Cleanup */
+            memset(pWep, 0, sizeof(MRVL_WEP_KEY));
+
+            /* Copy the key in the driver */
+            memcpy(pWep->KeyMaterial, extra, dwrq->length);
+
+            /* Set the length */
+            if (dwrq->length > MIN_WEP_KEY_SIZE) {
+                pWep->KeyLength = MAX_WEP_KEY_SIZE;
+            } else {
+                if (dwrq->length > 0) {
+                    pWep->KeyLength = MIN_WEP_KEY_SIZE;
+                } else {
+                    /* Disable the key */
+                    pWep->KeyLength = 0;
+                }
+            }
+            pWep->KeyIndex = index;
+
+            if (Adapter->SecInfo.WEPStatus != Wlan802_11WEPEnabled) {
+                /*
+                 * The status is set as Key Absent 
+                 * so as to make sure we display the 
+                 * keys when iwlist ethX key is used
+                 */
+                Adapter->SecInfo.WEPStatus = Wlan802_11WEPKeyAbsent;
+            }
+
+            PRINTM(INFO, "KeyIndex=%u KeyLength=%u\n",
+                   pWep->KeyIndex, pWep->KeyLength);
+            HEXDUMP("WepKey", (u8 *) pWep->KeyMaterial, pWep->KeyLength);
+        }
+    } else {
+        /*
+         * No key provided so it is either enable key, 
+         * on or off */
+        if (dwrq->flags & IW_ENCODE_DISABLED) {
+            PRINTM(INFO, "*** iwconfig ethX key off ***\n");
+
+            Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled;
+            if (Adapter->SecInfo.AuthenticationMode ==
+                Wlan802_11AuthModeShared)
+                Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        } else {
+            /* iwconfig ethX key [n]
+             * iwconfig ethX key on 
+             * Do we want to just set the transmit key index ? 
+             */
+
+            if (index < 0 || index > 3) {
+                PRINTM(INFO, "*** iwconfig ethX key on ***\n");
+                index = Adapter->CurrentWepKeyIndex;
+            } else {
+                PRINTM(INFO, "*** iwconfig ethX key [x=%d] ***\n", index);
+                Adapter->CurrentWepKeyIndex = index;
+            }
+
+            /* Copy the required key as the current key */
+            pWep = &Adapter->WepKey[index];
+
+            if (!pWep->KeyLength) {
+                PRINTM(INFO, "Key not set,so cannot enable it\n");
+                return -EPERM;
+            }
+
+            Adapter->SecInfo.WEPStatus = Wlan802_11WEPEnabled;
+
+            HEXDUMP("KeyMaterial", (u8 *) pWep->KeyMaterial, pWep->KeyLength);
+        }
+    }
+
+    if (pWep->KeyLength) {
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_SET_WEP,
+                                    0, HostCmd_OPTION_WAITFORRSP,
+                                    OID_802_11_ADD_WEP, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
+        Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE;
+    } else {
+        Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+    }
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_MAC_CONTROL,
+                                0, HostCmd_OPTION_WAITFORRSP,
+                                0, &Adapter->CurrentPacketFilter);
+
+    if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+        /* iwconfig ethX restricted key [1] */
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
+        PRINTM(INFO, "Auth mode restricted!\n");
+    } else if (dwrq->flags & IW_ENCODE_OPEN) {
+        /* iwconfig ethX key [2] open */
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        PRINTM(INFO, "Auth mode open!\n");
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set RX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param Mode			RF antenna mode
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+SetRxAntenna(wlan_private * priv, int Mode)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    if (Mode != RF_ANTENNA_1 && Mode != RF_ANTENNA_2
+        && Mode != RF_ANTENNA_AUTO) {
+        return -EINVAL;
+    }
+
+    Adapter->RxAntennaMode = Mode;
+
+    PRINTM(INFO, "SET RX Antenna Mode to 0x%04x\n", Adapter->RxAntennaMode);
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                                HostCmd_ACT_SET_RX, HostCmd_OPTION_WAITFORRSP,
+                                0, &Adapter->RxAntennaMode);
+    return ret;
+}
+
+/** 
+ *  @brief Set TX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param Mode			RF antenna mode
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+SetTxAntenna(wlan_private * priv, int Mode)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    if ((Mode != RF_ANTENNA_1) && (Mode != RF_ANTENNA_2)
+        && (Mode != RF_ANTENNA_AUTO)) {
+        return -EINVAL;
+    }
+
+    Adapter->TxAntennaMode = Mode;
+
+    PRINTM(INFO, "SET TX Antenna Mode to 0x%04x\n", Adapter->TxAntennaMode);
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                                HostCmd_ACT_SET_TX, HostCmd_OPTION_WAITFORRSP,
+                                0, &Adapter->TxAntennaMode);
+
+    return ret;
+}
+
+/** 
+ *  @brief Get RX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param buf			A pointer to recieve antenna mode
+ *  @return 	   		length of buf 
+ */
+static int
+GetRxAntenna(wlan_private * priv, char *buf)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    // clear it, so we will know if the value 
+    // returned below is correct or not.
+    Adapter->RxAntennaMode = 0;
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                                HostCmd_ACT_GET_RX, HostCmd_OPTION_WAITFORRSP,
+                                0, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    PRINTM(INFO, "Get Rx Antenna Mode:0x%04x\n", Adapter->RxAntennaMode);
+
+    LEAVE();
+
+    return sprintf(buf, "0x%04x", Adapter->RxAntennaMode) + 1;
+}
+
+/** 
+ *  @brief Get TX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param buf			A pointer to recieve antenna mode
+ *  @return 	   		length of buf 
+ */
+static int
+GetTxAntenna(wlan_private * priv, char *buf)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    // clear it, so we will know if the value 
+    // returned below is correct or not.
+    Adapter->TxAntennaMode = 0;
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                                HostCmd_ACT_GET_TX, HostCmd_OPTION_WAITFORRSP,
+                                0, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    PRINTM(INFO, "Get Tx Antenna Mode:0x%04x\n", Adapter->TxAntennaMode);
+
+    LEAVE();
+
+    return sprintf(buf, "0x%04x", Adapter->TxAntennaMode) + 1;
+}
+
+/** 
+ *  @brief Set Radio On/OFF
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @option 			Radio Option
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+wlan_radio_ioctl(wlan_private * priv, u8 option)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->RadioOn != option) {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            PRINTM(MSG, "Cannot turn radio off in connected state.\n");
+            LEAVE();
+            return -EINVAL;
+        }
+
+        PRINTM(INFO, "Switching %s the Radio\n", option ? "On" : "Off");
+        Adapter->RadioOn = option;
+
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_RADIO_CONTROL,
+                                    HostCmd_ACT_GEN_SET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, NULL);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+#ifdef REASSOCIATION
+/** 
+ *  @brief Set Auto Reassociation On
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+reassociation_on(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    Adapter->Reassoc_on = TRUE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Auto Reassociation Off
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+reassociation_off(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        CancelTimer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+
+    Adapter->Reassoc_on = FALSE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+#endif /* REASSOCIATION */
+
+/** 
+ *  @brief Set Region
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param region_code		region code
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+wlan_set_region(wlan_private * priv, u16 region_code)
+{
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+        // use the region code to search for the index
+        if (region_code == RegionCodeToIndex[i]) {
+            priv->adapter->RegionCode = region_code;
+            break;
+        }
+    }
+
+    // if it's unidentified region code
+    if (i >= MRVDRV_MAX_REGION_CODE) {
+        PRINTM(INFO, "Region Code not identified\n");
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    if (wlan_set_regiontable(priv, priv->adapter->RegionCode, 0)) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Copy Rates
+ *   
+ *  @param dest                 A pointer to Dest Buf
+ *  @param src		        A pointer to Src Buf
+ *  @param len                  The len of Src Buf
+ *  @return 	   	        Number of Rates copyed 
+ */
+static inline int
+CopyRates(u8 * dest, int pos, u8 * src, int len)
+{
+    int i;
+
+    for (i = 0; i < len && src[i]; i++, pos++) {
+        if (pos >= sizeof(WLAN_802_11_RATES))
+            break;
+        dest[pos] = src[i];
+    }
+
+    return pos;
+}
+
+/** 
+ *  @brief Get active data rates
+ *   
+ *  @param Adapter          A pointer to wlan_adapter structure
+ *  @param rate             The buf to return the active rates
+ *  @return                 The number of Rates
+ */
+static int
+get_active_data_rates(wlan_adapter * Adapter, WLAN_802_11_RATES rates)
+{
+    int k = 0;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus != WlanMediaStateConnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            //Infra. mode
+            PRINTM(INFO, "Infra\n");
+            k = CopyRates(rates, k, SupportedRates, sizeof(SupportedRates));
+        } else {
+            //ad-hoc mode
+            PRINTM(INFO, "Adhoc G\n");
+            k = CopyRates(rates, k, AdhocRates_G, sizeof(AdhocRates_G));
+        }
+    } else {
+        k = CopyRates(rates, 0, Adapter->CurBssParams.DataRates,
+                      Adapter->CurBssParams.NumOfRates);
+    }
+
+    LEAVE();
+
+    return k;
+}
+
+/** 
+ *  @brief Get/Set Per packet TX Control flags
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to user data
+ *  @return         WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[3];
+    int ret;
+
+    ENTER();
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    switch (wrq->u.data.length) {
+    case 0:
+        /*
+         *  Get the Global setting for TxCtrl 
+         */
+        if (copy_to_user(wrq->u.data.pointer,
+                         &Adapter->PktTxCtrl, sizeof(u32))) {
+            PRINTM(INFO, "copy_to_user failed!\n");
+            ret = -EFAULT;
+        } else {
+            wrq->u.data.length = 1;
+        }
+        break;
+
+    case 1:
+        /*
+         *  Set the Global setting for TxCtrl
+         */
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+        } else {
+            Adapter->PktTxCtrl = data[0];
+            PRINTM(INFO, "PktTxCtrl set: 0x%08x\n", Adapter->PktTxCtrl);
+        }
+        break;
+
+    case 2:
+        /*
+         *  Get the per User Priority setting for TxCtrl for the given UP
+         */
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * 2)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+
+        } else if (data[1] >= NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
+            /* Range check the UP input from user space */
+            PRINTM(INFO, "User priority out of range\n");
+            ret = -EINVAL;
+
+        } else if (Adapter->wmm.userPriPktTxCtrl[data[1]]) {
+            data[2] = Adapter->wmm.userPriPktTxCtrl[data[1]];
+
+            /* User priority setting is valid, return it */
+            if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
+                PRINTM(INFO, "copy_to_user failed!\n");
+                ret = -EFAULT;
+            } else {
+                wrq->u.data.length = 3;
+            }
+
+        } else {
+            /* Return the global setting since the UP set is zero */
+            data[2] = Adapter->PktTxCtrl;
+
+            if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
+                PRINTM(INFO, "copy_to_user failed!\n");
+                ret = -EFAULT;
+            } else {
+                wrq->u.data.length = 3;
+            }
+        }
+        break;
+
+    case 3:
+        /*
+         *  Set the per User Priority setting for TxCtrl for the given UP
+         */
+
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * 3)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+        } else if (data[1] >= NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
+            PRINTM(INFO, "User priority out of range\n");
+            ret = -EINVAL;
+        } else {
+            Adapter->wmm.userPriPktTxCtrl[data[1]] = data[2];
+
+            if (Adapter->wmm.userPriPktTxCtrl[data[1]] == 0) {
+                /* Return the global setting since the UP set is zero */
+                data[2] = Adapter->PktTxCtrl;
+            }
+
+            if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
+                PRINTM(INFO, "copy_to_user failed!\n");
+                ret = -EFAULT;
+            } else {
+                wrq->u.data.length = 3;
+            }
+        }
+        break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Enable/Disable atim uapsd null package generation
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_null_pkg_gen(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    wlan_adapter *Adapter = priv->adapter;
+    int *val;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    PRINTM(INFO, "Enable UAPSD NULL PKG: %s\n",
+           (data == CMD_ENABLED) ? "Enable" : "Disable");
+    switch (data) {
+    case CMD_ENABLED:
+        Adapter->gen_null_pkg = TRUE;
+        break;
+    case CMD_DISABLED:
+        Adapter->gen_null_pkg = FALSE;
+        break;
+    default:
+        break;
+    }
+
+    data = (Adapter->gen_null_pkg == TRUE) ? CMD_ENABLED : CMD_DISABLED;
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set NULL Package generation interval
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+    ENTER();
+
+    if ((int) wrq->u.data.length == 0) {
+        data = Adapter->NullPktInterval;
+
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(MSG, "copy_to_user failed!\n");
+            return -EFAULT;
+        }
+    } else {
+        if ((int) wrq->u.data.length > 1) {
+            PRINTM(MSG, "ioctl too many args!\n");
+            return -EFAULT;
+        }
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        Adapter->NullPktInterval = data;
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Adhoc awake period 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_adhoc_awake_period(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+    ENTER();
+
+    if ((int) wrq->u.data.length == 0) {
+        data = Adapter->AdhocAwakePeriod;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(MSG, "copy_to_user failed!\n");
+            return -EFAULT;
+        }
+    } else {
+        if ((int) wrq->u.data.length > 1) {
+            PRINTM(MSG, "ioctl too many args!\n");
+            return -EFAULT;
+        }
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+#define AWAKE_PERIOD_MIN 1
+#define AWAKE_PERIOD_MAX 31
+#define DISABLE_AWAKE_PERIOD 0xff
+        if ((((data & 0xff) >= AWAKE_PERIOD_MIN) &&
+             ((data & 0xff) <= AWAKE_PERIOD_MAX)) ||
+            ((data & 0xff) == DISABLE_AWAKE_PERIOD))
+            Adapter->AdhocAwakePeriod = (u16) data;
+        else {
+            PRINTM(INFO,
+                   "Invalid parameter, AdhocAwakePeriod not changed.\n");
+            return -EINVAL;
+
+        }
+    }
+    wrq->u.data.length = 1;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set bcn missing timeout 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_bcn_miss_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+    ENTER();
+
+    if ((int) wrq->u.data.length == 0) {
+        data = Adapter->BCNMissTimeOut;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(MSG, "copy_to_user failed!\n");
+            return -EFAULT;
+        }
+    } else {
+        if ((int) wrq->u.data.length > 1) {
+            PRINTM(MSG, "ioctl too many args!\n");
+            return -EFAULT;
+        }
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+        if (((data >= 0) && (data <= 50)) || (data == 0xffff))
+            Adapter->BCNMissTimeOut = (u16) data;
+        else {
+            PRINTM(INFO,
+                   "Invalid parameter, BCN Missing timeout not changed.\n");
+            return -EINVAL;
+
+        }
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set adhoc g proctection
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_adhoc_g_protection(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    int *val;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+#define ADHOC_G_PROTECTION_ON		1
+#define ADHOC_G_PROTECTION_OFF		0
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+    switch (data) {
+    case CMD_DISABLED:
+        Adapter->CurrentPacketFilter &=
+            ~HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+        break;
+    case CMD_ENABLED:
+        Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+        break;
+
+    case CMD_GET:
+        if (Adapter->
+            CurrentPacketFilter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)
+            data = ADHOC_G_PROTECTION_ON;
+        else
+            data = ADHOC_G_PROTECTION_OFF;
+        break;
+
+    default:
+        return -EINVAL;
+    }
+
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set LDO config
+ *  @param priv			A pointer to wlan_private structure
+ *  @param wrq			A pointer to wrq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_ldo_config(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_802_11_LDO_CONFIG ldocfg;
+    int data = 0;
+    u16 action;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0) {
+        action = HostCmd_ACT_GEN_GET;
+    } else if (wrq->u.data.length > 1) {
+        PRINTM(MSG, "ioctl too many args!\n");
+        ret = -EFAULT;
+        goto ldoexit;
+    } else {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+            goto ldoexit;
+        }
+        if (data != LDO_INTERNAL && data != LDO_EXTERNAL) {
+            PRINTM(MSG, "Invalid parameter, LDO config not changed.\n");
+            ret = -EFAULT;
+            goto ldoexit;
+        }
+        action = HostCmd_ACT_GEN_SET;
+    }
+    ldocfg.Action = action;
+    ldocfg.PMSource = (u16) data;
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_LDO_CONFIG,
+                                action, HostCmd_OPTION_WAITFORRSP,
+                                0, (void *) &ldocfg);
+
+    if (!ret && action == HostCmd_ACT_GEN_GET) {
+        data = (int) ldocfg.PMSource;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+            goto ldoexit;
+        }
+        wrq->u.data.length = 1;
+    }
+
+  ldoexit:
+    LEAVE();
+    return ret;
+}
+
+#ifdef DEBUG_LEVEL1
+/** 
+ *  @brief Get/Set the bit mask of driver debug message control
+ *  @param priv			A pointer to wlan_private structure
+ *  @param wrq			A pointer to wrq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_drv_dbg(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[4];
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0) {
+        data[0] = drvdbg;
+        data[1] = ifdbg;
+        /* Return the current driver debug bit masks */
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+            goto drvdbgexit;
+        }
+        wrq->u.data.length = 2;
+    } else if (wrq->u.data.length < 3) {
+        /* Get the driver debug bit masks */
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+            goto drvdbgexit;
+        }
+        drvdbg = data[0];
+        if (wrq->u.data.length == 2)
+            ifdbg = data[1];
+    } else {
+        PRINTM(INFO, "Invalid parameter number\n");
+        goto drvdbgexit;
+    }
+
+    printk(KERN_ALERT "drvdbg = 0x%x\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+    printk(KERN_ALERT "INFO  (%08x) %s\n", DBG_INFO,
+           (drvdbg & DBG_INFO) ? "X" : "");
+    printk(KERN_ALERT "WARN  (%08x) %s\n", DBG_WARN,
+           (drvdbg & DBG_WARN) ? "X" : "");
+    printk(KERN_ALERT "ENTRY (%08x) %s\n", DBG_ENTRY,
+           (drvdbg & DBG_ENTRY) ? "X" : "");
+#endif
+    printk(KERN_ALERT "FW_D  (%08x) %s\n", DBG_FW_D,
+           (drvdbg & DBG_FW_D) ? "X" : "");
+    printk(KERN_ALERT "CMD_D (%08x) %s\n", DBG_CMD_D,
+           (drvdbg & DBG_CMD_D) ? "X" : "");
+    printk(KERN_ALERT "DAT_D (%08x) %s\n", DBG_DAT_D,
+           (drvdbg & DBG_DAT_D) ? "X" : "");
+    printk(KERN_ALERT "INTR  (%08x) %s\n", DBG_INTR,
+           (drvdbg & DBG_INTR) ? "X" : "");
+    printk(KERN_ALERT "EVENT (%08x) %s\n", DBG_EVENT,
+           (drvdbg & DBG_EVENT) ? "X" : "");
+    printk(KERN_ALERT "CMND  (%08x) %s\n", DBG_CMND,
+           (drvdbg & DBG_CMND) ? "X" : "");
+    printk(KERN_ALERT "DATA  (%08x) %s\n", DBG_DATA,
+           (drvdbg & DBG_DATA) ? "X" : "");
+    printk(KERN_ALERT "ERROR (%08x) %s\n", DBG_ERROR,
+           (drvdbg & DBG_ERROR) ? "X" : "");
+    printk(KERN_ALERT "FATAL (%08x) %s\n", DBG_FATAL,
+           (drvdbg & DBG_FATAL) ? "X" : "");
+    printk(KERN_ALERT "MSG   (%08x) %s\n", DBG_MSG,
+           (drvdbg & DBG_MSG) ? "X" : "");
+    printk(KERN_ALERT "ifdbg = 0x%x\n", ifdbg);
+    printk(KERN_ALERT "IF_D  (%08x) %s\n", DBG_IF_D,
+           (ifdbg & DBG_IF_D) ? "X" : "");
+
+  drvdbgexit:
+    LEAVE();
+    return ret;
+}
+#endif
+
+/** 
+ *  @brief Commit handler: called after a bunch of SET operations
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_config_commit(struct net_device *dev,
+                   struct iw_request_info *info, char *cwrq, char *extra)
+{
+    ENTER();
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get protocol name 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+              char *cwrq, char *extra)
+{
+    const char *cp;
+    char comm[6] = { "COMM-" };
+    char mrvl[6] = { "MRVL-" };
+    int cnt;
+
+    ENTER();
+
+    strcpy(cwrq, mrvl);
+
+    cp = strstr(driver_version, comm);
+    if (cp == driver_version)   //skip leading "COMM-"
+        cp = driver_version + strlen(comm);
+    else
+        cp = driver_version;
+
+    cnt = strlen(mrvl);
+    cwrq += cnt;
+    while (cnt < 16 && (*cp != '-')) {
+        *cwrq++ = toupper(*cp++);
+        cnt++;
+    }
+    *cwrq = '\0';
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get frequency
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param fwrq 		A pointer to iw_freq structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+              struct iw_freq *fwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    CHANNEL_FREQ_POWER *cfp;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    cfp = find_cfp_by_band_and_channel(Adapter, 0,
+                                       (u16) Adapter->CurBssParams.
+                                       BSSDescriptor.Channel);
+
+    if (!cfp) {
+        if (Adapter->CurBssParams.BSSDescriptor.Channel) {
+            PRINTM(INFO, "Invalid channel=%d\n",
+                   Adapter->CurBssParams.BSSDescriptor.Channel);
+        }
+        return -EINVAL;
+    }
+
+    fwrq->m = (long) cfp->Freq * 100000;
+    fwrq->e = 1;
+
+    PRINTM(INFO, "freq=%u\n", fwrq->m);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get current BSSID
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param awrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+             struct sockaddr *awrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        memcpy(awrq->sa_data,
+               Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+    } else {
+        memset(awrq->sa_data, 0, ETH_ALEN);
+    }
+    awrq->sa_family = ARPHRD_ETHER;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Adapter Node Name
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /*
+     * Check the size of the string 
+     */
+
+    if (dwrq->length > 16) {
+        return -E2BIG;
+    }
+
+    memset(Adapter->nodeName, 0, sizeof(Adapter->nodeName));
+    memcpy(Adapter->nodeName, extra, dwrq->length);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Adapter Node Name
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /*
+     * Get the Nick Name saved 
+     */
+
+    strncpy(extra, Adapter->nodeName, 16);
+
+    extra[16] = '\0';
+
+    /*
+     * If none, we may want to get the one that was set 
+     */
+
+    /*
+     * Push it out ! 
+     */
+    dwrq->length = strlen(extra) + 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set RTS threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+             struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int rthr = vwrq->value;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (vwrq->disabled) {
+        Adapter->RTSThsd = rthr = MRVDRV_RTS_MAX_VALUE;
+    } else {
+        if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
+            return -EINVAL;
+        Adapter->RTSThsd = rthr;
+    }
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                                HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP,
+                                OID_802_11_RTS_THRESHOLD, &rthr);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get RTS threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+             struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    Adapter->RTSThsd = 0;
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                                HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP,
+                                OID_802_11_RTS_THRESHOLD, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    vwrq->value = Adapter->RTSThsd;
+    vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+                      || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+    vwrq->fixed = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Fragment threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    int fthr = vwrq->value;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (vwrq->disabled) {
+        Adapter->FragThsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+    } else {
+        if (fthr < MRVDRV_FRAG_MIN_VALUE || fthr > MRVDRV_FRAG_MAX_VALUE)
+            return -EINVAL;
+        Adapter->FragThsd = fthr;
+    }
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                                HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP,
+                                OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get Fragment threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    Adapter->FragThsd = 0;
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GET,
+                                HostCmd_OPTION_WAITFORRSP,
+                                OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    vwrq->value = Adapter->FragThsd;
+    vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+                      || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+    vwrq->fixed = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get Wlan Mode
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_mode(struct net_device *dev,
+              struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    switch (adapter->InfrastructureMode) {
+    case Wlan802_11IBSS:
+        *uwrq = IW_MODE_ADHOC;
+        break;
+
+    case Wlan802_11Infrastructure:
+        *uwrq = IW_MODE_INFRA;
+        break;
+
+    default:
+    case Wlan802_11AutoUnknown:
+        *uwrq = IW_MODE_AUTO;
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Encryption key
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_encode(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, u8 * extra)
+{
+
+    wlan_private *priv = dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+    int index = (dwrq->flags & IW_ENCODE_INDEX);
+
+    ENTER();
+
+    PRINTM(INFO, "flags=0x%x index=%d length=%d CurrentWepKeyIndex=%d\n",
+           dwrq->flags, index, dwrq->length, adapter->CurrentWepKeyIndex);
+    if (index < 0 || index > 4) {
+        PRINTM(INFO, "Key index #%d out of range.\n", index);
+        LEAVE();
+        return -EINVAL;
+    }
+    if (adapter->CurrentWepKeyIndex >= MRVL_NUM_WEP_KEY)
+        adapter->CurrentWepKeyIndex = 0;
+    dwrq->flags = 0;
+
+    /*
+     * Check encryption mode 
+     */
+
+    switch (adapter->SecInfo.AuthenticationMode) {
+    case Wlan802_11AuthModeOpen:
+        dwrq->flags = IW_ENCODE_OPEN;
+        break;
+
+    case Wlan802_11AuthModeShared:
+    case Wlan802_11AuthModeNetworkEAP:
+        dwrq->flags = IW_ENCODE_RESTRICTED;
+        break;
+    default:
+        dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+        break;
+    }
+
+    if ((adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)
+        || (adapter->SecInfo.WEPStatus == Wlan802_11WEPKeyAbsent)
+        || adapter->SecInfo.WPAEnabled || adapter->SecInfo.WPA2Enabled) {
+        dwrq->flags &= ~IW_ENCODE_DISABLED;
+    } else {
+        dwrq->flags |= IW_ENCODE_DISABLED;
+    }
+
+    memset(extra, 0, 16);
+
+    if (!index) {
+        /* Handle current key request   */
+        if ((adapter->WepKey[adapter->CurrentWepKeyIndex].KeyLength) &&
+            (adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)) {
+            index = adapter->WepKey[adapter->CurrentWepKeyIndex].KeyIndex;
+            memcpy(extra, adapter->WepKey[index].KeyMaterial,
+                   adapter->WepKey[index].KeyLength);
+            dwrq->length = adapter->WepKey[index].KeyLength;
+            /* return current key */
+            dwrq->flags |= (index + 1);
+            /* return WEP enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else if ((adapter->SecInfo.WPAEnabled)
+                   || (adapter->SecInfo.WPA2Enabled)
+            ) {
+            /* return WPA enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else {
+            dwrq->flags |= IW_ENCODE_DISABLED;
+        }
+    } else {
+        /* Handle specific key requests */
+        index--;
+        if (adapter->WepKey[index].KeyLength) {
+            memcpy(extra, adapter->WepKey[index].KeyMaterial,
+                   adapter->WepKey[index].KeyLength);
+            dwrq->length = adapter->WepKey[index].KeyLength;
+            /* return current key */
+            dwrq->flags |= (index + 1);
+            /* return WEP enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else if ((adapter->SecInfo.WPAEnabled)
+                   || (adapter->SecInfo.WPA2Enabled)
+            ) {
+            /* return WPA enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else {
+            dwrq->flags |= IW_ENCODE_DISABLED;
+        }
+    }
+
+    dwrq->flags |= IW_ENCODE_NOKEY;
+
+    PRINTM(INFO, "Key:%02x:%02x:%02x:%02x:%02x:%02x KeyLen=%d\n",
+           extra[0], extra[1], extra[2],
+           extra[3], extra[4], extra[5], dwrq->length);
+
+    PRINTM(INFO, "Return flags=0x%x\n", dwrq->flags);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get TX Power
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_txpow(struct net_device *dev,
+               struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_RF_TX_POWER,
+                                HostCmd_ACT_GEN_GET,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    PRINTM(INFO, "TXPOWER GET %d dbm.\n", Adapter->TxPowerLevel);
+    vwrq->value = Adapter->TxPowerLevel;
+    vwrq->fixed = 1;
+    if (Adapter->RadioOn) {
+        vwrq->disabled = 0;
+        vwrq->flags = IW_TXPOW_DBM;
+    } else {
+        vwrq->disabled = 1;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set TX Retry Count
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (vwrq->flags == IW_RETRY_LIMIT) {
+        /* The MAC has a 4-bit Total_Tx_Count register
+           Total_Tx_Count = 1 + Tx_Retry_Count */
+#define TX_RETRY_MIN 0
+#define TX_RETRY_MAX 14
+        if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+            return -EINVAL;
+
+        /* Set Tx retry count */
+        adapter->TxRetryCount = vwrq->value;
+
+        ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                                    HostCmd_ACT_SET,
+                                    HostCmd_OPTION_WAITFORRSP,
+                                    OID_802_11_TX_RETRYCOUNT, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    } else {
+        return -EOPNOTSUPP;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get TX Retry Count
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    Adapter->TxRetryCount = 0;
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GET,
+                                HostCmd_OPTION_WAITFORRSP,
+                                OID_802_11_TX_RETRYCOUNT, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+    vwrq->disabled = 0;
+    if (!vwrq->flags) {
+        vwrq->flags = IW_RETRY_LIMIT;
+        /* Subtract 1 to convert try count to retry count */
+        vwrq->value = Adapter->TxRetryCount - 1;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Sort Channels
+ *   
+ *  @param freq 		A pointer to iw_freq structure
+ *  @param num		        number of Channels
+ *  @return 	   		NA
+ */
+static inline void
+sort_channels(struct iw_freq *freq, int num)
+{
+    int i, j;
+    struct iw_freq temp;
+
+    for (i = 0; i < num; i++)
+        for (j = i + 1; j < num; j++)
+            if (freq[i].i > freq[j].i) {
+                temp.i = freq[i].i;
+                temp.m = freq[i].m;
+
+                freq[i].i = freq[j].i;
+                freq[i].m = freq[j].m;
+
+                freq[j].i = temp.i;
+                freq[j].m = temp.m;
+            }
+}
+
+/* data rate listing
+	MULTI_BANDS:
+		abg		a	b	b/g
+   Infra 	G(12)		A(8)	B(4)	G(12)
+   Adhoc 	A+B(12)		A(8)	B(4)	B(4)
+
+	non-MULTI_BANDS:
+		   		 	b	b/g
+   Infra 	     		    	B(4)	G(12)
+   Adhoc 	      		    	B(4)	B(4)
+ */
+/** 
+ *  @brief Get Range Info
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *dwrq, char *extra)
+{
+    int i, j;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct iw_range *range = (struct iw_range *) extra;
+    CHANNEL_FREQ_POWER *cfp;
+    WLAN_802_11_RATES rates;
+
+    ENTER();
+
+    dwrq->length = sizeof(struct iw_range);
+    memset(range, 0, sizeof(struct iw_range));
+
+    range->min_nwid = 0;
+    range->max_nwid = 0;
+
+    memset(rates, 0, sizeof(rates));
+    range->num_bitrates = get_active_data_rates(Adapter, rates);
+    if (range->num_bitrates > sizeof(rates))
+        range->num_bitrates = sizeof(rates);
+
+    for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+         i++) {
+        range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+    }
+    range->num_bitrates = i;
+    PRINTM(INFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+           range->num_bitrates);
+
+    range->num_frequency = 0;
+    if (wlan_get_state_11d(priv) == ENABLE_11D &&
+        Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        u8 chan_no;
+        u8 band;
+
+        parsed_region_chan_11d_t *parsed_region_chan =
+            &Adapter->parsed_region_chan;
+
+        band = parsed_region_chan->band;
+        PRINTM(INFO, "band=%d NoOfChan=%d\n", band,
+               parsed_region_chan->NoOfChan);
+
+        for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+             && (i < parsed_region_chan->NoOfChan); i++) {
+            chan_no = parsed_region_chan->chanPwr[i].chan;
+            PRINTM(INFO, "chan_no=%d\n", chan_no);
+            range->freq[range->num_frequency].i = (long) chan_no;
+            range->freq[range->num_frequency].m =
+                (long) chan_2_freq(chan_no, band) * 100000;
+            range->freq[range->num_frequency].e = 1;
+            range->num_frequency++;
+        }
+    } else {
+        for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+             && (j < sizeof(Adapter->region_channel)
+                 / sizeof(Adapter->region_channel[0])); j++) {
+            cfp = Adapter->region_channel[j].CFP;
+            for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+                 && Adapter->region_channel[j].Valid
+                 && cfp && (i < Adapter->region_channel[j].NrCFP); i++) {
+                range->freq[range->num_frequency].i = (long) cfp->Channel;
+                range->freq[range->num_frequency].m =
+                    (long) cfp->Freq * 100000;
+                range->freq[range->num_frequency].e = 1;
+                cfp++;
+                range->num_frequency++;
+            }
+        }
+    }
+
+    PRINTM(INFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+           IW_MAX_FREQUENCIES, range->num_frequency);
+
+    range->num_channels = range->num_frequency;
+
+    sort_channels(&range->freq[0], range->num_frequency);
+
+    /*
+     * Set an indication of the max TCP throughput in bit/s that we can
+     * expect using this interface 
+     */
+    if (i > 2)
+        range->throughput = 5000 * 1000;
+    else
+        range->throughput = 1500 * 1000;
+
+    range->min_rts = MRVDRV_RTS_MIN_VALUE;
+    range->max_rts = MRVDRV_RTS_MAX_VALUE;
+    range->min_frag = MRVDRV_FRAG_MIN_VALUE;
+    range->max_frag = MRVDRV_FRAG_MAX_VALUE;
+
+    range->encoding_size[0] = 5;
+    range->encoding_size[1] = 13;
+    range->num_encoding_sizes = 2;
+    range->max_encoding_tokens = 4;
+
+#define IW_POWER_PERIOD_MIN 1000000     /* 1 sec */
+#define IW_POWER_PERIOD_MAX 120000000   /* 2 min */
+#define IW_POWER_TIMEOUT_MIN 1000       /* 1 ms  */
+#define IW_POWER_TIMEOUT_MAX 1000000    /* 1 sec */
+
+    /* Power Management duration & timeout */
+    range->min_pmp = IW_POWER_PERIOD_MIN;
+    range->max_pmp = IW_POWER_PERIOD_MAX;
+    range->min_pmt = IW_POWER_TIMEOUT_MIN;
+    range->max_pmt = IW_POWER_TIMEOUT_MAX;
+    range->pmp_flags = IW_POWER_PERIOD;
+    range->pmt_flags = IW_POWER_TIMEOUT;
+    range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+    /*
+     * Minimum version we recommend 
+     */
+    range->we_version_source = 15;
+
+    /*
+     * Version we are compiled with 
+     */
+    range->we_version_compiled = WIRELESS_EXT;
+
+    range->retry_capa = IW_RETRY_LIMIT;
+    range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+    range->min_retry = TX_RETRY_MIN;
+    range->max_retry = TX_RETRY_MAX;
+
+    /*
+     * Set the qual, level and noise range values 
+     */
+    /*
+     * need to put the right values here 
+     */
+#define IW_MAX_QUAL_PERCENT 100
+#define IW_AVG_QUAL_PERCENT 70
+    range->max_qual.qual = IW_MAX_QUAL_PERCENT;
+    range->max_qual.level = 0;
+    range->max_qual.noise = 0;
+
+    range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
+    range->avg_qual.level = 0;
+    range->avg_qual.noise = 0;
+
+    range->sensitivity = 0;
+    /*
+     * Setup the supported power level ranges 
+     */
+    memset(range->txpower, 0, sizeof(range->txpower));
+    range->txpower[0] = Adapter->MinTxPowerLevel;
+    range->txpower[1] = Adapter->MaxTxPowerLevel;
+    range->num_txpower = 2;
+    range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+
+	if (FW_IS_WPA_ENABLED(Adapter)) {
+		range->enc_capa = IW_ENC_CAPA_WPA
+			| IW_ENC_CAPA_WPA2
+			| IW_ENC_CAPA_CIPHER_TKIP
+			| IW_ENC_CAPA_CIPHER_CCMP;
+	}
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Set power management 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    /* PS is currently supported only in Infrastructure Mode 
+     * Remove this check if it is to be supported in IBSS mode also 
+     */
+
+    if (vwrq->disabled) {
+        Adapter->PSMode = Wlan802_11PowerModeCAM;
+        if (Adapter->PSState != PS_STATE_FULL_POWER) {
+            PSWakeup(priv, HostCmd_OPTION_WAITFORRSP);
+        }
+
+        return 0;
+    }
+
+    if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+        PRINTM(INFO, "Setting power timeout command is not supported\n");
+        return -EINVAL;
+    } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+        PRINTM(INFO, "Setting power period command is not supported\n");
+        return -EINVAL;
+    }
+
+    if (Adapter->PSMode != Wlan802_11PowerModeCAM) {
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    Adapter->PSMode = Wlan802_11PowerModeMAX_PSP;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        PSSleep(priv, HostCmd_OPTION_WAITFORRSP);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Get power management 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int mode;
+
+    ENTER();
+
+    mode = Adapter->PSMode;
+
+    if ((vwrq->disabled = (mode == Wlan802_11PowerModeCAM))
+        || Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    vwrq->value = 0;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Set sensitivity threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_sens(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    ENTER();
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Get sensitivity threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_FAILURE
+ */
+static int
+wlan_get_sens(struct net_device *dev,
+              struct iw_request_info *info, struct iw_param *vwrq,
+              char *extra)
+{
+    ENTER();
+    LEAVE();
+    return WLAN_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief  Append/Reset IE buffer. 
+ *   
+ *  Pass an opaque block of data, expected to be IEEE IEs, to the driver 
+ *    for eventual passthrough to the firmware in an associate/join 
+ *    (and potentially start) command.  This function is the main body
+ *    for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
+ *
+ *  Data is appended to an existing buffer and then wrapped in a passthrough
+ *    TLV in the command API to the firmware.  The firmware treats the data
+ *    as a transparent passthrough to the transmitted management frame.
+ *
+ *  @param Adapter      A pointer to wlan_private structure
+ *  @param ie_data_ptr  A pointer to iwreq structure
+ *  @param ie_len       Length of the IE or IE block passed in ie_data_ptr
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie_helper(wlan_private * priv, u8 * ie_data_ptr, u16 ie_len)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    IEEEtypes_VendorHeader_t *pVendorIe;
+    const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+    const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+    /* If the passed length is zero, reset the buffer */
+    if (ie_len == 0) {
+        Adapter->genIeBufferLen = 0;
+
+    } else if (ie_data_ptr == NULL) {
+        /* NULL check */
+        ret = -EINVAL;
+    } else {
+
+        pVendorIe = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+
+        /* Test to see if it is a WPA IE, if not, then it is a gen IE */
+        if ((pVendorIe->ElementId == RSN_IE)
+            || ((pVendorIe->ElementId == WPA_IE)
+                && (pVendorIe->OuiType == wpa_oui[3])
+                && (memcmp(pVendorIe->Oui, wpa_oui, sizeof(pVendorIe->Oui)) ==
+                    0))) {
+
+            /* IE is a WPA/WPA2 IE so call set_wpa function */
+            ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+        } else if ((pVendorIe->ElementId == WPS_IE)
+                   && (memcmp(pVendorIe->Oui, wps_oui, sizeof(pVendorIe->Oui))
+                       == 0)
+                   && (pVendorIe->OuiType == wps_oui[3])) {
+            /*
+             * Discard first two byte (Element ID and Length)
+             * because they are not needed in the case of setting WPS_IE
+             */
+            if (pVendorIe->Len > 4) {
+                memcpy((u8 *) & Adapter->wps.wpsIe, ie_data_ptr, ie_len);
+                HEXDUMP("wpsIe",
+                        (u8 *) & Adapter->wps.wpsIe,
+                        Adapter->wps.wpsIe.VendHdr.Len + 2);
+
+            } else {
+                /* Only wps oui exist, reset driver wps buffer */
+                memset((u8 *) & Adapter->wps.wpsIe,
+                       0x00, sizeof(Adapter->wps.wpsIe));
+                PRINTM(INFO, "wpsIe cleared\n");
+            }
+        } else {
+            /* 
+             * Verify that the passed length is not larger than the available 
+             *   space remaining in the buffer
+             */
+            if (ie_len < (sizeof(Adapter->genIeBuffer)
+                          - Adapter->genIeBufferLen)) {
+
+                /* Append the passed data to the end of the genIeBuffer */
+                if (copy_from_user((Adapter->genIeBuffer
+                                    + Adapter->genIeBufferLen),
+                                   ie_data_ptr, ie_len)) {
+                    PRINTM(INFO, "Copy from user failed\n");
+                    ret = -EFAULT;
+
+                } else {
+                    /* Increment the stored buffer length by the size passed */
+                    Adapter->genIeBufferLen += ie_len;
+                }
+
+            } else {
+                /* Passed data does not fit in the remaining buffer space */
+                ret = WLAN_STATUS_FAILURE;
+            }
+        }
+    }
+
+    /* Return WLAN_STATUS_SUCCESS, or < 0 for error case */
+    return ret;
+}
+
+/** 
+ *  @brief  Get IE buffer from driver 
+ *   
+ *  Used to pass an opaque block of data, expected to be IEEE IEs,
+ *    back to the application.  Currently the data block passed
+ *    back to the application is the saved association response retrieved 
+ *    from the firmware.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param ie_data_ptr  A pointer to the IE or IE block
+ *  @param ie_len_ptr   In/Out parameter pointer for the buffer length passed 
+ *                      in ie_data_ptr and the resulting data length copied
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_gen_ie_helper(wlan_private * priv,
+                       u8 * ie_data_ptr, u16 * ie_len_ptr)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    IEEEtypes_AssocRsp_t *pAssocRsp;
+    int copySize;
+
+    pAssocRsp = (IEEEtypes_AssocRsp_t *) Adapter->assocRspBuffer;
+
+    /*
+     * Set the amount to copy back to the application as the minimum of the 
+     *   available IE data or the buffer provided by the application
+     */
+    copySize = (Adapter->assocRspSize - sizeof(pAssocRsp->Capability) -
+                -sizeof(pAssocRsp->StatusCode) - sizeof(pAssocRsp->AId));
+    copySize = MIN(copySize, *ie_len_ptr);
+
+    /* Copy the IEEE TLVs in the assoc response back to the application */
+    if (copy_to_user(ie_data_ptr, (u8 *) pAssocRsp->IEBuffer, copySize)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    /* Returned copy length */
+    *ie_len_ptr = copySize;
+
+    /* No error on return */
+    return WLAN_STATUS_SUCCESS;
+}
+
+#if (WIRELESS_EXT >= 18)
+/** 
+ *  @brief  Set IE 
+ *
+ *  Calls main function set_gen_ie_fuct that adds the inputted IE
+ *    to the genie buffer
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, char *extra)
+{
+    return wlan_set_gen_ie_helper(dev->priv, dwrq->pointer, dwrq->length);
+}
+
+/** 
+ *  @brief  Get IE 
+ *
+ *  Calls main function get_gen_ie_fuct that retrieves expected IEEE IEs
+ *    and places then in the iw_point structure
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_gen_ie(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, char *extra)
+{
+    return wlan_get_gen_ie_helper(dev->priv, dwrq->pointer, &dwrq->length);
+}
+
+/** 
+ *  @brief Set authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setauthalg(wlan_private * priv, int alg)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "auth alg is %#x\n", alg);
+
+    switch (alg) {
+    case IW_AUTH_ALG_SHARED_KEY:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
+        break;
+    case IW_AUTH_ALG_LEAP:
+        //clear WPA IE
+        wlan_set_wpa_ie_helper(priv, NULL, 0);
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeNetworkEAP;
+        break;
+    case IW_AUTH_ALG_OPEN_SYSTEM:
+    default:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief set authentication mode params
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_auth(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+    switch (vwrq->flags & IW_AUTH_INDEX) {
+    case IW_AUTH_CIPHER_PAIRWISE:
+    case IW_AUTH_CIPHER_GROUP:
+        if (vwrq->value & IW_AUTH_CIPHER_NONE)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_NONE;
+        else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_WEP40;
+        else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_TKIP;
+        else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_CCMP;
+        else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_WEP104;
+        break;
+    case IW_AUTH_80211_AUTH_ALG:
+        wlan_setauthalg(priv, vwrq->value);
+        break;
+    case IW_AUTH_WPA_ENABLED:
+        if (vwrq->value == FALSE)
+            wlan_set_wpa_ie_helper(priv, NULL, 0);
+        break;
+    case IW_AUTH_WPA_VERSION:
+    case IW_AUTH_KEY_MGMT:
+    case IW_AUTH_TKIP_COUNTERMEASURES:
+    case IW_AUTH_DROP_UNENCRYPTED:
+    case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+    case IW_AUTH_ROAMING_CONTROL:
+    case IW_AUTH_PRIVACY_INVOKED:
+    default:
+        break;
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  get authentication mode params 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_auth(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    ENTER();
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+    switch (vwrq->flags & IW_AUTH_INDEX) {
+    case IW_AUTH_CIPHER_PAIRWISE:
+    case IW_AUTH_CIPHER_GROUP:
+        if (priv->adapter->SecInfo.EncryptionMode == CIPHER_NONE)
+            vwrq->value = IW_AUTH_CIPHER_NONE;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_WEP40)
+            vwrq->value = IW_AUTH_CIPHER_WEP40;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_TKIP)
+            vwrq->value = IW_AUTH_CIPHER_TKIP;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_CCMP)
+            vwrq->value = IW_AUTH_CIPHER_CCMP;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_WEP104)
+            vwrq->value = IW_AUTH_CIPHER_WEP104;
+        break;
+    case IW_AUTH_80211_AUTH_ALG:
+        if (Adapter->SecInfo.AuthenticationMode == Wlan802_11AuthModeShared)
+            vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+        else if (Adapter->SecInfo.AuthenticationMode ==
+                 Wlan802_11AuthModeNetworkEAP)
+            vwrq->value = IW_AUTH_ALG_LEAP;
+        else
+            vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+        break;
+    case IW_AUTH_WPA_ENABLED:
+        if (Adapter->Wpa_ie_len > 0)
+            vwrq->value = TRUE;
+        else
+            vwrq->value = FALSE;
+        break;
+    case IW_AUTH_WPA_VERSION:
+    case IW_AUTH_KEY_MGMT:
+    case IW_AUTH_TKIP_COUNTERMEASURES:
+    case IW_AUTH_DROP_UNENCRYPTED:
+    case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+    case IW_AUTH_ROAMING_CONTROL:
+    case IW_AUTH_PRIVACY_INVOKED:
+    default:
+        ret = -EOPNOTSUPP;
+        break;
+    }
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief  Request MLME operation 
+ *
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_mlme(struct net_device *dev,
+              struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    struct iw_mlme *mlme = (struct iw_mlme *) extra;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+    if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure &&
+            Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            SendDeauthentication(priv);
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS &&
+                   Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            StopAdhocNetwork(priv);
+        }
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Extended version of encoding configuration 
+ *
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode_ext(struct net_device *dev,
+                    struct iw_request_info *info,
+                    struct iw_point *dwrq, char *extra)
+{
+    struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+    wlan_private *priv = dev->priv;
+    WLAN_802_11_KEY *pkey;
+    int keyindex;
+    u8 *pKeyMaterial = NULL;
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+    keyindex = dwrq->flags & IW_ENCODE_INDEX;
+    if (keyindex > 4)
+        return -EINVAL;
+    if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext)))
+        return -EINVAL;
+    pKeyMaterial = (u8 *) (ext + 1);
+    //Disable Key
+    if ((dwrq->flags & IW_ENCODE_DISABLED) && (ext->key_len == 0)) {
+        dwrq->length = 0;
+        wlan_set_encode_nonwpa(dev, info, dwrq, extra);
+        return WLAN_STATUS_SUCCESS;
+    }
+    //Set WEP key
+    if (ext->key_len <= MAX_WEP_KEY_SIZE) {
+        dwrq->length = ext->key_len;
+        wlan_set_encode_nonwpa(dev, info, dwrq, pKeyMaterial);
+        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+            dwrq->length = 0;
+            wlan_set_encode_nonwpa(dev, info, dwrq, extra);
+        }
+    } else {
+        pkey = kmalloc(sizeof(WLAN_802_11_KEY) + ext->key_len, GFP_KERNEL);
+        if (!pkey) {
+            PRINTM(INFO, "allocate key buffer failed!\n");
+            return -ENOMEM;
+        }
+        memset(pkey, 0, sizeof(WLAN_802_11_KEY) + ext->key_len);
+        memcpy((u8 *) pkey->BSSID, (u8 *) ext->addr.sa_data, ETH_ALEN);
+        pkey->KeyLength = ext->key_len;
+        memcpy(pkey->KeyMaterial, pKeyMaterial, ext->key_len);
+        pkey->KeyIndex = keyindex - 1;
+        if (pkey->KeyIndex == 0)
+            pkey->KeyIndex = 0x40000000;
+        if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+            memcpy((u8 *) & pkey->KeyRSC, ext->rx_seq,
+                   IW_ENCODE_SEQ_MAX_SIZE);
+        pkey->Length = sizeof(WLAN_802_11_KEY) + ext->key_len;
+        wlan_set_encode_wpa(dev, info, dwrq, (u8 *) pkey);
+        kfree(pkey);
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Extended version of encoding configuration 
+ *
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_encode_ext(struct net_device *dev,
+                    struct iw_request_info *info,
+                    struct iw_point *dwrq, char *extra)
+{
+    return -EOPNOTSUPP;
+}
+#endif /* #if (WIRELESS_EXT >= 18) */
+
+/** 
+ *  @brief  Append/Reset IE buffer. 
+ *   
+ *  Pass an opaque block of data, expected to be IEEE IEs, to the driver 
+ *    for eventual passthrough to the firmware in an associate/join 
+ *    (and potentially start) command.
+ *
+ *  Data is appended to an existing buffer and then wrapped in a passthrough
+ *    TLV in the command API to the firmware.  The firmware treats the data
+ *    as a transparent passthrough to the transmitted management frame.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure    
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    return wlan_set_gen_ie_helper(priv,
+                                  wrq->u.data.pointer, wrq->u.data.length);
+}
+
+/** 
+ *  @brief  Get IE buffer from driver 
+ *   
+ *  Used to pass an opaque block of data, expected to be IEEE IEs,
+ *    back to the application.  Currently the data block passed
+ *    back to the application is the saved association response retrieved 
+ *    from the firmware.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_gen_ie_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    return wlan_get_gen_ie_helper(priv,
+                                  wrq->u.data.pointer, &wrq->u.data.length);
+}
+
+/*
+ * iwconfig settable callbacks 
+ */
+static const iw_handler wlan_handler[] = {
+    (iw_handler) wlan_config_commit,    /* SIOCSIWCOMMIT */
+    (iw_handler) wlan_get_name, /* SIOCGIWNAME */
+    (iw_handler) NULL,          /* SIOCSIWNWID */
+    (iw_handler) NULL,          /* SIOCGIWNWID */
+    (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
+    (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
+    (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
+    (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
+    (iw_handler) wlan_set_sens, /* SIOCSIWSENS */
+    (iw_handler) wlan_get_sens, /* SIOCGIWSENS */
+    (iw_handler) NULL,          /* SIOCSIWRANGE */
+    (iw_handler) wlan_get_range,        /* SIOCGIWRANGE */
+    (iw_handler) NULL,          /* SIOCSIWPRIV */
+    (iw_handler) NULL,          /* SIOCGIWPRIV */
+    (iw_handler) NULL,          /* SIOCSIWSTATS */
+    (iw_handler) NULL,          /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+    iw_handler_set_spy,         /* SIOCSIWSPY */
+    iw_handler_get_spy,         /* SIOCGIWSPY */
+    iw_handler_set_thrspy,      /* SIOCSIWTHRSPY */
+    iw_handler_get_thrspy,      /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+    (iw_handler) wlan_set_spy,  /* SIOCSIWSPY */
+    (iw_handler) wlan_get_spy,  /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+    (iw_handler) NULL,          /* SIOCSIWSPY */
+    (iw_handler) NULL,          /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) NULL,          /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+    (iw_handler) wlan_set_wap,  /* SIOCSIWAP */
+    (iw_handler) wlan_get_wap,  /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+    (iw_handler) wlan_set_mlme, /* SIOCSIWMLME  */
+#else
+    (iw_handler) NULL,          /* -- hole -- */
+#endif
+    //(iw_handler) wlan_get_aplist,         /* SIOCGIWAPLIST */
+    NULL,                       /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+    (iw_handler) wlan_set_scan, /* SIOCSIWSCAN */
+    (iw_handler) wlan_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+    (iw_handler) NULL,          /* SIOCSIWSCAN */
+    (iw_handler) NULL,          /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+    (iw_handler) wlan_set_essid,        /* SIOCSIWESSID */
+    (iw_handler) wlan_get_essid,        /* SIOCGIWESSID */
+    (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
+    (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
+    (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
+    (iw_handler) wlan_set_rts,  /* SIOCSIWRTS */
+    (iw_handler) wlan_get_rts,  /* SIOCGIWRTS */
+    (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
+    (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
+    (iw_handler) wlan_set_txpow,        /* SIOCSIWTXPOW */
+    (iw_handler) wlan_get_txpow,        /* SIOCGIWTXPOW */
+    (iw_handler) wlan_set_retry,        /* SIOCSIWRETRY */
+    (iw_handler) wlan_get_retry,        /* SIOCGIWRETRY */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) wlan_get_encode,       /* SIOCGIWENCODE */
+    (iw_handler) wlan_set_power,        /* SIOCSIWPOWER */
+    (iw_handler) wlan_get_power,        /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) wlan_set_gen_ie,       /* SIOCSIWGENIE */
+    (iw_handler) wlan_get_gen_ie,       /* SIOCGIWGENIE */
+    (iw_handler) wlan_set_auth, /* SIOCSIWAUTH  */
+    (iw_handler) wlan_get_auth, /* SIOCGIWAUTH  */
+    (iw_handler) wlan_set_encode_ext,   /* SIOCSIWENCODEEXT */
+    (iw_handler) wlan_get_encode_ext,   /* SIOCGIWENCODEEXT */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/*
+ * iwpriv settable callbacks 
+ */
+
+static const iw_handler wlan_private_handler[] = {
+    NULL,                       /* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_priv_args wlan_private_args[] = {
+    /*
+     * { cmd, set_args, get_args, name } 
+     */
+    {
+     WLANEXTSCAN,
+     IW_PRIV_TYPE_INT,
+     IW_PRIV_TYPE_CHAR | 2,
+     "extscan"},
+    {
+     WLANHOSTCMD,
+     IW_PRIV_TYPE_BYTE | 2047,
+     IW_PRIV_TYPE_BYTE | 2047,
+     "hostcmd"},
+    {
+     WLANARPFILTER,
+     IW_PRIV_TYPE_BYTE | 2047,
+     IW_PRIV_TYPE_BYTE | 2047,
+     "arpfilter"},
+    {
+     WLANREGRDWR,
+     IW_PRIV_TYPE_CHAR | 256,
+     IW_PRIV_TYPE_CHAR | 256,
+     "regrdwr"},
+    {
+     WLANCMD52RDWR,
+     IW_PRIV_TYPE_BYTE | 7,
+     IW_PRIV_TYPE_BYTE | 7,
+     "sdcmd52rw"},
+    {
+     WLANCMD53RDWR,
+     IW_PRIV_TYPE_CHAR | 32,
+     IW_PRIV_TYPE_CHAR | 32,
+     "sdcmd53rw"},
+    {
+     WLAN_SETCONF_GETCONF,
+     IW_PRIV_TYPE_BYTE | MAX_SETGET_CONF_SIZE,
+     IW_PRIV_TYPE_BYTE | MAX_SETGET_CONF_SIZE,
+     "setgetconf"},
+    {
+     WLANCISDUMP,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_BYTE | 512,
+     "getcis"},
+    {
+     WLANSCAN_TYPE,
+     IW_PRIV_TYPE_CHAR | 8,
+     IW_PRIV_TYPE_CHAR | 8,
+     "scantype"},
+    {
+     WLAN_SETINT_GETINT,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     ""},
+    {
+     WLANNF,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getNF"},
+    {
+     WLANRSSI,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getRSSI"},
+    {
+     WLANBGSCAN,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "bgscan"},
+    {
+     WLANENABLE11D,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "enable11d"},
+    {
+     WLANADHOCGRATE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "adhocgrate"},
+    {
+     WLANSDIOCLOCK,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "sdioclock"},
+    {
+     WLANWMM_ENABLE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "wmm"},
+    {
+     WLANNULLGEN,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "uapsdnullgen"},
+    {
+     WLANADHOCCSET,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "setcoalescing"},
+    {
+     WLAN_ADHOC_G_PROT,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "adhocgprot"},
+    {
+     WLAN_SETONEINT_GETONEINT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     ""},
+    {
+     WLAN_WMM_QOSINFO,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "wmm_qosinfo"},
+    {
+     WLAN_LISTENINTRVL,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "lolisteninter"},
+    {
+     WLAN_FW_WAKEUP_METHOD,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "fwwakeupmethod"},
+    {
+     WLAN_NULLPKTINTERVAL,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "psnullinterval"},
+    {
+     WLAN_BCN_MISS_TIMEOUT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "bcnmisto"},
+    {
+     WLAN_ADHOC_AWAKE_PERIOD,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "adhocawakepd"},
+    {
+     WLAN_LDO,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "ldocfg"},
+    {
+     WLAN_AUTODEEPSLEEP,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "autodeepsleep"},
+    {
+     WLAN_WAKEUP_MT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "wakeupmt"},
+    /* Using iwpriv sub-command feature */
+    {
+     WLAN_SETONEINT_GETNONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLAN_SUBCMD_SETRXANTENNA,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setrxant"},
+    {
+     WLAN_SUBCMD_SETTXANTENNA,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "settxant"},
+    {
+     WLANSETAUTHALG,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "authalgs",
+     },
+    {
+     WLANSETENCRYPTIONMODE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "encryptionmode",
+     },
+    {
+     WLANSETREGION,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setregioncode"},
+    {
+     WLAN_SET_LISTEN_INTERVAL,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setlisteninter"},
+    {
+     WLAN_SET_MULTIPLE_DTIM,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setmultipledtim"},
+    {
+     WLANSETBCNAVG,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setbcnavg"},
+    {
+     WLANSETDATAAVG,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setdataavg"},
+    {
+     WLANASSOCIATE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "associate"},
+    {
+     WLAN_SETNONE_GETONEINT,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     ""},
+    {
+     WLANGETREGION,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getregioncode"},
+    {
+     WLAN_GET_LISTEN_INTERVAL,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getlisteninter"},
+    {
+     WLAN_GET_MULTIPLE_DTIM,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getmultipledtim"},
+    {
+     WLAN_GET_TX_RATE,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "gettxrate"},
+    {
+     WLANGETBCNAVG,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getbcnavg"},
+    {
+     WLANGETDATAAVG,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getdataavg"},
+    {
+     WLAN_SETNONE_GETTWELVE_CHAR,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     ""},
+    {
+     WLAN_SUBCMD_GETRXANTENNA,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "getrxant"},
+    {
+     WLAN_SUBCMD_GETTXANTENNA,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "gettxant"},
+    {
+     WLAN_GET_TSF,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "gettsf"},
+    {
+     WLAN_WPS_SESSION,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "wpssession"},
+    {
+     WLANDEEPSLEEP,
+     IW_PRIV_TYPE_CHAR | 1,
+     IW_PRIV_TYPE_CHAR | 6,
+     "deepsleep"},
+    {
+     WLANHOSTSLEEPCFG,
+     IW_PRIV_TYPE_CHAR | 31,
+     IW_PRIV_TYPE_NONE,
+     "hostsleepcfg"},
+    {
+     WLAN_SETNONE_GETNONE,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLANDEAUTH,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "deauth"},
+    {
+     WLANADHOCSTOP,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "adhocstop"},
+    {
+     WLANRADIOON,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "radioon"},
+    {
+     WLANRADIOOFF,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "radiooff"},
+    {
+     WLANREMOVEADHOCAES,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "rmaeskey"},
+#ifdef REASSOCIATION
+    {
+     WLANREASSOCIATIONAUTO,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "reasso-on"},
+    {
+     WLANREASSOCIATIONUSER,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "reasso-off"},
+#endif /* REASSOCIATION */
+    {
+     WLANWLANIDLEON,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "wlanidle-on"},
+    {
+     WLANWLANIDLEOFF,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "wlanidle-off"},
+    {
+     WLAN_SET64CHAR_GET64CHAR,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     ""},
+    {
+     WLANSLEEPPARAMS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "sleepparams"},
+
+    {
+     WLAN_BCA_TIMESHARE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "bca-ts"},
+    {
+     WLANSCAN_MODE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "scanmode"},
+    {
+     WLAN_GET_ADHOC_STATUS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "getadhocstatus"},
+    {
+     WLAN_SET_GEN_IE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "setgenie"},
+    {
+     WLAN_GET_GEN_IE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "getgenie"},
+    {
+     WLAN_WMM_QUEUE_STATUS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "qstatus"},
+    {
+     WLAN_SETWORDCHAR_GETNONE,
+     IW_PRIV_TYPE_CHAR | 32,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLANSETADHOCAES,
+     IW_PRIV_TYPE_CHAR | 32,
+     IW_PRIV_TYPE_NONE,
+     "setaeskey"},
+    {
+     WLAN_SETONEINT_GETWORDCHAR,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     ""},
+    {
+     WLANGETADHOCAES,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     "getaeskey"},
+    {
+     WLANVERSION,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     "version"},
+    {
+     WLANVEREXT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     "verext"},
+    {
+     WLANSETWPAIE,
+     IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+     IW_PRIV_TYPE_NONE,
+     "setwpaie"},
+    {
+     WLANGETLOG,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+     "getlog"},
+    {
+     WLAN_SET_GET_SIXTEEN_INT,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     ""},
+    {
+     WLAN_TPCCFG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "tpccfg"},
+    {
+     WLAN_SCANPROBES,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "scanprobes"},
+    {
+     WLAN_LED_GPIO_CTRL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "ledgpio"},
+    {
+     WLAN_SLEEP_PERIOD,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "sleeppd"},
+    {
+     WLAN_ADAPT_RATESET,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "rateadapt"},
+
+    {
+     WLAN_INACTIVITY_TIMEOUT,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "inactivityto"},
+    {
+     WLANSNR,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "getSNR"},
+    {
+     WLAN_GET_RATE,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "getrate"},
+    {
+     WLAN_GET_RXINFO,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "getrxinfo"},
+    {
+     WLAN_SET_ATIM_WINDOW,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "atimwindow"},
+    {
+     WLAN_BEACON_INTERVAL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "bcninterval"},
+    {
+     WLAN_SDIO_PULL_CTRL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "sdiopullctrl"},
+    {
+     WLAN_SCAN_TIME,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "scantime"},
+    {
+     WLAN_DATA_SUBSCRIBE_EVENT,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "dataevtcfg"},
+    {
+     WLAN_TXCONTROL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "txcontrol"},
+    {
+     WLANHSCFG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "hscfg"},
+    {
+     WLANHSSETPARA,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "hssetpara"},
+#ifdef DEBUG_LEVEL1
+    {
+     WLAN_DRV_DBG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "drvdbg"},
+#endif
+
+    {
+     WLAN_SET_GET_2K,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     ""},
+    {
+     WLAN_SET_USER_SCAN,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "setuserscan"},
+    {
+     WLAN_GET_SCAN_TABLE,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getscantable"},
+    {
+     WLAN_SET_MRVL_TLV,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "setmrvltlv"},
+    {
+     WLAN_GET_ASSOC_RSP,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getassocrsp"},
+    {
+     WLAN_ADDTS_REQ,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "addts"},
+    {
+     WLAN_DELTS_REQ,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "delts"},
+    {
+     WLAN_QUEUE_CONFIG,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "qconfig"},
+    {
+     WLAN_QUEUE_STATS,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "qstats"},
+    {
+     WLAN_TX_PKT_STATS,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "txpktstats"},
+    {
+     WLAN_GET_CFP_TABLE,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getcfptable"},
+};
+
+struct iw_handler_def wlan_handler_def = {
+  num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
+  num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
+  num_private_args:sizeof(wlan_private_args) /
+        sizeof(struct iw_priv_args),
+  standard:(iw_handler *) wlan_handler,
+  private:(iw_handler *) wlan_private_handler,
+  private_args:(struct iw_priv_args *) wlan_private_args,
+  get_wireless_stats:(struct iw_statistics *) wlan_get_wireless_stats,
+};
+
+/** 
+ *  @brief wlan hostcmd ioctl handler
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param req		        A pointer to ifreq structure
+ *  @param cmd			command 
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_hostcmd_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+    u8 *tempResponseBuffer;
+    CmdCtrlNode *pCmdNode;
+    HostCmd_DS_GEN *pCmdPtr;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 wait_option = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    if ((wrq->u.data.pointer == NULL) || (wrq->u.data.length < S_DS_GEN)) {
+        PRINTM(INFO,
+               "wlan_hostcmd_ioctl() corrupt data: pointer=%p, length=%d\n",
+               wrq->u.data.pointer, wrq->u.data.length);
+        return -EFAULT;
+    }
+
+    /*
+     * Get a free command control node 
+     */
+    if (!(pCmdNode = GetFreeCmdCtrlNode(priv))) {
+        PRINTM(INFO, "Failed GetFreeCmdCtrlNode\n");
+        return -ENOMEM;
+    }
+
+    if (!
+        (tempResponseBuffer =
+         kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
+        PRINTM(INFO, "ERROR: Failed to allocate response buffer!\n");
+        CleanupAndInsertCmd(priv, pCmdNode);
+        return -ENOMEM;
+    }
+
+    wait_option |= HostCmd_OPTION_WAITFORRSP;
+
+    SetCmdCtrlNode(priv, pCmdNode, 0, wait_option, NULL);
+    init_waitqueue_head(&pCmdNode->cmdwait_q);
+
+    pCmdPtr = (HostCmd_DS_GEN *) pCmdNode->BufVirtualAddr;
+
+    /*
+     * Copy the whole command into the command buffer 
+     */
+    if (copy_from_user(pCmdPtr, wrq->u.data.pointer, wrq->u.data.length)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(tempResponseBuffer);
+        CleanupAndInsertCmd(priv, pCmdNode);
+        return -EFAULT;
+    }
+
+    if (pCmdPtr->Size < S_DS_GEN) {
+        PRINTM(INFO, "wlan_hostcmd_ioctl() invalid cmd size: Size=%d\n",
+               pCmdPtr->Size);
+        kfree(tempResponseBuffer);
+        CleanupAndInsertCmd(priv, pCmdNode);
+        return -EFAULT;
+    }
+
+    pCmdNode->pdata_buf = tempResponseBuffer;
+    pCmdNode->CmdFlags |= CMD_F_HOSTCMD;
+
+    pCmdPtr->Result = 0;
+
+    PRINTM(INFO, "HOSTCMD Command: 0x%04x Size: %d\n",
+           pCmdPtr->Command, pCmdPtr->Size);
+    HEXDUMP("Command Data", (u8 *) (pCmdPtr), MIN(32, pCmdPtr->Size));
+    PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n",
+           req->ifr_data, pCmdPtr);
+
+    pCmdNode->CmdWaitQWoken = FALSE;
+    pCmdPtr->Command = wlan_cpu_to_le16(pCmdPtr->Command);
+    pCmdPtr->Size = wlan_cpu_to_le16(pCmdPtr->Size);
+    QueueCmd(Adapter, pCmdNode, TRUE);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+    if (wait_option & HostCmd_OPTION_WAITFORRSP) {
+        /* Sleep until response is generated by FW */
+        wait_event_interruptible(pCmdNode->cmdwait_q,
+                                 pCmdNode->CmdWaitQWoken);
+    }
+
+    /* Copy the response back to user space */
+    pCmdPtr = (HostCmd_DS_GEN *) tempResponseBuffer;
+
+    if (copy_to_user(wrq->u.data.pointer, tempResponseBuffer, pCmdPtr->Size))
+        PRINTM(INFO, "ERROR: copy_to_user failed!\n");
+    wrq->u.data.length = pCmdPtr->Size;
+    kfree(tempResponseBuffer);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief wlan arpfilter ioctl handler
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param req		        A pointer to ifreq structure
+ *  @param cmd			command 
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_arpfilter_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+    wlan_private *priv = dev->priv;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypesHeader_t hdr;
+
+    ENTER();
+
+    if ((wrq->u.data.pointer == NULL)
+        || (wrq->u.data.length < sizeof(MrvlIEtypesHeader_t))
+        || (wrq->u.data.length > sizeof(Adapter->ArpFilter))) {
+        PRINTM(INFO,
+               "wlan_arpfilter_ioctl() corrupt data: pointer=%p, length=%d\n",
+               wrq->u.data.pointer, wrq->u.data.length);
+        return -EFAULT;
+    }
+
+    if (copy_from_user(&hdr, wrq->u.data.pointer, sizeof(hdr))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    if (hdr.Len == 0) {
+        Adapter->ArpFilterSize = 0;
+        memset(Adapter->ArpFilter, 0, sizeof(Adapter->ArpFilter));
+    } else {
+        Adapter->ArpFilterSize = wrq->u.data.length;
+
+        PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n",
+               wrq->u.data.pointer, Adapter->ArpFilter);
+        if (copy_from_user(Adapter->ArpFilter, wrq->u.data.pointer,
+                           Adapter->ArpFilterSize)) {
+            Adapter->ArpFilterSize = 0;
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        HEXDUMP("ArpFilter", Adapter->ArpFilter, Adapter->ArpFilterSize);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Rx Info 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success
+ */
+static int
+wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[2];
+    ENTER();
+    data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+    data[1] = Adapter->RxPDRate;
+    if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    wrq->u.data.length = 2;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get SNR 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    int data[4];
+
+    ENTER();
+    memset(data, 0, sizeof(data));
+    if (wrq->u.data.length) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer,
+             MIN(wrq->u.data.length, 4) * sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+    }
+    if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            ret = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_802_11_RSSI,
+                                        0, HostCmd_OPTION_WAITFORRSP,
+                                        0, NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+        }
+    }
+
+    if (wrq->u.data.length == 0) {
+        data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+        data[1] = Adapter->SNR[TYPE_BEACON][TYPE_AVG];
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            data[2] = 0;
+        else
+            data[2] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+        data[3] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = 4;
+    } else if (data[0] == 0) {
+        data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else if (data[0] == 1) {
+        data[0] = Adapter->SNR[TYPE_BEACON][TYPE_AVG];
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else if (data[0] == 2) {
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            data[0] = 0;
+        else
+            data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else if (data[0] == 3) {
+        data[0] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else {
+        return -ENOTSUPP;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set SDIO PULL CTRL 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_sdio_pull_ctrl(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[2];
+    HostCmd_DS_SDIO_PULL_CTRL sdio_pull_ctrl;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    memset(&sdio_pull_ctrl, 0, sizeof(sdio_pull_ctrl));
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(data))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+        PRINTM(INFO, "WLAN SET SDIO PULL CTRL: %d %d\n", data[0], data[1]);
+        sdio_pull_ctrl.Action = HostCmd_ACT_GEN_SET;
+        sdio_pull_ctrl.PullUp = data[0];
+        sdio_pull_ctrl.PullDown = data[1];
+    } else {
+        sdio_pull_ctrl.Action = HostCmd_ACT_GEN_GET;
+    }
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_SDIO_PULL_CTRL,
+                                0, HostCmd_OPTION_WAITFORRSP,
+                                0, (void *) &sdio_pull_ctrl);
+    data[0] = sdio_pull_ctrl.PullUp;
+    data[1] = sdio_pull_ctrl.PullDown;
+    wrq->u.data.length = 2;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set scan time
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_scan_time(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[3] = { 0, 0, 0 };
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0 && wrq->u.data.length <= 3) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        PRINTM(INFO,
+               "WLAN SET Scan Time: Specific %d, Active %d, Passive %d\n",
+               data[0], data[1], data[2]);
+        if (data[0]) {
+            if (data[0] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) {
+                PRINTM(MSG,
+                       "Invalid parameter, max specific scan time is %d ms\n",
+                       MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME);
+                return -EINVAL;
+            }
+            Adapter->SpecificScanTime = data[0];
+        }
+        if (data[1]) {
+            if (data[1] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) {
+                PRINTM(MSG,
+                       "Invalid parameter, max active scan time is %d ms\n",
+                       MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME);
+                return -EINVAL;
+            }
+            Adapter->ActiveScanTime = data[1];
+        }
+        if (data[2]) {
+            if (data[2] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME) {
+                PRINTM(MSG,
+                       "Invalid parameter, max passive scan time is %d ms\n",
+                       MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME);
+                return -EINVAL;
+            }
+            Adapter->PassiveScanTime = data[2];
+        }
+    }
+
+    data[0] = Adapter->SpecificScanTime;
+    data[1] = Adapter->ActiveScanTime;
+    data[2] = Adapter->PassiveScanTime;
+    wrq->u.data.length = 3;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Adhoc beacon Interval 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[2];
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        PRINTM(INFO, "WLAN SET BEACON INTERVAL: %d\n", data[0]);
+        if ((data[0] > MRVDRV_MAX_BEACON_INTERVAL) ||
+            (data[0] < MRVDRV_MIN_BEACON_INTERVAL))
+            return -ENOTSUPP;
+        Adapter->BeaconPeriod = data[0];
+    }
+    data[0] = Adapter->BeaconPeriod;
+    wrq->u.data.length = 1;
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        data[1] = Adapter->CurBssParams.BSSDescriptor.BeaconPeriod;
+        wrq->u.data.length = 2;
+    }
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Adhoc ATIM Window 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_ATIM_Window(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[2];
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        PRINTM(INFO, "WLAN SET ATIM WINDOW: %d\n", data[0]);
+        Adapter->AtimWindow = data[0];
+        Adapter->AtimWindow = MIN(Adapter->AtimWindow, 50);
+    }
+    data[0] = Adapter->AtimWindow;
+    wrq->u.data.length = 1;
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        data[1] = Adapter->CurBssParams.BSSDescriptor.ATIMWindow;
+        wrq->u.data.length = 2;
+    }
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set data subscribe event
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_data_subscribe_event(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[9];
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    memset(data, 0, sizeof(data));
+    if (wrq->u.data.length > 9)
+        return -EFAULT;
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+        memset(&Adapter->subevent, 0, sizeof(Adapter->subevent));
+        Adapter->subevent.EventsBitmap = (u16) data[0];
+        Adapter->subevent.Rssi_low.value = (u8) data[1];
+        Adapter->subevent.Rssi_low.Freq = (u8) data[2];
+        Adapter->subevent.Snr_low.value = (u8) data[3];
+        Adapter->subevent.Snr_low.Freq = (u8) data[4];
+        Adapter->subevent.Rssi_high.value = (u8) data[5];
+        Adapter->subevent.Rssi_high.Freq = (u8) data[6];
+        Adapter->subevent.Snr_high.value = (u8) data[7];
+        Adapter->subevent.Snr_high.Freq = (u8) data[8];
+    } else {
+        data[0] = (int) Adapter->subevent.EventsBitmap;
+        data[1] = (int) Adapter->subevent.Rssi_low.value;
+        data[2] = (int) Adapter->subevent.Rssi_low.Freq;
+        data[3] = (int) Adapter->subevent.Snr_low.value;
+        data[4] = (int) Adapter->subevent.Snr_low.Freq;
+        data[5] = (int) Adapter->subevent.Rssi_high.value;
+        data[6] = (int) Adapter->subevent.Rssi_high.Freq;
+        data[7] = (int) Adapter->subevent.Snr_high.value;
+        data[8] = (int) Adapter->subevent.Snr_high.Freq;
+    }
+    wrq->u.data.length = 9;
+    if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get RSSI 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    int temp;
+    int data = 0;
+    int *val;
+
+    ENTER();
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    if ((data == 0) || (data == 1)) {
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_RSSI,
+                                    0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    switch (data) {
+    case 0:
+
+        temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                        Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+        break;
+    case 1:
+        temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG],
+                        Adapter->NF[TYPE_BEACON][TYPE_AVG]);
+        break;
+    case 2:
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            temp = 0;
+        else
+            temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+                            Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+        break;
+    case 3:
+        temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                        Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+        break;
+    default:
+        return -ENOTSUPP;
+    }
+    val = (int *) wrq->u.name;
+    *val = temp;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get NF
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure 
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    int temp;
+    int data = 0;
+    int *val;
+
+    ENTER();
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    if ((data == 0) || (data == 1)) {
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_RSSI,
+                                    0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    switch (data) {
+    case 0:
+        temp = Adapter->NF[TYPE_BEACON][TYPE_NOAVG];
+        break;
+    case 1:
+        temp = Adapter->NF[TYPE_BEACON][TYPE_AVG];
+        break;
+    case 2:
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            temp = 0;
+        else
+            temp = Adapter->NF[TYPE_RXPD][TYPE_NOAVG];
+        break;
+    case 3:
+        temp = Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        break;
+    default:
+        return -ENOTSUPP;
+    }
+
+    temp = CAL_NF(temp);
+
+    PRINTM(INFO, "***temp = %d\n", temp);
+    val = (int *) wrq->u.name;
+    *val = temp;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Remove AES key
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_remove_aes(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_KEY key;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS ||
+        Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        return -EOPNOTSUPP;
+
+    Adapter->AdhocAESEnabled = FALSE;
+
+    memset(&key, 0, sizeof(WLAN_802_11_KEY));
+    PRINTM(INFO, "WPA2: DISABLE AES_KEY\n");
+    key.KeyLength = WPA_AES_KEY_LEN;
+    key.KeyIndex = 0x40000000;
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_KEY_MATERIAL,
+                                HostCmd_ACT_SET,
+                                HostCmd_OPTION_WAITFORRSP,
+                                !(KEY_INFO_ENABLED), &key);
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief Get Support Rates
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_getrate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_RATES rates;
+    int rate[sizeof(rates)];
+    int i;
+
+    ENTER();
+
+    memset(rates, 0, sizeof(rates));
+    memset(rate, 0, sizeof(rate));
+    wrq->u.data.length = get_active_data_rates(Adapter, rates);
+    if (wrq->u.data.length > sizeof(rates))
+        wrq->u.data.length = sizeof(rates);
+
+    for (i = 0; i < wrq->u.data.length; i++) {
+        rates[i] &= ~0x80;
+        rate[i] = rates[i];
+    }
+
+    if (copy_to_user
+        (wrq->u.data.pointer, rate, wrq->u.data.length * sizeof(int))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get TxRate
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int *pdata;
+    struct iwreq *wrq = (struct iwreq *) req;
+    int ret = WLAN_STATUS_SUCCESS;
+    ENTER();
+    Adapter->TxRate = 0;
+    PRINTM(INFO, "wlan_get_txrate_ioctl\n");
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                                HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP,
+                                0, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+    pdata = (int *) wrq->u.name;
+    *pdata = (int) Adapter->TxRate;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Adhoc Status
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    char status[64];
+    wlan_adapter *Adapter = priv->adapter;
+
+    memset(status, 0, sizeof(status));
+
+    switch (Adapter->InfrastructureMode) {
+    case Wlan802_11IBSS:
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            if (Adapter->AdhocCreate == TRUE)
+                strcpy(status, "AdhocStarted");
+            else
+                strcpy(status, "AdhocJoined");
+        } else {
+            strcpy(status, "AdhocIdle");
+        }
+        break;
+    case Wlan802_11Infrastructure:
+        strcpy(status, "InfraMode");
+        break;
+    default:
+        strcpy(status, "AutoUnknownMode");
+        break;
+    }
+
+    PRINTM(INFO, "Status = %s\n", status);
+    wrq->u.data.length = strlen(status) + 1;
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &status, wrq->u.data.length))
+            return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Driver Version
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_version_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int len;
+    char buf[128];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    get_version(priv->adapter, buf, sizeof(buf) - 1);
+
+    len = strlen(buf);
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = len;
+    }
+
+    PRINTM(INFO, "wlan version: %s\n", buf);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Driver and FW version
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_verext_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_VERSION_EXT versionExtCmd;
+    int len;
+
+    ENTER();
+
+    memset(&versionExtCmd, 0x00, sizeof(versionExtCmd));
+
+    if (wrq->u.data.flags == 0) {
+        //from iwpriv subcmd
+        versionExtCmd.versionStrSel =
+            *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    } else {
+        if (copy_from_user(&versionExtCmd.versionStrSel,
+                           wrq->u.data.pointer,
+                           sizeof(versionExtCmd.versionStrSel))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+    }
+
+    PrepareAndSendCommand(priv,
+                          HostCmd_CMD_VERSION_EXT, 0,
+                          HostCmd_OPTION_WAITFORRSP, 0, &versionExtCmd);
+
+    len = strlen(versionExtCmd.versionStr) + 1;
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, versionExtCmd.versionStr, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = len;
+    }
+
+    PRINTM(INFO, "Version: %s\n", versionExtCmd.versionStr);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Read/Write adapter registers
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_regrdwr_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_ioctl_regrdwr regrdwr;
+    wlan_offset_value offval;
+    u8 *pRdeeprom;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (copy_from_user(&regrdwr, req->ifr_data, sizeof(regrdwr))) {
+        PRINTM(INFO,
+               "copy of regrdwr for wlan_regrdwr_ioctl from user failed \n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    if (regrdwr.WhichReg == REG_EEPROM) {
+        PRINTM(INFO, "Inside RDEEPROM\n");
+        pRdeeprom =
+            (char *) kmalloc((regrdwr.NOB + sizeof(regrdwr)), GFP_KERNEL);
+        if (!pRdeeprom) {
+            PRINTM(INFO, "allocate memory for EEPROM read failed\n");
+            return -ENOMEM;
+        }
+        memcpy(pRdeeprom, &regrdwr, sizeof(regrdwr));
+        PRINTM(INFO, "Action: %d, Offset: %x, NOB: %02x\n",
+               regrdwr.Action, regrdwr.Offset, regrdwr.NOB);
+
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_EEPROM_ACCESS,
+                                    regrdwr.Action, HostCmd_OPTION_WAITFORRSP,
+                                    0, pRdeeprom);
+
+        /*
+         * Return the result back to the user 
+         */
+        if (!ret && regrdwr.Action == HostCmd_ACT_GEN_READ) {
+            if (copy_to_user
+                (req->ifr_data, pRdeeprom, sizeof(regrdwr) + regrdwr.NOB)) {
+                PRINTM(INFO,
+                       "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n");
+                ret = -EFAULT;
+            }
+        }
+
+        kfree(pRdeeprom);
+
+        LEAVE();
+        return ret;
+    }
+
+    offval.offset = regrdwr.Offset;
+    offval.value = (regrdwr.Action) ? regrdwr.Value : 0x00;
+
+    PRINTM(INFO, "RegAccess: %02x Action:%d "
+           "Offset: %04x Value: %04x\n",
+           regrdwr.WhichReg, regrdwr.Action, offval.offset, offval.value);
+
+    /*
+     * regrdwr.WhichReg should contain the command that
+     * corresponds to which register access is to be 
+     * performed HostCmd_CMD_MAC_REG_ACCESS 0x0019
+     * HostCmd_CMD_BBP_REG_ACCESS 0x001a 
+     * HostCmd_CMD_RF_REG_ACCESS 0x001b 
+     */
+    ret = PrepareAndSendCommand(priv, regrdwr.WhichReg,
+                                regrdwr.Action, HostCmd_OPTION_WAITFORRSP,
+                                0, &offval);
+
+    /*
+     * Return the result back to the user 
+     */
+    if (!ret && regrdwr.Action == HostCmd_ACT_GEN_READ) {
+        regrdwr.Value = offval.value;
+        if (copy_to_user(req->ifr_data, &regrdwr, sizeof(regrdwr))) {
+            PRINTM(INFO,
+                   "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n");
+            ret = -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Cmd52 read/write register
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_cmd52rdwr_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 buf[7];
+    u8 rw, func, dat = 0xff;
+    u32 reg;
+
+    ENTER();
+
+    if (copy_from_user(buf, req->ifr_data, sizeof(buf))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    rw = buf[0];
+    func = buf[1];
+    reg = buf[5];
+    reg = (reg << 8) + buf[4];
+    reg = (reg << 8) + buf[3];
+    reg = (reg << 8) + buf[2];
+
+    if (rw != 0)
+        dat = buf[6];
+
+    PRINTM(INFO, "rw=%d func=%d reg=0x%08X dat=0x%02X\n", rw, func, reg, dat);
+
+    if (rw == 0) {
+        if (sbi_read_ioreg(priv, reg, &dat) < 0) {
+            PRINTM(INFO, "sdio_read_ioreg: reading register 0x%X failed\n",
+                   reg);
+            dat = 0xff;
+        }
+    } else {
+        if (sbi_write_ioreg(priv,reg, dat) < 0) {
+            PRINTM(INFO, "sdio_read_ioreg: writing register 0x%X failed\n",
+                   reg);
+            dat = 0xff;
+        }
+    }
+    if (copy_to_user(req->ifr_data, &dat, sizeof(dat))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Cmd53 read/write register
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_cmd53rdwr_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    return -EINVAL;
+}
+
+/** 
+ *  @brief Convert ascii string to Hex integer
+ *     
+ *  @param d                    A pointer to integer buf
+ *  @param s			A pointer to ascii string 
+ *  @param dlen			the length o fascii string
+ *  @return 	   	        number of integer  
+ */
+static int
+ascii2hex(u8 * d, char *s, u32 dlen)
+{
+    int i;
+    u8 n;
+
+    memset(d, 0x00, dlen);
+
+    for (i = 0; i < dlen * 2; i++) {
+        if ((s[i] >= 48) && (s[i] <= 57))
+            n = s[i] - 48;
+        else if ((s[i] >= 65) && (s[i] <= 70))
+            n = s[i] - 55;
+        else if ((s[i] >= 97) && (s[i] <= 102))
+            n = s[i] - 87;
+        else
+            break;
+        if ((i % 2) == 0)
+            n = n * 16;
+        d[i / 2] += n;
+    }
+
+    return i;
+}
+
+/** 
+ *  @brief Set adhoc aes key
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setadhocaes_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 key_ascii[32];
+    u8 key_hex[16];
+    int ret = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    WLAN_802_11_KEY key;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS)
+        return -EOPNOTSUPP;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        return -EOPNOTSUPP;
+
+    if (copy_from_user(key_ascii, wrq->u.data.pointer, sizeof(key_ascii))) {
+        PRINTM(INFO, "wlan_setadhocaes_ioctl copy from user failed \n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    Adapter->AdhocAESEnabled = TRUE;
+    ascii2hex(key_hex, key_ascii, sizeof(key_hex));
+
+    HEXDUMP("wlan_setadhocaes_ioctl", key_hex, sizeof(key_hex));
+
+    PRINTM(INFO, "WPA2: ENABLE AES_KEY\n");
+    key.KeyLength = WPA_AES_KEY_LEN;
+    key.KeyIndex = 0x40000000;
+    memcpy(key.KeyMaterial, key_hex, key.KeyLength);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_KEY_MATERIAL,
+                                HostCmd_ACT_SET,
+                                HostCmd_OPTION_WAITFORRSP,
+                                KEY_INFO_ENABLED, &key);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get adhoc aes key   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_getadhocaes_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 *tmp;
+    u8 key_ascii[33];
+    u8 key_hex[16];
+    int i, ret = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_KEY key;
+
+    ENTER();
+
+    memset(key_hex, 0x00, sizeof(key_hex));
+
+    PRINTM(INFO, "WPA2: ENABLE AES_KEY\n");
+    key.KeyLength = WPA_AES_KEY_LEN;
+    key.KeyIndex = 0x40000000;
+    memcpy(key.KeyMaterial, key_hex, key.KeyLength);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_KEY_MATERIAL,
+                                HostCmd_ACT_GET,
+                                HostCmd_OPTION_WAITFORRSP,
+                                KEY_INFO_ENABLED, &key);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    memcpy(key_hex, Adapter->aeskey.KeyParamSet.Key, sizeof(key_hex));
+
+    HEXDUMP("wlan_getadhocaes_ioctl", key_hex, sizeof(key_hex));
+
+    wrq->u.data.length = sizeof(key_ascii) + 1;
+
+    memset(key_ascii, 0x00, sizeof(key_ascii));
+    tmp = key_ascii;
+
+    for (i = 0; i < sizeof(key_hex); i++)
+        tmp += sprintf(tmp, "%02x", key_hex[i]);
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &key_ascii, sizeof(key_ascii))) {
+            PRINTM(INFO, "copy_to_user failed\n");
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set multiple dtim
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    struct iwreq *wrq = (struct iwreq *) req;
+    u32 mdtim;
+    int idata;
+    int ret = -EINVAL;
+
+    ENTER();
+
+    idata = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    mdtim = (u32) idata;
+    if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) &&
+         (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+        || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+        priv->adapter->MultipleDtim = mdtim;
+        ret = WLAN_STATUS_SUCCESS;
+    }
+    if (ret)
+        PRINTM(INFO, "Invalid parameter, MultipleDtim not changed.\n");
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int alg;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.flags == 0) {
+        //from iwpriv subcmd
+        alg = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    } else {
+        //from wpa_supplicant subcmd
+        if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+    }
+
+    PRINTM(INFO, "auth alg is %#x\n", alg);
+
+    switch (alg) {
+    case AUTH_ALG_SHARED_KEY:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
+        break;
+    case AUTH_ALG_NETWORK_EAP:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeNetworkEAP;
+        break;
+    case AUTH_ALG_OPEN_SYSTEM:
+    default:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Encryption mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int mode;
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    if (wrq->u.data.flags == 0) {
+        //from iwpriv subcmd
+        mode = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    } else {
+        //from wpa_supplicant subcmd
+        if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+    }
+    PRINTM(INFO, "encryption mode is %#x\n", mode);
+    priv->adapter->SecInfo.EncryptionMode = mode;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Rx antenna
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int len;
+    char buf[8];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    PRINTM(INFO, "WLAN_SUBCMD_GETRXANTENNA\n");
+    len = GetRxAntenna(priv, buf);
+
+    wrq->u.data.length = len;
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Tx antenna
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int len;
+    char buf[8];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    PRINTM(INFO, "WLAN_SUBCMD_GETTXANTENNA\n");
+    len = GetTxAntenna(priv, buf);
+
+    wrq->u.data.length = len;
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get the MAC TSF value from the firmware
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure containing buffer
+ *                      space to store a TSF value retrieved from the firmware
+ *
+ *  @return             0 if successful; IOCTL error code otherwise
+ */
+static int
+wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    u64 tsfVal = 0;
+    int ret;
+
+    ENTER();
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_GET_TSF,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, &tsfVal);
+
+    PRINTM(INFO, "IOCTL: Get TSF = 0x%016llx\n", tsfVal);
+
+    if (ret != WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "IOCTL: Get TSF; Command exec failed\n");
+        ret = -EFAULT;
+    } else {
+        if (copy_to_user(wrq->u.data.pointer,
+                         &tsfVal,
+                         MIN(wrq->u.data.length, sizeof(tsfVal))) != 0) {
+
+            PRINTM(INFO, "IOCTL: Get TSF; Copy to user failed\n");
+            ret = -EFAULT;
+        } else {
+            ret = 0;
+        }
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief  Control WPS Session Enable/Disable
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_wps_session_ioctl(wlan_private * priv, struct iwreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    char buf[8];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    PRINTM(INFO, "WLAN_WPS_SESSION\n");
+
+    memset(buf, 0, sizeof(buf));
+    if (copy_from_user(buf, wrq->u.data.pointer,
+                       MIN(sizeof(buf) - 1, wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    if (buf[0] == 1)
+        Adapter->wps.SessionEnable = TRUE;
+    else
+        Adapter->wps.SessionEnable = FALSE;
+
+    PRINTM(INFO, "Adapter->wps.SessionEnable = %d\n",
+           Adapter->wps.SessionEnable);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set DeepSleep mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_deepsleep_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    char status[128];
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        PRINTM(MSG, "Cannot enter Deep Sleep mode in connected state.\n");
+        return -EINVAL;
+    }
+
+    if (*(char *) req->ifr_data == '0') {
+        PRINTM(INFO, "Exit Deep Sleep Mode.\n");
+        sprintf(status, "setting to off ");
+        SetDeepSleep(priv, FALSE);
+    } else if (*(char *) req->ifr_data == '1') {
+        PRINTM(INFO, "Enter Deep Sleep Mode.\n");
+        sprintf(status, "setting to on ");
+        SetDeepSleep(priv, TRUE);
+    } else if (*(char *) req->ifr_data == '2') {
+        PRINTM(INFO, "Get Deep Sleep Mode.\n");
+        if (Adapter->IsDeepSleep == TRUE) {
+            sprintf(status, "on ");
+        } else {
+            sprintf(status, "off ");
+        }
+    } else {
+        PRINTM(INFO, "unknown option = %d\n", *(u8 *) req->ifr_data);
+        return -EINVAL;
+    }
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &status, strlen(status)))
+            return -EFAULT;
+        wrq->u.data.length = strlen(status);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Config hostsleep parameter
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_hostsleepcfg_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    char buf[32];
+    int ret = WLAN_STATUS_SUCCESS;
+    int gpio, gap;
+
+    memset(buf, 0, sizeof(buf));
+    if (copy_from_user(buf, wrq->u.data.pointer,
+                       MIN(sizeof(buf) - 1, wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+    buf[sizeof(buf) - 1] = 0;
+
+    if (sscanf(buf, "%x %x %x", &Adapter->HSCfg.conditions, &gpio, &gap) != 3) {
+        PRINTM(MSG, "Invalid parameters\n");
+        return -EINVAL;
+    }
+
+    if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
+        Adapter->HSCfg.gpio = (u8) gpio;
+        Adapter->HSCfg.gap = (u8) gap;
+    }
+
+    PRINTM(INFO,
+           "hostsleepcfg: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
+           Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
+           Adapter->PSState, Adapter->HS_Activated);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_HOST_SLEEP_CFG,
+                                0, HostCmd_OPTION_WAITFORRSP, 0,
+                                &Adapter->HSCfg);
+
+    return ret;
+}
+
+/** 
+ *  @brief Config Host Sleep parameters
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_hscfg_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[3] = { -1, 0xff, 0xff };
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length >= 1 && wrq->u.data.length <= 3) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+        PRINTM(INFO,
+               "wlan_hscfg_ioctl: data[0]=%#08x, data[1]=%#02x, data[2]=%#02x\n",
+               data[0], data[1], data[2]);
+    } else {
+        PRINTM(MSG, "Invalid Argument\n");
+        return -EINVAL;
+    }
+
+    Adapter->HSCfg.conditions = data[0];
+    if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
+        if (wrq->u.data.length == 2) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+        } else if (wrq->u.data.length == 3) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+            Adapter->HSCfg.gap = (u8) data[2];
+        }
+    }
+
+    PRINTM(INFO,
+           "hscfg: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
+           Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
+           Adapter->PSState, Adapter->HS_Activated);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_HOST_SLEEP_CFG,
+                                0, HostCmd_OPTION_WAITFORRSP, 0,
+                                &Adapter->HSCfg);
+
+    data[0] = Adapter->HSCfg.conditions;
+    data[1] = Adapter->HSCfg.gpio;
+    data[2] = Adapter->HSCfg.gap;
+    wrq->u.data.length = 3;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set Host Sleep parameters
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_hssetpara_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[3] = { -1, 0xff, 0xff };
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length >= 1 && wrq->u.data.length <= 3) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+        PRINTM(INFO,
+               "wlan_hssetpara_ioctl: data[0]=%#08x, data[1]=%#02x, data[2]=%#02x\n",
+               data[0], data[1], data[2]);
+    }
+
+    Adapter->HSCfg.conditions = data[0];
+    if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
+        if (wrq->u.data.length == 2) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+        } else if (wrq->u.data.length == 3) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+            Adapter->HSCfg.gap = (u8) data[2];
+        }
+    }
+
+    PRINTM(INFO,
+           "hssetpara: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
+           Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
+           Adapter->PSState, Adapter->HS_Activated);
+
+    data[0] = Adapter->HSCfg.conditions;
+    data[1] = Adapter->HSCfg.gpio;
+    data[2] = Adapter->HSCfg.gap;
+    wrq->u.data.length = 3;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set Cal data ext
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_caldata_ext_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    HostCmd_DS_802_11_CAL_DATA_EXT *pCalData = NULL;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 action;
+
+    ENTER();
+
+    if (!(pCalData = kmalloc(MAX_SETGET_CONF_CMD_LEN, GFP_KERNEL))) {
+        PRINTM(INFO, "Allocate memory failed\n");
+        ret = -ENOMEM;
+        goto calexit;
+    }
+    memset(pCalData, 0, MAX_SETGET_CONF_CMD_LEN);
+
+    if (copy_from_user(pCalData, req->ifr_data + SKIP_CMDNUM,
+                       MAX_SETGET_CONF_CMD_LEN)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(pCalData);
+        ret = -EFAULT;
+        goto calexit;
+    }
+
+    action = (pCalData->Action == HostCmd_ACT_GEN_SET) ?
+        HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET;
+
+    HEXDUMP("Cal data ext", (u8 *) pCalData, MAX_SETGET_CONF_CMD_LEN);
+
+    PRINTM(INFO, "CalData Action = 0x%0X\n", action);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_CAL_DATA_EXT,
+                                action,
+                                HostCmd_OPTION_WAITFORRSP, 0, pCalData);
+
+    if (!ret && action == HostCmd_ACT_GEN_GET) {
+        if (copy_to_user(req->ifr_data + SKIP_CMDNUM, pCalData,
+                         MAX_SETGET_CONF_CMD_LEN)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+    }
+
+    kfree(pCalData);
+  calexit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set sleep period 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_sleep_period(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    int data;
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_SLEEP_PERIOD sleeppd;
+
+    ENTER();
+
+    if (wrq->u.data.length > 1)
+        return -ENOTSUPP;
+
+    memset(&sleeppd, 0, sizeof(sleeppd));
+    memset(&Adapter->sleep_period, 0, sizeof(SleepPeriod));
+
+    if (wrq->u.data.length == 0) {
+        sleeppd.Action = HostCmd_ACT_GEN_GET;
+    } else {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        /* sleep period is 0 or 10~60 in milliseconds */
+#define MIN_SLEEP_PERIOD		10
+#define MAX_SLEEP_PERIOD		60
+#define SLEEP_PERIOD_RESERVED_FF	0xFF
+        if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+            (data == 0)
+            || (data == SLEEP_PERIOD_RESERVED_FF)       /* for UPSD certification tests */
+            ) {
+            sleeppd.Action = HostCmd_ACT_GEN_SET;
+            sleeppd.Period = data;
+        } else
+            return -EINVAL;
+    }
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SLEEP_PERIOD,
+                                0, HostCmd_OPTION_WAITFORRSP,
+                                0, (void *) &sleeppd);
+
+    data = (int) Adapter->sleep_period.period;
+    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set adapt rate 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    int data[4];
+    int rateindex;
+
+    ENTER();
+    memset(data, 0, sizeof(data));
+    if (!wrq->u.data.length) {
+        PRINTM(INFO, "Get ADAPT RATE SET\n");
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                                    HostCmd_ACT_GEN_GET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, NULL);
+        data[0] = Adapter->HWRateDropMode;
+        data[2] = Adapter->Threshold;
+        data[3] = Adapter->FinalRate;
+        wrq->u.data.length = 4;
+        data[1] = Adapter->RateBitmap;
+        if (copy_to_user
+            (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+
+    } else {
+        PRINTM(INFO, "Set ADAPT RATE SET\n");
+        if (wrq->u.data.length > 4)
+            return -EINVAL;
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        if (data[0] > HW_SINGLE_RATE_DROP)
+            return -EINVAL;
+        Adapter->HWRateDropMode = data[0];
+        Adapter->Threshold = data[2];
+        Adapter->FinalRate = data[3];
+        Adapter->RateBitmap = data[1];
+        Adapter->Is_DataRate_Auto = Is_Rate_Auto(priv);
+        if (Adapter->Is_DataRate_Auto)
+            Adapter->DataRate = 0;
+        else {
+            rateindex = GetRateIndex(priv);
+            Adapter->DataRate = index_to_data_rate(rateindex);
+        }
+        PRINTM(INFO, "RateBitmap=%x,IsRateAuto=%d,DataRate=%d\n",
+               Adapter->RateBitmap, Adapter->Is_DataRate_Auto,
+               Adapter->DataRate);
+        ret =
+            PrepareAndSendCommand(priv, HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                                  HostCmd_ACT_GEN_SET,
+                                  HostCmd_OPTION_WAITFORRSP, 0, NULL);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set inactivity timeout
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    int data = 0;
+    u16 timeout = 0;
+
+    ENTER();
+    if (wrq->u.data.length > 1)
+        return -ENOTSUPP;
+
+    if (wrq->u.data.length == 0) {
+        /* Get */
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_INACTIVITY_TIMEOUT,
+                                    HostCmd_ACT_GET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, &timeout);
+        data = timeout;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+    } else {
+        /* Set */
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        timeout = data;
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_INACTIVITY_TIMEOUT,
+                                    HostCmd_ACT_SET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, &timeout);
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get LOG
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    char *buf = NULL;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, " GET STATS\n");
+
+    if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL))) {
+        PRINTM(INFO, "kmalloc failed!\n");
+        return -ENOMEM;
+    }
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_GET_LOG,
+                                0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (!ret && wrq->u.data.pointer) {
+        sprintf(buf, "\n"
+                "mcasttxframe     %u\n"
+                "failed           %u\n"
+                "retry            %u\n"
+                "multiretry       %u\n"
+                "framedup         %u\n"
+                "rtssuccess       %u\n"
+                "rtsfailure       %u\n"
+                "ackfailure       %u\n"
+                "rxfrag           %u\n"
+                "mcastrxframe     %u\n"
+                "fcserror         %u\n"
+                "txframe          %u\n",
+                Adapter->LogMsg.mcasttxframe,
+                Adapter->LogMsg.failed,
+                Adapter->LogMsg.retry,
+                Adapter->LogMsg.multiretry,
+                Adapter->LogMsg.framedup,
+                Adapter->LogMsg.rtssuccess,
+                Adapter->LogMsg.rtsfailure,
+                Adapter->LogMsg.ackfailure,
+                Adapter->LogMsg.rxfrag,
+                Adapter->LogMsg.mcastrxframe,
+                Adapter->LogMsg.fcserror, Adapter->LogMsg.txframe);
+        wrq->u.data.length = strlen(buf) + 1;
+        if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+    }
+
+    kfree(buf);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief config sleep parameters
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_sleep_params_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_sleep_params_config sp;
+
+    ENTER();
+
+    memset(&sp, 0, sizeof(sp));
+
+    if (!wrq->u.data.pointer)
+        return -EFAULT;
+    if (copy_from_user(&sp, wrq->u.data.pointer,
+                       MIN(sizeof(sp), wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    memcpy(&Adapter->sp, &sp.Error, sizeof(SleepParams));
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_SLEEP_PARAMS,
+                                sp.Action, HostCmd_OPTION_WAITFORRSP,
+                                0, NULL);
+
+    if (!ret && !sp.Action) {
+        memcpy(&sp.Error, &Adapter->sp, sizeof(SleepParams));
+        if (copy_to_user(wrq->u.data.pointer, &sp, sizeof(sp))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = sizeof(sp);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Read the CIS Table
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_getcis_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, Adapter->CisInfoBuf,
+                         Adapter->CisInfoLen)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = Adapter->CisInfoLen;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set BCA timeshare
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_bca_timeshare_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_bca_timeshare_config bca_ts;
+
+    ENTER();
+
+    memset(&bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
+
+    if (!wrq->u.data.pointer)
+        return -EFAULT;
+    if (copy_from_user(&bca_ts, wrq->u.data.pointer,
+                       MIN(sizeof(bca_ts), wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    PRINTM(INFO, "TrafficType=%x TimeShareInterva=%x BTTime=%x\n",
+           bca_ts.TrafficType, bca_ts.TimeShareInterval, bca_ts.BTTime);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE,
+                                bca_ts.Action, HostCmd_OPTION_WAITFORRSP,
+                                0, &bca_ts);
+
+    if (!ret && !bca_ts.Action) {
+        if (copy_to_user(wrq->u.data.pointer, &Adapter->bca_ts,
+                         sizeof(bca_ts))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = sizeof(HostCmd_DS_802_11_BCA_TIMESHARE);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set scan type
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    u8 buf[12];
+    u8 *option[] = { "active", "passive", "get", };
+    int i, max_options = (sizeof(option) / sizeof(option[0]));
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wlan_get_state_11d(priv) == ENABLE_11D) {
+        PRINTM(INFO, "11D: Cannot set scantype when 11D enabled\n");
+        return -EFAULT;
+    }
+
+    memset(buf, 0, sizeof(buf));
+
+    if (copy_from_user(buf, wrq->u.data.pointer, MIN(sizeof(buf),
+                                                     wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    PRINTM(INFO, "Scan Type Option = %s\n", buf);
+
+    buf[sizeof(buf) - 1] = '\0';
+
+    for (i = 0; i < max_options; i++) {
+        if (!strcmp(buf, option[i]))
+            break;
+    }
+
+    switch (i) {
+    case 0:
+        Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE;
+        break;
+    case 1:
+        Adapter->ScanType = HostCmd_SCAN_TYPE_PASSIVE;
+        break;
+    case 2:
+        wrq->u.data.length = strlen(option[Adapter->ScanType]) + 1;
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         option[Adapter->ScanType], wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+
+        break;
+    default:
+        PRINTM(INFO, "Invalid Scan Type Ioctl Option\n");
+        ret = -EINVAL;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set scan mode
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u8 buf[12];
+    u8 *option[] = { "bss", "ibss", "any", "get" };
+    int i, max_options = (sizeof(option) / sizeof(option[0]));
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    memset(buf, 0, sizeof(buf));
+
+    if (copy_from_user(buf, wrq->u.data.pointer, MIN(sizeof(buf),
+                                                     wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    PRINTM(INFO, "Scan Mode Option = %s\n", buf);
+
+    buf[sizeof(buf) - 1] = '\0';
+
+    for (i = 0; i < max_options; i++) {
+        if (!strcmp(buf, option[i]))
+            break;
+    }
+
+    switch (i) {
+
+    case 0:
+        Adapter->ScanMode = HostCmd_BSS_TYPE_BSS;
+        break;
+    case 1:
+        Adapter->ScanMode = HostCmd_BSS_TYPE_IBSS;
+        break;
+    case 2:
+        Adapter->ScanMode = HostCmd_BSS_TYPE_ANY;
+        break;
+    case 3:
+
+        wrq->u.data.length = strlen(option[Adapter->ScanMode - 1]) + 1;
+
+        PRINTM(INFO, "Get Scan Mode Option = %s\n",
+               option[Adapter->ScanMode - 1]);
+
+        PRINTM(INFO, "Scan Mode Length %d\n", wrq->u.data.length);
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         option[Adapter->ScanMode - 1], wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+        PRINTM(INFO, "GET Scan Type Option after copy = %s\n",
+               (char *) wrq->u.data.pointer);
+
+        break;
+
+    default:
+        PRINTM(INFO, "Invalid Scan Mode Ioctl Option\n");
+        ret = -EINVAL;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set Adhoc G Rate
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data, data1;
+    int *val;
+
+    ENTER();
+
+    data1 = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    switch (data1) {
+    case 0:
+        Adapter->adhoc_grate_enabled = FALSE;
+        break;
+    case 1:
+        Adapter->adhoc_grate_enabled = TRUE;
+        break;
+    case 2:
+        break;
+    default:
+        return -EINVAL;
+    }
+    data = Adapter->adhoc_grate_enabled;
+    val = (int *) wrq->u.name;
+    *val = data;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Firmware wakeup method
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_cmd_fw_wakeup_method(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u16 action;
+    u16 method;
+    int ret;
+    int data;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
+        action = HostCmd_ACT_GET;
+        method = Adapter->fwWakeupMethod;
+    } else {
+        action = HostCmd_ACT_SET;
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        switch (data) {
+        case 0:
+            method = WAKEUP_FW_UNCHANGED;
+            break;
+        case 1:
+            method = WAKEUP_FW_THRU_INTERFACE;
+            break;
+        case 2:
+            method = WAKEUP_FW_THRU_GPIO;
+            break;
+        default:
+            return -EINVAL;
+        }
+    }
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_FW_WAKE_METHOD, action,
+                                HostCmd_OPTION_WAITFORRSP, 0, &method);
+
+    if (action == HostCmd_ACT_GET) {
+        method = Adapter->fwWakeupMethod;
+        if (copy_to_user(wrq->u.data.pointer, &method, sizeof(method))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set Auto Deep Sleep mode
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_auto_deep_sleep(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0 && wrq->u.data.pointer) {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        switch (data) {
+        case 0:
+            if (Adapter->IsAutoDeepSleepEnabled) {
+                Adapter->IsAutoDeepSleepEnabled = FALSE;
+                /* Try to exit DS if auto DS disabled */
+                SetDeepSleep(priv, FALSE);
+            }
+            break;
+        case 1:
+            if (!Adapter->IsAutoDeepSleepEnabled) {
+                Adapter->IsAutoDeepSleepEnabled = TRUE;
+                /* Wakeup main thread to enter DS if auto DS enabled */
+                wake_up_interruptible(&priv->MainThread.waitQ);
+            }
+            break;
+        default:
+            return -EINVAL;
+        }
+    }
+
+    data = Adapter->IsAutoDeepSleepEnabled;
+    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Get the CFP table based on the region code
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to iwreq structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_cfp_table_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    pwlan_ioctl_cfp_table ioctl_cfp;
+    CHANNEL_FREQ_POWER *cfp;
+    int cfp_no;
+    int regioncode;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
+        ret = -EINVAL;
+        goto cfpexit;
+    }
+
+    ioctl_cfp = (pwlan_ioctl_cfp_table) wrq->u.data.pointer;
+
+    if (copy_from_user(&regioncode, &ioctl_cfp->region, sizeof(int))) {
+        PRINTM(INFO, "Get CFP table: copy from user failed\n");
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    if (!regioncode)
+        regioncode = Adapter->RegionCode;
+
+    cfp =
+        wlan_get_region_cfp_table((u8) regioncode, BAND_G | BAND_B, &cfp_no);
+
+    if (cfp == NULL) {
+        PRINTM(MSG, "No related CFP table found, region code = 0x%x\n",
+               regioncode);
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    if (copy_to_user(&ioctl_cfp->cfp_no, &cfp_no, sizeof(int))) {
+        PRINTM(INFO, "Get CFP table: copy to user failed\n");
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    if (copy_to_user
+        (ioctl_cfp->cfp, cfp, sizeof(CHANNEL_FREQ_POWER) * cfp_no)) {
+        PRINTM(INFO, "Get CFP table: copy to user failed\n");
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    wrq->u.data.length =
+        sizeof(int) * 2 + sizeof(CHANNEL_FREQ_POWER) * cfp_no;
+
+  cfpexit:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief  Retrieve transmit packet statistics from the firmware
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to iwreq structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_tx_pkt_stats_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_TX_PKT_STATS txPktStats;
+    int ret;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (wrq->u.data.length < sizeof(txPktStats)) {
+        LEAVE();
+        return -E2BIG;
+    }
+
+    memset(&txPktStats, 0x00, sizeof(txPktStats));
+
+    if ((ret = PrepareAndSendCommand(priv,
+                                     HostCmd_CMD_TX_PKT_STATS, 0,
+                                     HostCmd_OPTION_WAITFORRSP,
+                                     0, &txPktStats))) {
+        LEAVE();
+        return ret;
+    }
+
+    if (copy_to_user(wrq->u.data.pointer,
+                     (u8 *) & txPktStats, sizeof(txPktStats))) {
+        PRINTM(INFO, "TxPktStats: copy to user failed\n");
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+/** 
+ *  @brief ioctl function - entry point
+ *  
+ *  @param dev		A pointer to net_device structure
+ *  @param req	   	A pointer to ifreq structure
+ *  @param cmd 		command
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+int
+wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+    int subcmd = 0;
+    int idata = 0;
+    int *pdata;
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    if (Adapter->bHostSleepConfigured) {
+        BOOLEAN cmd_allowed = FALSE;
+        int count = sizeof(Commands_Allowed_In_HostSleep)
+            / sizeof(Commands_Allowed_In_HostSleep[0]);
+
+        if (cmd == WLANHOSTSLEEPCFG) {
+            char buf[32];
+            u32 cond;
+
+            memset(buf, 0, sizeof(buf));
+            if (copy_from_user(buf, wrq->u.data.pointer,
+                               MIN(sizeof(buf) - 1, wrq->u.data.length))) {
+                PRINTM(INFO, "Copy from user failed\n");
+                return -EFAULT;
+            }
+            buf[sizeof(buf) - 1] = 0;
+            sscanf(buf, "%x ", &cond);
+            if (cond == HOST_SLEEP_CFG_CANCEL) {
+                cmd_allowed = TRUE;
+                if (Adapter->IsDeepSleep) {
+                    SetDeepSleep(priv, FALSE);
+                }
+            }
+        } else if (cmd == WLAN_SET_GET_SIXTEEN_INT &&
+                   ((int) wrq->u.data.flags == WLANHSCFG)) {
+            u32 cond;
+            if (copy_from_user(&cond, wrq->u.data.pointer, sizeof(cond))) {
+                PRINTM(INFO, "Copy from user failed\n");
+                return -EFAULT;
+            }
+
+            if (cond == HOST_SLEEP_CFG_CANCEL) {
+                cmd_allowed = TRUE;
+                if (Adapter->IsDeepSleep) {
+                    SetDeepSleep(priv, FALSE);
+                }
+            }
+        } else
+            if (Is_Command_Allowed_In_Sleep
+                (req, cmd, Commands_Allowed_In_HostSleep, count)) {
+            cmd_allowed = TRUE;
+        }
+        if (!cmd_allowed) {
+            PRINTM(MSG, "%s IOCTLS called when WLAN access is blocked\n",
+                   __FUNCTION__);
+            return -EBUSY;
+        }
+    }
+
+    if (!Adapter->IsAutoDeepSleepEnabled) {
+        if (Adapter->IsDeepSleep) {
+            int count = sizeof(Commands_Allowed_In_DeepSleep)
+                / sizeof(Commands_Allowed_In_DeepSleep[0]);
+
+            if (!Is_Command_Allowed_In_Sleep
+                (req, cmd, Commands_Allowed_In_DeepSleep, count)) {
+                PRINTM(MSG,
+                       "():%s IOCTLS called when station is"
+                       " in DeepSleep\n", __FUNCTION__);
+                return -EBUSY;
+            }
+        }
+    } else if (cmd == WLANDEEPSLEEP) {
+        PRINTM(MSG,
+               "DeepSleep command is not allowed in AutoDeepSleep mode\n");
+        return -EBUSY;
+    }
+
+    PRINTM(INFO, "wlan_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+    switch (cmd) {
+    case WLANEXTSCAN:
+        ret = wlan_extscan_ioctl(priv, req);
+        break;
+    case WLANHOSTCMD:
+        ret = wlan_hostcmd_ioctl(dev, req, cmd);
+        break;
+    case WLANARPFILTER:
+        ret = wlan_arpfilter_ioctl(dev, req, cmd);
+        break;
+
+    case WLANCISDUMP:          /* Read CIS Table  */
+        ret = wlan_do_getcis_ioctl(priv, req);
+        break;
+
+    case WLANSCAN_TYPE:
+        PRINTM(INFO, "Scan Type Ioctl\n");
+        ret = wlan_scan_type_ioctl(priv, wrq);
+        break;
+
+#ifdef MFG_CMD_SUPPORT
+    case WLANMANFCMD:
+        PRINTM(INFO, "Entering the Manufacturing ioctl SIOCCFMFG\n");
+        ret = wlan_mfg_command(priv, wrq);
+
+        PRINTM(INFO, "Manufacturing Ioctl %s\n",
+               (ret) ? "failed" : "success");
+        break;
+#endif
+
+    case WLANREGRDWR:          /* Register read write command */
+        ret = wlan_regrdwr_ioctl(priv, req);
+        break;
+
+    case WLANCMD52RDWR:        /* CMD52 read/write command */
+        ret = wlan_cmd52rdwr_ioctl(priv, req);
+        break;
+
+    case WLANCMD53RDWR:        /* CMD53 read/write command */
+        ret = wlan_cmd53rdwr_ioctl(priv, req);
+        break;
+
+    case SIOCSIWENCODE:        /* set encoding token & mode for WPA */
+        ret = wlan_set_encode(dev, NULL, &(wrq->u.data), wrq->u.data.pointer);
+        break;
+    case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
+        switch (wrq->u.data.flags) {
+        case WLANDEAUTH:
+            PRINTM(INFO, "Deauth\n");
+            if (Adapter->InfrastructureMode == Wlan802_11Infrastructure &&
+                Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+                SendDeauthentication(priv);
+            } else if (Adapter->InfrastructureMode == Wlan802_11IBSS &&
+                       Adapter->MediaConnectStatus ==
+                       WlanMediaStateConnected) {
+                StopAdhocNetwork(priv);
+            }
+            break;
+
+        case WLANADHOCSTOP:
+            PRINTM(INFO, "Adhoc stop\n");
+            ret = wlan_do_adhocstop_ioctl(priv);
+            break;
+
+        case WLANRADIOON:
+            wlan_radio_ioctl(priv, RADIO_ON);
+            break;
+
+        case WLANRADIOOFF:
+            ret = wlan_radio_ioctl(priv, RADIO_OFF);
+            break;
+        case WLANREMOVEADHOCAES:
+            ret = wlan_remove_aes(priv);
+            break;
+#ifdef REASSOCIATION
+        case WLANREASSOCIATIONAUTO:
+            reassociation_on(priv);
+            break;
+        case WLANREASSOCIATIONUSER:
+            reassociation_off(priv);
+            break;
+#endif /* REASSOCIATION */
+        case WLANWLANIDLEON:
+            wlanidle_on(priv);
+            break;
+        case WLANWLANIDLEOFF:
+            wlanidle_off(priv);
+            break;
+        }                       /* End of switch */
+        break;
+
+    case WLAN_SETWORDCHAR_GETNONE:
+        switch (wrq->u.data.flags) {
+        case WLANSETADHOCAES:
+            ret = wlan_setadhocaes_ioctl(priv, req);
+            break;
+        }
+        break;
+
+    case WLAN_SETONEINT_GETWORDCHAR:
+        switch (wrq->u.data.flags) {
+        case WLANGETADHOCAES:
+            ret = wlan_getadhocaes_ioctl(priv, req);
+            break;
+        case WLANVERSION:      /* Get driver version */
+            ret = wlan_version_ioctl(priv, req);
+            break;
+        case WLANVEREXT:
+            ret = wlan_verext_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLANSETWPAIE:
+        ret = wlan_set_wpa_ie_ioctl(priv, req);
+        break;
+    case WLAN_SETINT_GETINT:
+        /* The first 4 bytes of req->ifr_data is sub-ioctl number
+         * after 4 bytes sits the payload.
+         */
+        subcmd = (int) req->ifr_data;   //from iwpriv subcmd
+        switch (subcmd) {
+        case WLANNF:
+            ret = wlan_get_nf(priv, wrq);
+            break;
+        case WLANRSSI:
+            ret = wlan_get_rssi(priv, wrq);
+            break;
+        case WLANBGSCAN:
+            {
+                int data, data1;
+                int *val;
+                data1 = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+                switch (data1) {
+                case CMD_DISABLED:
+                    PRINTM(INFO, "Background scan is set to disable\n");
+                    ret = wlan_bg_scan_enable(priv, FALSE);
+                    val = (int *) wrq->u.name;
+                    *val = data1;
+                    break;
+                case CMD_ENABLED:
+                    PRINTM(INFO, "Background scan is set to enable\n");
+                    ret = wlan_bg_scan_enable(priv, TRUE);
+                    val = (int *) wrq->u.name;
+                    *val = data1;
+                    break;
+                case CMD_GET:
+                    data = (Adapter->bgScanConfig->Enable == TRUE) ?
+                        CMD_ENABLED : CMD_DISABLED;
+                    val = (int *) wrq->u.name;
+                    *val = data;
+                    break;
+                default:
+                    ret = -EINVAL;
+                    PRINTM(INFO, "Background scan: wrong parameter\n");
+                    break;
+                }
+            }
+            break;
+        case WLANENABLE11D:
+            ret = wlan_cmd_enable_11d(priv, wrq);
+            break;
+        case WLANADHOCGRATE:
+            ret = wlan_do_set_grate_ioctl(priv, wrq);
+            break;
+        case WLANSDIOCLOCK:
+            {
+                int data;
+                int *val;
+                data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+                switch (data) {
+                case CMD_DISABLED:
+                    PRINTM(INFO, "SDIO clock is turned off\n");
+                    ret = sbi_set_bus_clock(priv, FALSE);
+                    break;
+                case CMD_ENABLED:
+                    PRINTM(INFO, "SDIO clock is turned on\n");
+                    ret = sbi_set_bus_clock(priv, TRUE);
+                    break;
+                case CMD_GET:  /* need an API in sdio.c to get STRPCL */
+                default:
+                    ret = -EINVAL;
+                    PRINTM(INFO, "sdioclock: wrong parameter\n");
+                    break;
+                }
+                val = (int *) wrq->u.name;
+                *val = data;
+            }
+            break;
+        case WLANWMM_ENABLE:
+            ret = wlan_wmm_enable_ioctl(priv, wrq);
+            break;
+        case WLANNULLGEN:
+            ret = wlan_null_pkg_gen(priv, wrq);
+            /* enable/disable null pkg generation */
+            break;
+        case WLANADHOCCSET:
+            ret = wlan_set_coalescing_ioctl(priv, wrq);
+            break;
+        case WLAN_ADHOC_G_PROT:
+            ret = wlan_adhoc_g_protection(priv, wrq);
+            break;
+
+        }
+        break;
+
+    case WLAN_SETONEINT_GETONEINT:
+        switch (wrq->u.data.flags) {
+
+        case WLAN_WMM_QOSINFO:
+            {
+                int data;
+                if (wrq->u.data.length == 1) {
+                    if (copy_from_user
+                        (&data, wrq->u.data.pointer, sizeof(int))) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        return -EFAULT;
+                    }
+                    Adapter->wmm.qosinfo = (u8) data;
+                } else {
+                    data = (int) Adapter->wmm.qosinfo;
+                    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                        PRINTM(INFO, "Copy to user failed\n");
+                        return -EFAULT;
+                    }
+                    wrq->u.data.length = 1;
+                }
+            }
+            break;
+        case WLAN_LISTENINTRVL:
+            if (!wrq->u.data.length) {
+                int data;
+                PRINTM(INFO, "Get LocalListenInterval Value\n");
+#define GET_ONE_INT	1
+                data = Adapter->LocalListenInterval;
+                if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                    PRINTM(INFO, "Copy to user failed\n");
+                    return -EFAULT;
+                }
+
+                wrq->u.data.length = GET_ONE_INT;
+            } else {
+                int data;
+                if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+                    PRINTM(INFO, "Copy from user failed\n");
+                    return -EFAULT;
+                }
+
+                PRINTM(INFO, "Set LocalListenInterval = %d\n", data);
+#define MAX_U16_VAL	65535
+                if (data > MAX_U16_VAL) {
+                    PRINTM(INFO, "Exceeds U16 value\n");
+                    return -EINVAL;
+                }
+                Adapter->LocalListenInterval = data;
+            }
+            break;
+        case WLAN_FW_WAKEUP_METHOD:
+            ret = wlan_cmd_fw_wakeup_method(priv, wrq);
+            break;
+        case WLAN_NULLPKTINTERVAL:
+            ret = wlan_null_pkt_interval(priv, wrq);
+            break;
+        case WLAN_BCN_MISS_TIMEOUT:
+            ret = wlan_bcn_miss_timeout(priv, wrq);
+            break;
+        case WLAN_ADHOC_AWAKE_PERIOD:
+            ret = wlan_adhoc_awake_period(priv, wrq);
+            break;
+        case WLAN_LDO:
+            ret = wlan_ldo_config(priv, wrq);
+            break;
+        case WLAN_AUTODEEPSLEEP:
+            ret = wlan_auto_deep_sleep(priv, wrq);
+            break;
+        case WLAN_WAKEUP_MT:
+            if (wrq->u.data.length > 0)
+                Adapter->IntCounter++;
+            wake_up_interruptible(&priv->MainThread.waitQ);
+            break;
+        default:
+            ret = -EOPNOTSUPP;
+            break;
+        }
+        break;
+
+    case WLAN_SETONEINT_GETNONE:
+        /* The first 4 bytes of req->ifr_data is sub-ioctl number
+         * after 4 bytes sits the payload.
+         */
+        subcmd = wrq->u.data.flags;     //from wpa_supplicant subcmd
+
+        if (!subcmd)
+            subcmd = (int) req->ifr_data;       //from iwpriv subcmd
+
+        idata = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+        switch (subcmd) {
+        case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */
+            ret = SetRxAntenna(priv, idata);
+            break;
+        case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */
+            ret = SetTxAntenna(priv, idata);
+            break;
+
+        case WLANSETBCNAVG:
+            if (idata == 0)
+                Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+            else if (idata > MAX_BCN_AVG_FACTOR || idata < MIN_BCN_AVG_FACTOR) {
+                PRINTM(MSG, "The value '%u' is out of the range (0-%u).\n",
+                       idata, MAX_BCN_AVG_FACTOR);
+                return -EINVAL;
+            } else
+                Adapter->bcn_avg_factor = idata;
+            break;
+        case WLANSETDATAAVG:
+            if (idata == 0)
+                Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+            else if (idata > MAX_DATA_AVG_FACTOR
+                     || idata < MIN_DATA_AVG_FACTOR) {
+                PRINTM(MSG, "The value '%u' is out of the range (0-%u).\n",
+                       idata, MAX_DATA_AVG_FACTOR);
+                return -EINVAL;
+            } else
+                Adapter->data_avg_factor = idata;
+            memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
+            memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
+            Adapter->nextSNRNF = 0;
+            Adapter->numSNRNF = 0;
+            break;
+        case WLANASSOCIATE:
+            ret = wlan_associate_to_table_idx(priv, idata);
+            break;
+
+        case WLANSETREGION:
+            ret = wlan_set_region(priv, (u16) idata);
+            break;
+
+        case WLAN_SET_LISTEN_INTERVAL:
+            Adapter->ListenInterval = (u16) idata;
+            break;
+
+        case WLAN_SET_MULTIPLE_DTIM:
+            ret = wlan_set_multiple_dtim_ioctl(priv, req);
+            break;
+
+        case WLANSETAUTHALG:
+            ret = wlan_setauthalg_ioctl(priv, req);
+            break;
+
+        case WLANSETENCRYPTIONMODE:
+            ret = wlan_setencryptionmode_ioctl(priv, req);
+            break;
+
+        default:
+            ret = -EOPNOTSUPP;
+            break;
+        }
+
+        break;
+
+    case WLAN_SETNONE_GETTWELVE_CHAR:  /* Get Antenna settings */
+        /* 
+         * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+         * in flags of iwreq structure, otherwise it will be in
+         * mode member of iwreq structure.
+         */
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */
+            ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
+            break;
+
+        case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */
+            ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
+            break;
+
+        case WLAN_GET_TSF:
+            ret = wlan_get_tsf_ioctl(priv, wrq);
+            break;
+
+        case WLAN_WPS_SESSION:
+            ret = wlan_do_wps_session_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLANDEEPSLEEP:
+        ret = wlan_deepsleep_ioctl(priv, req);
+        break;
+
+    case WLANHOSTSLEEPCFG:
+        ret = wlan_do_hostsleepcfg_ioctl(priv, wrq);
+        break;
+
+    case WLAN_SET64CHAR_GET64CHAR:
+        switch ((int) wrq->u.data.flags) {
+
+        case WLANSLEEPPARAMS:
+            ret = wlan_sleep_params_ioctl(priv, wrq);
+            break;
+
+        case WLAN_BCA_TIMESHARE:
+            ret = wlan_bca_timeshare_ioctl(priv, wrq);
+            break;
+        case WLANSCAN_MODE:
+            PRINTM(INFO, "Scan Mode Ioctl\n");
+            ret = wlan_scan_mode_ioctl(priv, wrq);
+            break;
+
+        case WLAN_GET_ADHOC_STATUS:
+            ret = wlan_get_adhoc_status_ioctl(priv, wrq);
+            break;
+        case WLAN_SET_GEN_IE:
+            ret = wlan_set_gen_ie_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_GEN_IE:
+            ret = wlan_get_gen_ie_ioctl(priv, wrq);
+            break;
+        case WLAN_WMM_QUEUE_STATUS:
+            ret = wlan_wmm_queue_status_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLAN_SETCONF_GETCONF:
+        PRINTM(INFO, "The WLAN_SETCONF_GETCONF=0x%x is %d\n",
+               WLAN_SETCONF_GETCONF, *(u8 *) req->ifr_data);
+        switch (*(u8 *) req->ifr_data) {
+        case CAL_DATA_EXT_CONFIG:
+            ret = wlan_do_caldata_ext_ioctl(priv, req);
+            break;
+        case BG_SCAN_CONFIG:
+            ret = wlan_do_bg_scan_config_ioctl(priv, req);
+            break;
+        }
+        break;
+
+    case WLAN_SETNONE_GETONEINT:
+        switch ((int) req->ifr_data) {
+        case WLANGETBCNAVG:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->bcn_avg_factor;
+            break;
+
+        case WLANGETDATAAVG:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->data_avg_factor;
+            break;
+
+        case WLANGETREGION:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->RegionCode;
+            break;
+
+        case WLAN_GET_LISTEN_INTERVAL:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->ListenInterval;
+            break;
+
+        case WLAN_GET_MULTIPLE_DTIM:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->MultipleDtim;
+            break;
+        case WLAN_GET_TX_RATE:
+            ret = wlan_get_txrate_ioctl(priv, req);
+            break;
+        default:
+            ret = -EOPNOTSUPP;
+
+        }
+
+        break;
+
+    case WLANGETLOG:
+        ret = wlan_do_getlog_ioctl(priv, wrq);
+        break;
+
+    case WLAN_SET_GET_SIXTEEN_INT:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_TPCCFG:
+            {
+                int data[5];
+                HostCmd_DS_802_11_TPC_CFG cfg;
+                memset(&cfg, 0, sizeof(cfg));
+                if ((wrq->u.data.length > 1) && (wrq->u.data.length != 5))
+                    return WLAN_STATUS_FAILURE;
+
+                if (wrq->u.data.length == 0) {
+                    cfg.Action = HostCmd_ACT_GEN_GET;
+                } else {
+                    if (copy_from_user(data,
+                                       wrq->u.data.pointer,
+                                       sizeof(int) * 5)) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        return -EFAULT;
+                    }
+
+                    cfg.Action = HostCmd_ACT_GEN_SET;
+                    cfg.Enable = data[0];
+                    cfg.UseSNR = data[1];
+#define TPC_DATA_NO_CHANG	0x7f
+                    if (wrq->u.data.length == 1) {
+                        cfg.P0 = TPC_DATA_NO_CHANG;
+                        cfg.P1 = TPC_DATA_NO_CHANG;
+                        cfg.P2 = TPC_DATA_NO_CHANG;
+                    } else {
+                        cfg.P0 = data[2];
+                        cfg.P1 = data[3];
+                        cfg.P2 = data[4];
+                    }
+                }
+                ret = PrepareAndSendCommand(priv,
+                                            HostCmd_CMD_802_11_TPC_CFG, 0,
+                                            HostCmd_OPTION_WAITFORRSP, 0,
+                                            (void *) &cfg);
+
+                data[0] = cfg.Enable;
+                data[1] = cfg.UseSNR;
+                data[2] = cfg.P0;
+                data[3] = cfg.P1;
+                data[4] = cfg.P2;
+                if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 5)) {
+                    PRINTM(INFO, "Copy to user failed\n");
+                    return -EFAULT;
+                }
+
+                wrq->u.data.length = 5;
+            }
+            break;
+
+        case WLAN_SCANPROBES:
+            {
+                int data;
+                if (wrq->u.data.length > 0) {
+                    if (copy_from_user
+                        (&data, wrq->u.data.pointer, sizeof(int))) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        return -EFAULT;
+                    }
+
+                    Adapter->ScanProbes = data;
+                } else {
+                    data = Adapter->ScanProbes;
+                    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                        PRINTM(INFO, "Copy to user failed\n");
+                        return -EFAULT;
+                    }
+                }
+                wrq->u.data.length = 1;
+            }
+            break;
+        case WLAN_LED_GPIO_CTRL:
+            {
+                int i;
+                int data[MAX_LEDS * 2];
+                HostCmd_DS_802_11_LED_CTRL ctrl;
+                MrvlIEtypes_LedGpio_t *gpio;
+
+                gpio = (MrvlIEtypes_LedGpio_t *) & ctrl.LedGpio;
+
+                if ((wrq->u.data.length > MAX_LEDS * 2) ||
+                    (wrq->u.data.length % 2) != 0) {
+                    PRINTM(MSG, "invalid ledgpio parameters\n");
+                    return -EINVAL;
+                }
+
+                memset(&ctrl, 0, sizeof(ctrl));
+                if (wrq->u.data.length == 0) {
+                    ctrl.Action = HostCmd_ACT_GEN_GET;
+                } else {
+                    if (copy_from_user(data, wrq->u.data.pointer,
+                                       sizeof(int) * wrq->u.data.length)) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        return -EFAULT;
+                    }
+
+                    ctrl.Action = HostCmd_ACT_GEN_SET;
+                    ctrl.LedNums = 0;
+                    gpio->Header.Type = TLV_TYPE_LED_GPIO;
+                    gpio->Header.Len = wrq->u.data.length;
+                    for (i = 0; i < wrq->u.data.length; i += 2) {
+                        gpio->LedGpio[i / 2].LedNum = data[i];
+                        gpio->LedGpio[i / 2].GpioNum = data[i + 1];
+                    }
+                }
+                ret = PrepareAndSendCommand(priv,
+                                            HostCmd_CMD_802_11_LED_CONTROL, 0,
+                                            HostCmd_OPTION_WAITFORRSP,
+                                            0, (void *) &ctrl);
+
+                for (i = 0; i < gpio->Header.Len; i += 2) {
+                    data[i] = gpio->LedGpio[i / 2].LedNum;
+                    data[i + 1] = gpio->LedGpio[i / 2].GpioNum;
+                }
+                if (copy_to_user(wrq->u.data.pointer, data,
+                                 sizeof(int) * gpio->Header.Len)) {
+                    PRINTM(INFO, "Copy to user failed\n");
+                    return -EFAULT;
+                }
+
+                wrq->u.data.length = gpio->Header.Len;
+            }
+            break;
+        case WLAN_SLEEP_PERIOD:
+            ret = wlan_sleep_period(priv, wrq);
+            break;
+        case WLAN_ADAPT_RATESET:
+            ret = wlan_adapt_rateset(priv, wrq);
+            break;
+        case WLAN_INACTIVITY_TIMEOUT:
+            ret = wlan_inactivity_timeout(priv, wrq);
+            break;
+        case WLANSNR:
+            ret = wlan_get_snr(priv, wrq);
+            break;
+        case WLAN_GET_RATE:
+            ret = wlan_getrate_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_RXINFO:
+            ret = wlan_get_rxinfo(priv, wrq);
+            break;
+        case WLAN_SET_ATIM_WINDOW:
+            ret = wlan_ATIM_Window(priv, wrq);
+            break;
+        case WLAN_BEACON_INTERVAL:
+            ret = wlan_beacon_interval(priv, wrq);
+            break;
+        case WLAN_SDIO_PULL_CTRL:
+            ret = wlan_sdio_pull_ctrl(priv, wrq);
+            break;
+        case WLAN_SCAN_TIME:
+            ret = wlan_scan_time(priv, wrq);
+            break;
+        case WLAN_DATA_SUBSCRIBE_EVENT:
+            ret = wlan_data_subscribe_event(priv, wrq);
+            break;
+        case WLAN_TXCONTROL:
+            ret = wlan_txcontrol(priv, wrq);
+            break;
+        case WLANHSCFG:
+            ret = wlan_hscfg_ioctl(priv, wrq);
+            break;
+        case WLANHSSETPARA:
+            ret = wlan_hssetpara_ioctl(priv, wrq);
+            break;
+#ifdef DEBUG_LEVEL1
+        case WLAN_DRV_DBG:
+            ret = wlan_drv_dbg(priv, wrq);
+            break;
+#endif
+
+        }
+        break;
+
+    case WLAN_SET_GET_2K:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_SET_USER_SCAN:
+            ret = wlan_set_user_scan_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_SCAN_TABLE:
+            ret = wlan_get_scan_table_ioctl(priv, wrq);
+            break;
+        case WLAN_SET_MRVL_TLV:
+            ret = wlan_set_mrvl_tlv_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_ASSOC_RSP:
+            ret = wlan_get_assoc_rsp_ioctl(priv, wrq);
+            break;
+        case WLAN_ADDTS_REQ:
+            ret = wlan_wmm_addts_req_ioctl(priv, wrq);
+            break;
+        case WLAN_DELTS_REQ:
+            ret = wlan_wmm_delts_req_ioctl(priv, wrq);
+            break;
+        case WLAN_QUEUE_CONFIG:
+            ret = wlan_wmm_queue_config_ioctl(priv, wrq);
+            break;
+        case WLAN_QUEUE_STATS:
+            ret = wlan_wmm_queue_stats_ioctl(priv, wrq);
+            break;
+        case WLAN_TX_PKT_STATS:
+            ret = wlan_tx_pkt_stats_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_CFP_TABLE:
+            ret = wlan_get_cfp_table_ioctl(priv, wrq);
+            break;
+        default:
+            ret = -EOPNOTSUPP;
+        }
+        break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get wireless statistics
+ *
+ *  NOTE: If PrepareAndSendCommand() with wait option is issued 
+ *    in this function, a kernel dump (scheduling while atomic) 
+ *    issue may happen on some versions of kernels.
+ *
+ *  @param dev		A pointer to net_device structure
+ *  @return 	   	A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+wlan_get_wireless_stats(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return NULL;
+    }
+
+    priv->wstats.status = Adapter->InfrastructureMode;
+    priv->wstats.discard.retries = priv->stats.tx_errors;
+
+    /* send RSSI command to get beacon RSSI/NF, valid only if associated */
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_RSSI, 0,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    priv->wstats.qual.level =
+        CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                 Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+    priv->wstats.qual.noise = CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+    if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0
+        && Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+    else
+        priv->wstats.qual.noise =
+            CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+    priv->wstats.qual.qual = 0;
+
+    PRINTM(INFO, "Signal Level = %#x\n", priv->wstats.qual.level);
+    PRINTM(INFO, "Noise = %#x\n", priv->wstats.qual.noise);
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_GET_LOG, 0,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (!ret) {
+        priv->wstats.discard.code = 0;
+        priv->wstats.discard.fragment = Adapter->LogMsg.fcserror;
+        priv->wstats.discard.retries = Adapter->LogMsg.retry;
+        priv->wstats.discard.misc = Adapter->LogMsg.ackfailure;
+    }
+
+    return &priv->wstats;
+}
+
+static int
+wlan_set_coalescing_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    int *val;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+    switch (data) {
+    case CMD_DISABLED:
+    case CMD_ENABLED:
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                                    HostCmd_ACT_SET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, &data);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+        break;
+
+    case CMD_GET:
+        ret = PrepareAndSendCommand(priv,
+                                    HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                                    HostCmd_ACT_GET,
+                                    HostCmd_OPTION_WAITFORRSP, 0, &data);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+        break;
+
+    default:
+        return -EINVAL;
+    }
+
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set frequency
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @param info			A pointer to iw_request_info structure 
+ *  @param fwrq			A pointer to iw_freq structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+              struct iw_freq *fwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int rc = -EINPROGRESS;      /* Call commit handler */
+    CHANNEL_FREQ_POWER *cfp;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS)
+        return -EOPNOTSUPP;
+
+    /*
+     * If setting by frequency, convert to a channel 
+     */
+    if (fwrq->e == 1) {
+
+        long f = fwrq->m / 100000;
+        int c = 0;
+
+        cfp = find_cfp_by_band_and_freq(Adapter, 0, f);
+        if (!cfp) {
+            PRINTM(INFO, "Invalid freq=%ld\n", f);
+            return -EINVAL;
+        }
+
+        c = (int) cfp->Channel;
+
+        if (c < 0)
+            return -EINVAL;
+
+        fwrq->e = 0;
+        fwrq->m = c;
+    }
+
+    /*
+     * Setting by channel number 
+     */
+    if (fwrq->m > 1000 || fwrq->e > 0) {
+        rc = -EOPNOTSUPP;
+    } else {
+        int channel = fwrq->m;
+
+        cfp = find_cfp_by_band_and_channel(Adapter, 0, (u16) channel);
+        if (!cfp) {
+            rc = -EINVAL;
+        } else {
+            rc = ChangeAdhocChannel(priv, channel);
+            /*  If station is WEP enabled, send the 
+             *  command to set WEP in firmware
+             */
+            if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
+                PRINTM(INFO, "set_freq: WEP Enabled\n");
+                ret = PrepareAndSendCommand(priv,
+                                            HostCmd_CMD_802_11_SET_WEP,
+                                            0, HostCmd_OPTION_WAITFORRSP,
+                                            OID_802_11_ADD_WEP, NULL);
+
+                if (ret) {
+                    LEAVE();
+                    return ret;
+                }
+                Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE;
+
+                PrepareAndSendCommand(priv,
+                                      HostCmd_CMD_MAC_CONTROL,
+                                      0, HostCmd_OPTION_WAITFORRSP,
+                                      0, &Adapter->CurrentPacketFilter);
+            }
+        }
+    }
+
+    LEAVE();
+    return rc;
+}
+
+/** 
+ *  @brief Set Deep Sleep 
+ *   
+ *  @param adapter 	A pointer to wlan_private structure
+ *  @param bDeepSleep	TRUE--enalbe deepsleep, FALSE--disable deepsleep
+ *  @return 	   	WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+
+int
+SetDeepSleep(wlan_private * priv, BOOLEAN bDeepSleep)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (bDeepSleep == TRUE) {
+        if (Adapter->IsDeepSleep != TRUE) {
+            PRINTM(INFO, "Deep Sleep: sleep\n");
+
+            // note: the command could be queued and executed later
+            //       if there is command in prigressing.
+            ret = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_802_11_DEEP_SLEEP, 0,
+                                        HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+            wmm_stop_queue(priv);
+            os_stop_queue(priv);
+            os_carrier_off(priv);
+        }
+    } else {
+        if (Adapter->IsDeepSleep == TRUE) {
+            PRINTM(CMND, "Deep Sleep: wakeup\n");
+
+            if (Adapter->IntCounterSaved) {
+                Adapter->IntCounter = Adapter->IntCounterSaved;
+                Adapter->IntCounterSaved = 0;
+            }
+
+            if (sbi_exit_deep_sleep(priv))
+                PRINTM(ERROR, "Deep Sleep : wakeup failed\n");
+
+            if (Adapter->IsDeepSleep == TRUE) {
+
+                if (os_wait_interruptible_timeout(Adapter->ds_awake_q,
+                                                  !Adapter->IsDeepSleep,
+                                                  MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT)
+                    == 0) {
+                    PRINTM(MSG, "ds_awake_q: timer expired\n");
+                }
+            }
+
+            if (Adapter->IntCounter)
+                wake_up_interruptible(&priv->MainThread.waitQ);
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief use index to get the data rate
+ *   
+ *  @param index                The index of data rate
+ *  @return 	   		data rate or 0 
+ */
+u32
+index_to_data_rate(u8 index)
+{
+    if (index >= sizeof(WlanDataRates))
+        index = 0;
+
+    return WlanDataRates[index];
+}
+
+/** 
+ *  @brief use rate to get the index
+ *   
+ *  @param rate                 data rate
+ *  @return 	   		index or 0 
+ */
+u8
+data_rate_to_index(u32 rate)
+{
+    u8 *ptr;
+
+    if (rate)
+        if ((ptr = wlan_memchr(WlanDataRates, (u8) rate,
+                               sizeof(WlanDataRates))))
+            return (ptr - WlanDataRates);
+
+    return 0;
+}
+
+/** 
+ *  @brief set data rate
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+
+int
+wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    u32 data_rate;
+    int ret = WLAN_STATUS_SUCCESS;
+    WLAN_802_11_RATES rates;
+    u8 *rate;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    PRINTM(INFO, "Vwrq->value = %d\n", vwrq->value);
+
+    if (vwrq->value == -1) {
+        Adapter->DataRate = 0;
+        Adapter->RateBitmap = 0;
+        memset(rates, 0, sizeof(rates));
+        get_active_data_rates(Adapter, rates);
+        rate = rates;
+        while (*rate) {
+            Adapter->RateBitmap |= 1 << (data_rate_to_index(*rate & 0x7f));
+            rate++;
+        }
+        Adapter->Is_DataRate_Auto = TRUE;
+    } else {
+        if ((vwrq->value % 500000)) {
+            return -EINVAL;
+        }
+
+        data_rate = vwrq->value / 500000;
+
+        memset(rates, 0, sizeof(rates));
+        get_active_data_rates(Adapter, rates);
+        rate = rates;
+        while (*rate) {
+            PRINTM(INFO, "Rate=0x%X  Wanted=0x%X\n", *rate, data_rate);
+            if ((*rate & 0x7f) == (data_rate & 0x7f))
+                break;
+            rate++;
+        }
+        if (!*rate) {
+            PRINTM(MSG, "The fixed data rate 0x%X is out "
+                   "of range.\n", data_rate);
+            return -EINVAL;
+        }
+
+        Adapter->DataRate = data_rate;
+        Adapter->RateBitmap = 1 << (data_rate_to_index(Adapter->DataRate));
+        Adapter->Is_DataRate_Auto = FALSE;
+    }
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                                HostCmd_ACT_GEN_SET,
+                                HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief get data rate
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (Adapter->Is_DataRate_Auto)
+        vwrq->fixed = 0;
+    else
+        vwrq->fixed = 1;
+
+    Adapter->TxRate = 0;
+
+    ret = PrepareAndSendCommand(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                                HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP,
+                                0, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+    vwrq->value = index_to_data_rate(Adapter->TxRate) * 500000;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief set wireless mode 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_mode(struct net_device *dev,
+              struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    WLAN_802_11_NETWORK_INFRASTRUCTURE WantedMode;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    switch (*uwrq) {
+    case IW_MODE_ADHOC:
+        PRINTM(INFO, "Wanted Mode is ad-hoc: current DataRate=%#x\n",
+               Adapter->DataRate);
+        WantedMode = Wlan802_11IBSS;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+        if (!find_cfp_by_band_and_channel
+            (Adapter, 0, (u16) Adapter->AdhocChannel)) {
+            CHANNEL_FREQ_POWER *cfp;
+            cfp =
+                find_cfp_by_band_and_channel(Adapter, 0, FIRST_VALID_CHANNEL);
+            if (cfp)
+                Adapter->AdhocChannel = cfp->Channel;
+        }
+        break;
+
+    case IW_MODE_INFRA:
+        PRINTM(INFO, "Wanted Mode is Infrastructure\n");
+        WantedMode = Wlan802_11Infrastructure;
+        break;
+
+    case IW_MODE_AUTO:
+        PRINTM(INFO, "Wanted Mode is Auto\n");
+        WantedMode = Wlan802_11AutoUnknown;
+        break;
+
+    default:
+        PRINTM(INFO, "Wanted Mode is Unknown: 0x%x\n", *uwrq);
+        return -EINVAL;
+    }
+
+    if (Adapter->InfrastructureMode == WantedMode ||
+        WantedMode == Wlan802_11AutoUnknown) {
+        PRINTM(INFO, "Already set to required mode! No change!\n");
+
+        Adapter->InfrastructureMode = WantedMode;
+
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+        if (Adapter->PSState != PS_STATE_FULL_POWER) {
+            PSWakeup(priv, HostCmd_OPTION_WAITFORRSP);
+        }
+        Adapter->PSMode = Wlan802_11PowerModeCAM;
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            ret = SendDeauthentication(priv);
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+            /* If current mode is Adhoc, clean stale information */
+            ret = StopAdhocNetwork(priv);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+        }
+    }
+
+    Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+
+    Adapter->InfrastructureMode = WantedMode;
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_SNMP_MIB,
+                                0, HostCmd_OPTION_WAITFORRSP,
+                                OID_802_11_INFRASTRUCTURE_MODE, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Encryption key
+ *   
+ *  @param dev      A pointer to net_device structure
+ *  @param info     A pointer to iw_request_info structure
+ *  @param vwrq     A pointer to iw_param structure
+ *  @param extra    A pointer to extra data buf
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, char *extra)
+{
+
+    WLAN_802_11_KEY *pKey = NULL;
+    int retval = -EINVAL;
+
+    ENTER();
+
+    if (dwrq->length > MAX_WEP_KEY_SIZE) {
+        pKey = (WLAN_802_11_KEY *) extra;
+        if (pKey->KeyLength <= MAX_WEP_KEY_SIZE) {
+            //dynamic WEP
+            dwrq->length = pKey->KeyLength;
+            dwrq->flags = pKey->KeyIndex + 1;
+            retval = wlan_set_encode_nonwpa(dev, info, dwrq,
+                                            pKey->KeyMaterial);
+        } else {
+            //WPA
+            retval = wlan_set_encode_wpa(dev, info, dwrq, extra);
+        }
+    } else {
+        //static WEP
+        PRINTM(INFO, "Setting WEP\n");
+        retval = wlan_set_encode_nonwpa(dev, info, dwrq, extra);
+    }
+
+    return retval;
+}
+
+/** 
+ *  @brief set tx power 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    u16 dbm;
+
+    ENTER();
+
+    if (!Is_Command_Allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (vwrq->disabled) {
+        wlan_radio_ioctl(priv, RADIO_OFF);
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    wlan_radio_ioctl(priv, RADIO_ON);
+
+#if WIRELESS_EXT > 14
+    if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
+        dbm = (u16) mw_to_dbm(vwrq->value);
+    } else
+#endif
+        dbm = (u16) vwrq->value;
+
+    if ((dbm < Adapter->MinTxPowerLevel) || (dbm > Adapter->MaxTxPowerLevel)) {
+        PRINTM(MSG,
+               "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
+               dbm, Adapter->MinTxPowerLevel, Adapter->MaxTxPowerLevel);
+        LEAVE();
+        return -EINVAL;
+    }
+
+    /* auto tx power control */
+
+    if (vwrq->fixed == 0)
+        dbm = 0xffff;
+
+    PRINTM(INFO, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+    ret = PrepareAndSendCommand(priv,
+                                HostCmd_CMD_802_11_RF_TX_POWER,
+                                HostCmd_ACT_GEN_SET,
+                                HostCmd_OPTION_WAITFORRSP, 0, (void *) &dbm);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get current essid 
+ *   
+ *  @param dev      A pointer to net_device structure
+ *  @param info     A pointer to iw_request_info structure
+ *  @param vwrq     A pointer to iw_param structure
+ *  @param extra    A pointer to extra data buf
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int tblIdx = -1;
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
+
+    /*
+     * Get the current SSID 
+     */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+        tblIdx = FindSSIDInList(Adapter,
+                                &pBSSDesc->Ssid,
+                                pBSSDesc->MacAddress,
+                                Adapter->InfrastructureMode);
+
+        memcpy(extra, &pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength);
+        extra[pBSSDesc->Ssid.SsidLength] = '\0';
+
+    } else {
+        memset(extra, 0, 32);
+        extra[pBSSDesc->Ssid.SsidLength] = '\0';
+    }
+
+    /* To make the driver backward compatible with WPA supplicant v0.2.4 */
+    if (dwrq->length == 32) {
+        dwrq->length = MIN(pBSSDesc->Ssid.SsidLength, IW_ESSID_MAX_SIZE);
+    } else {
+        dwrq->length = pBSSDesc->Ssid.SsidLength + 1;
+    }
+
+    /* If the current network is in the table, return the table index */
+    if (tblIdx >= 0) {
+        dwrq->flags = (tblIdx + 1) & IW_ENCODE_INDEX;
+    } else {
+        dwrq->flags = 1;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get version 
+ *   
+ *  @param adapter              A pointer to wlan_adapter structure
+ *  @param version		A pointer to version buffer
+ *  @param maxlen		max length of version buffer
+ *  @return 	   		NA
+ */
+void
+get_version(wlan_adapter * adapter, char *version, int maxlen)
+{
+    union
+    {
+        u32 l;
+        u8 c[4];
+    } ver;
+    char fwver[32];
+
+    ver.l = adapter->FWReleaseNumber;
+    if (ver.c[3] == 0)
+        sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
+    else
+        sprintf(fwver, "%u.%u.%u.p%u",
+                ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+    snprintf(version, maxlen, driver_version, fwver);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wext.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wext.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wext.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wext.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,415 @@
+/** @file wlan_wext.h
+ * @brief This file contains definition for IOCTL call.
+ *  
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	10/11/05: Add Doxygen format comments
+	12/19/05: Correct a typo in structure _wlan_ioctl_wmm_tspec
+	01/11/06: Conditionalize new scan/join ioctls
+	04/10/06: Add hostcmd generic API
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	06/08/06: Add definitions of custom events
+	08/29/06: Add ledgpio private command
+********************************************************/
+
+#ifndef	_WLAN_WEXT_H_
+#define	_WLAN_WEXT_H_
+
+#include "wlan_types.h"
+
+#define SUBCMD_OFFSET			4
+/** PRIVATE CMD ID */
+#define	WLANIOCTL			0x8BE0
+
+#define WLANSETWPAIE			(WLANIOCTL + 0)
+#define WLANCISDUMP 			(WLANIOCTL + 1)
+#ifdef MFG_CMD_SUPPORT
+#define	WLANMANFCMD			(WLANIOCTL + 2)
+#endif
+#define	WLANREGRDWR			(WLANIOCTL + 3)
+#define MAX_EEPROM_DATA     			256
+#define	WLANHOSTCMD			(WLANIOCTL + 4)
+
+#define WLANHOSTSLEEPCFG		(WLANIOCTL + 5)
+#define WLANARPFILTER			(WLANIOCTL + 6)
+
+#define WLAN_SETINT_GETINT		(WLANIOCTL + 7)
+#define WLANNF					1
+#define WLANRSSI				2
+#define WLANBGSCAN				4
+#define WLANENABLE11D				5
+#define WLANADHOCGRATE				6
+#define WLANSDIOCLOCK				7
+#define WLANWMM_ENABLE				8
+#define WLANNULLGEN				10
+#define WLANADHOCCSET				11
+#define WLAN_ADHOC_G_PROT			12
+
+#define WLAN_SETNONE_GETNONE	        (WLANIOCTL + 8)
+#define WLANDEAUTH                  		1
+#define WLANRADIOON                 		2
+#define WLANRADIOOFF                		3
+#define WLANREMOVEADHOCAES          		4
+#define WLANADHOCSTOP               		5
+#ifdef REASSOCIATION
+#define WLANREASSOCIATIONAUTO			8
+#define WLANREASSOCIATIONUSER			9
+#endif /* REASSOCIATION */
+#define WLANWLANIDLEON				10
+#define WLANWLANIDLEOFF				11
+
+#define WLANGETLOG                  	(WLANIOCTL + 9)
+#define WLAN_SETCONF_GETCONF		(WLANIOCTL + 10)
+
+#define BG_SCAN_CONFIG				1
+#define CAL_DATA_EXT_CONFIG         2
+
+#define WLANSCAN_TYPE			(WLANIOCTL + 11)
+
+#define WLAN_SET_GET_2K         (WLANIOCTL + 13)
+#define WLAN_SET_USER_SCAN              1
+#define WLAN_GET_SCAN_TABLE             2
+#define WLAN_SET_MRVL_TLV               3
+#define WLAN_GET_ASSOC_RSP              4
+#define WLAN_ADDTS_REQ                  5
+#define WLAN_DELTS_REQ                  6
+#define WLAN_QUEUE_CONFIG               7
+#define WLAN_QUEUE_STATS                8
+#define WLAN_GET_CFP_TABLE              9
+#define WLAN_TX_PKT_STATS              12
+
+#define WLAN_SETNONE_GETONEINT		(WLANIOCTL + 15)
+#define WLANGETREGION				1
+#define WLAN_GET_LISTEN_INTERVAL		2
+#define WLAN_GET_MULTIPLE_DTIM			3
+#define WLAN_GET_TX_RATE			4
+#define	WLANGETBCNAVG				5
+#define WLANGETDATAAVG				6
+
+#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
+#define WLAN_SUBCMD_GETRXANTENNA    1
+#define WLAN_SUBCMD_GETTXANTENNA    2
+#define WLAN_GET_TSF                3
+#define WLAN_WPS_SESSION            4
+
+#define WLAN_SETWORDCHAR_GETNONE	(WLANIOCTL + 20)
+#define WLANSETADHOCAES				1
+
+#define WLAN_SETONEINT_GETWORDCHAR	(WLANIOCTL + 21)
+#define WLANGETADHOCAES				1
+#define WLANVERSION				2
+#define WLANVEREXT				3
+
+#define WLAN_SETONEINT_GETONEINT	(WLANIOCTL + 23)
+#define WLAN_WMM_QOSINFO			2
+#define	WLAN_LISTENINTRVL			3
+#define WLAN_FW_WAKEUP_METHOD			4
+#define WAKEUP_FW_UNCHANGED			0
+#define WAKEUP_FW_THRU_INTERFACE		1
+#define WAKEUP_FW_THRU_GPIO			2
+
+#define WLAN_NULLPKTINTERVAL			5
+#define WLAN_BCN_MISS_TIMEOUT			6
+#define WLAN_ADHOC_AWAKE_PERIOD			7
+#define WLAN_LDO				8
+#define WLAN_AUTODEEPSLEEP			12
+#define WLAN_WAKEUP_MT				13
+
+#define WLAN_SETONEINT_GETNONE		(WLANIOCTL + 24)
+#define WLAN_SUBCMD_SETRXANTENNA		1
+#define WLAN_SUBCMD_SETTXANTENNA		2
+#define WLANSETAUTHALG				4
+#define WLANSETENCRYPTIONMODE			5
+#define WLANSETREGION				6
+#define WLAN_SET_LISTEN_INTERVAL		7
+
+#define WLAN_SET_MULTIPLE_DTIM			8
+
+#define WLANSETBCNAVG				9
+#define WLANSETDATAAVG				10
+#define WLANASSOCIATE				11
+
+#define WLAN_SET64CHAR_GET64CHAR	(WLANIOCTL + 25)
+#define WLANSLEEPPARAMS 			2
+#define	WLAN_BCA_TIMESHARE			3
+#define WLANSCAN_MODE				6
+
+#define WLAN_GET_ADHOC_STATUS			9
+
+#define WLAN_SET_GEN_IE                 	10
+#define WLAN_GET_GEN_IE                 	11
+
+#define WLAN_WMM_QUEUE_STATUS               13
+
+#define WLANEXTSCAN			(WLANIOCTL + 26)
+#define WLANDEEPSLEEP			(WLANIOCTL + 27)
+#define DEEP_SLEEP_ENABLE			1
+#define DEEP_SLEEP_DISABLE  			0
+
+#define WLAN_SET_GET_SIXTEEN_INT       (WLANIOCTL + 29)
+#define WLAN_TPCCFG                             1
+#define WLAN_LED_GPIO_CTRL			5
+#define WLAN_SCANPROBES 			6
+#define WLAN_SLEEP_PERIOD			7
+#define	WLAN_ADAPT_RATESET			8
+#define	WLAN_INACTIVITY_TIMEOUT			9
+#define WLANSNR					10
+#define WLAN_GET_RATE				11
+#define	WLAN_GET_RXINFO				12
+#define	WLAN_SET_ATIM_WINDOW			13
+#define WLAN_BEACON_INTERVAL			14
+#define WLAN_SDIO_PULL_CTRL			15
+#define WLAN_SCAN_TIME				16
+#define WLAN_DATA_SUBSCRIBE_EVENT		18
+#define WLAN_TXCONTROL				19
+#define WLANHSCFG				21
+#define WLANHSSETPARA				22
+#ifdef DEBUG_LEVEL1
+#define WLAN_DRV_DBG				25
+#endif
+
+#define WLANCMD52RDWR			(WLANIOCTL + 30)
+#define WLANCMD53RDWR			(WLANIOCTL + 31)
+#define CMD53BUFLEN				32
+
+#define	REG_MAC					0x19
+#define	REG_BBP					0x1a
+#define	REG_RF					0x1b
+#define	REG_EEPROM				0x59
+
+#define	CMD_DISABLED				0
+#define	CMD_ENABLED				1
+#define	CMD_GET					2
+#define SKIP_CMDNUM				4
+#define SKIP_TYPE				1
+#define SKIP_SIZE				2
+#define SKIP_ACTION				2
+#define SKIP_TYPE_SIZE			(SKIP_TYPE + SKIP_SIZE)
+#define SKIP_TYPE_ACTION		(SKIP_TYPE + SKIP_ACTION)
+
+#define MAX_SETGET_CONF_SIZE		2000    /* less than MRVDRV_SIZE_OF_CMD_BUFFER */
+#define MAX_SETGET_CONF_CMD_LEN		(MAX_SETGET_CONF_SIZE - SKIP_CMDNUM)
+
+/* define custom events */
+#define CUS_EVT_HS_ACTIVATED		"HS_ACTIVATED "
+#define CUS_EVT_HS_DEACTIVATED		"HS_DEACTIVATED "
+#define CUS_EVT_HS_GPIO_INT		"HS_GPIO_INT "
+#define CUS_EVT_BEACON_RSSI_LOW		"EVENT=BEACON_RSSI_LOW"
+#define CUS_EVT_BEACON_SNR_LOW		"EVENT=BEACON_SNR_LOW"
+#define CUS_EVT_BEACON_RSSI_HIGH	"EVENT=BEACON_RSSI_HIGH"
+#define CUS_EVT_BEACON_SNR_HIGH		"EVENT=BEACON_SNR_HIGH"
+#define CUS_EVT_MAX_FAIL		"EVENT=MAX_FAIL"
+#define CUS_EVT_MLME_MIC_ERR_UNI	"MLME-MICHAELMICFAILURE.indication unicast "
+#define CUS_EVT_MLME_MIC_ERR_MUL	"MLME-MICHAELMICFAILURE.indication multicast "
+
+#define CUS_EVT_DATA_RSSI_LOW		"EVENT=DATA_RSSI_LOW"
+#define CUS_EVT_DATA_SNR_LOW		"EVENT=DATA_SNR_LOW"
+#define CUS_EVT_DATA_RSSI_HIGH		"EVENT=DATA_RSSI_HIGH"
+#define CUS_EVT_DATA_SNR_HIGH		"EVENT=DATA_SNR_HIGH"
+
+#define CUS_EVT_DEEP_SLEEP_AWAKE	"EVENT=DS_AWAKE"
+
+#define CUS_EVT_ADHOC_LINK_SENSED	"EVENT=ADHOC_LINK_SENSED"
+#define CUS_EVT_ADHOC_BCN_LOST		"EVENT=ADHOC_BCN_LOST"
+
+/**
+ *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+ *  @sa wlan_ioctl_user_scan_cfg
+ */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX  50
+
+/** wlan_ioctl */
+typedef struct _wlan_ioctl
+{
+        /** Command ID */
+    u16 command;
+        /** data length */
+    u16 len;
+        /** data pointer */
+    u8 *data;
+} wlan_ioctl;
+
+/** wlan_ioctl_rfantenna */
+typedef struct _wlan_ioctl_rfantenna
+{
+    u16 Action;
+    u16 AntennaMode;
+} wlan_ioctl_rfantenna;
+
+/** wlan_ioctl_regrdwr */
+typedef struct _wlan_ioctl_regrdwr
+{
+        /** Which register to access */
+    u16 WhichReg;
+        /** Read or Write */
+    u16 Action;
+    u32 Offset;
+    u16 NOB;
+    u32 Value;
+} wlan_ioctl_regrdwr;
+
+/** wlan_ioctl_cfregrdwr */
+typedef struct _wlan_ioctl_cfregrdwr
+{
+        /** Read or Write */
+    u8 Action;
+        /** register address */
+    u16 Offset;
+        /** register value */
+    u16 Value;
+} wlan_ioctl_cfregrdwr;
+
+/** wlan_ioctl_adhoc_key_info */
+typedef struct _wlan_ioctl_adhoc_key_info
+{
+    u16 action;
+    u8 key[16];
+    u8 tkiptxmickey[16];
+    u8 tkiprxmickey[16];
+} wlan_ioctl_adhoc_key_info;
+
+/** sleep_params */
+typedef struct _wlan_ioctl_sleep_params_config
+{
+    u16 Action;
+    u16 Error;
+    u16 Offset;
+    u16 StableTime;
+    u8 CalControl;
+    u8 ExtSleepClk;
+    u16 Reserved;
+} __ATTRIB_PACK__ wlan_ioctl_sleep_params_config,
+    *pwlan_ioctl_sleep_params_config;
+
+/** BCA TIME SHARE */
+typedef struct _wlan_ioctl_bca_timeshare_config
+{
+        /** ACT_GET/ACT_SET */
+    u16 Action;
+        /** Type: WLAN, BT */
+    u16 TrafficType;
+        /** Interval: 20msec - 60000msec */
+    u32 TimeShareInterval;
+        /** PTA arbiter time in msec */
+    u32 BTTime;
+} __ATTRIB_PACK__ wlan_ioctl_bca_timeshare_config,
+    *pwlan_ioctl_bca_timeshare_config;
+
+#define MAX_CFP_LIST_NUM	64
+
+/** wlan_ioctl_cfp_table */
+typedef struct _wlan_ioctl_cfp_table
+{
+    u32 region;
+    u32 cfp_no;
+    struct
+    {
+        u16 Channel;
+        u32 Freq;
+        u16 MaxTxPower;
+        BOOLEAN Unsupported;
+    } cfp[MAX_CFP_LIST_NUM];
+} __ATTRIB_PACK__ wlan_ioctl_cfp_table, *pwlan_ioctl_cfp_table;
+
+/**
+ *  @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ *  Multiple instances of this structure are included in the IOCTL command
+ *   to configure a instance of a scan on the specific channel.
+ */
+typedef struct
+{
+    u8 chanNumber;              //!< Channel Number to scan
+    u8 radioType;               //!< Radio type: 'B/G' Band = 0, 'A' Band = 1
+    u8 scanType;                //!< Scan type: Active = 0, Passive = 1
+    u8 reserved;
+    u16 scanTime;               //!< Scan duration in milliseconds; if 0 default used
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_chan;
+/**
+ *  @brief IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ * 
+ *  Used to specify SSID specific filters as well as SSID pattern matching
+ *    filters for scan result processing in firmware.
+ */
+typedef struct
+{
+    char ssid[MRVDRV_MAX_SSID_LENGTH + 1];
+    u8 maxLen;
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_ssid;
+
+/**
+ *  @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+ *  Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl.  Specifies
+ *   a number of parameters to be used in general for the scan as well
+ *   as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ *   desired.
+ *
+ *  @sa wlan_set_user_scan_ioctl
+ */
+typedef struct
+{
+
+    /**
+     *  @brief Flag set to keep the previous scan table intact
+     *
+     *  If set, the scan results will accumulate, replacing any previous
+     *   matched entries for a BSS with the new scan data
+     */
+    u8 keepPreviousScan;        //!< Do not erase the existing scan results
+
+    /**
+     *  @brief BSS Type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  Valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+    u8 bssType;
+
+    /**
+     *  @brief Configure the number of probe requests for active chan scans
+     */
+    u8 numProbes;
+
+    u8 reserved;
+
+    /**
+     *  @brief BSSID filter sent in the firmware command to limit the results
+     */
+    u8 specificBSSID[MRVDRV_ETH_ADDR_LEN];
+
+    /**
+     *  @brief SSID filter list used in the to limit the scan results
+     */
+    wlan_ioctl_user_scan_ssid ssidList[MRVDRV_MAX_SSID_LIST_LENGTH];
+
+    /**
+     *  @brief Variable number (fixed maximum) of channels to scan up
+     */
+    wlan_ioctl_user_scan_chan chanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_cfg;
+
+#endif /* _WLAN_WEXT_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wmm.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wmm.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wmm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wmm.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1687 @@
+/** @file wlan_wmm.c
+ * @brief This file contains functions for WMM.
+ * 
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+    10/04/05: Add Doxygen format comments
+    11/11/05: Add support for WMM Status change event
+    01/05/06: Add kernel 2.6.x support  
+    01/11/06: Conditionalize new scan/join code modifications.
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+********************************************************/
+#include    "include.h"
+
+/********************************************************
+        Local Variables
+********************************************************/
+
+/** Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX   512
+
+/** Set limit of driver packet delay for use in MSDU lifetime expiry and
+ *   traffic stream metrics.
+ *
+ *   - Set to 0 to disable driver delay in firmware
+ *   - Set to DRV_PKT_DELAY_TO_FW_MAX to enable all possible values
+ */
+#define DRV_PKT_DELAY_TO_FW_LIMIT  0
+
+/** Upper and Lower threshold for packet queuing in the driver
+ *
+ *    - When the number of packets queued reaches the upper limit,
+ *      the driver will stop the net queue in the app/kernel space.
+ *
+ *    - When the number of packets drops beneath the lower limit after
+ *      having reached the upper limit, the driver will restart the net
+ *      queue.
+ */
+#define WMM_QUEUED_PACKET_LOWER_LIMIT   40
+#define WMM_QUEUED_PACKET_UPPER_LIMIT   50
+
+#define IPTOS_OFFSET 5
+
+static const u8 wmm_info_ie[] = { WMM_IE, 0x07,
+    0x00, 0x50, 0xf2, 0x02,
+    0x00, 0x01, 0x00
+};
+
+/********************************************************
+        Local Functions
+********************************************************/
+#ifdef DEBUG_LEVEL2
+/** 
+ *  @brief Debug print function to display the priority parameters for a WMM AC
+ *
+ *  @param acStr    String pointer giving the AC enumeration (BK, BE, VI, VO)
+ *  @param pACParam Pointer to the AC paramters to display
+ *
+ *  @return         void
+ */
+static void
+wmm_debugPrintAC(wlan_wmm_ac_e acVal,
+                 const IEEEtypes_WmmAcParameters_t * pACParam)
+{
+    const char *acStr[] = { "BK", "BE", "VI", "VO" };
+
+    PRINTM(INFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+           "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+           acStr[acVal], pACParam->AciAifsn.Aci, pACParam->AciAifsn.Acm,
+           pACParam->AciAifsn.Aifsn, pACParam->Ecw.EcwMin,
+           pACParam->Ecw.EcwMax, wlan_le16_to_cpu(pACParam->TxopLimit));
+}
+
+#define PRINTM_AC(acStr, pACParam) wmm_debugPrintAC(acStr, pACParam)
+#else
+#define PRINTM_AC(acStr, pACParam)
+#endif
+
+/**
+ *  @brief Compute the difference between two timestamps.
+ *
+ *  @param pTv1 Pointer to timestamp1
+ *  @param pTv2 Pointer to timestamp2
+ *
+ *  @return Time difference in ms between pTv1 and pTv2 (pTv1 - pTv2)
+ */
+static int
+timeval_diff_in_ms(const struct timeval *pTv1, const struct timeval *pTv2)
+{
+    int diff_ms;
+
+    diff_ms = (pTv1->tv_sec - pTv2->tv_sec) * 1000;
+    diff_ms += (pTv1->tv_usec - pTv2->tv_usec) / 1000;
+
+    return diff_ms;
+}
+
+/** 
+ *  @brief Set the WMM queue priorities to their default values
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_default_queue_priorities(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* default queue priorities: VO->VI->BE->BK */
+    Adapter->wmm.queuePriority[0] = WMM_AC_VO;
+    Adapter->wmm.queuePriority[1] = WMM_AC_VI;
+    Adapter->wmm.queuePriority[2] = WMM_AC_BE;
+    Adapter->wmm.queuePriority[3] = WMM_AC_BK;
+}
+
+/** 
+ *  @brief Initialize WMM priority queues
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_setup_queue_priorities(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    IEEEtypes_WmmParameter_t *pWmmIe;
+    wlan_wmm_ac_e acOrder[4] = { WMM_AC_BE, WMM_AC_BK,
+        WMM_AC_VI, WMM_AC_VO
+    };
+
+    u16 cwmax, cwmin, avg_back_off, tmp[4];
+    int i, j, numAc;
+
+    if (Adapter->wmm.enabled == FALSE) {
+        /* WMM is not enabled, just set the defaults and return */
+        wmm_default_queue_priorities(priv);
+        return;
+    }
+
+    pWmmIe = &Adapter->CurBssParams.BSSDescriptor.wmmIE;
+
+    HEXDUMP("WMM: setup_queue_priorities: param IE",
+            (u8 *) pWmmIe, sizeof(IEEEtypes_WmmParameter_t));
+
+    PRINTM(INFO, "WMM Parameter IE: version=%d, "
+           "QoSInfo Parameter Set Count=%d, Reserved=%#x\n",
+           pWmmIe->VendHdr.Version, pWmmIe->QoSInfo.ParaSetCount,
+           pWmmIe->Reserved);
+
+    for (numAc = 0; numAc < NELEMENTS(acOrder); numAc++) {
+        cwmax = (1 << pWmmIe->AcParams[numAc].Ecw.EcwMax) - 1;
+        cwmin = (1 << pWmmIe->AcParams[numAc].Ecw.EcwMin) - 1;
+        avg_back_off = (cwmin >> 1) + pWmmIe->AcParams[numAc].AciAifsn.Aifsn;
+        Adapter->wmm.queuePriority[numAc] = acOrder[numAc];
+        tmp[numAc] = avg_back_off;
+
+        PRINTM(INFO, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+               cwmax, cwmin, avg_back_off);
+        PRINTM_AC(acOrder[numAc], &pWmmIe->AcParams[numAc]);
+    }
+
+    HEXDUMP("WMM: avg_back_off", (u8 *) tmp, sizeof(tmp));
+    HEXDUMP("WMM: queuePriority", Adapter->wmm.queuePriority,
+            sizeof(Adapter->wmm.queuePriority));
+
+    /* bubble sort */
+    for (i = 0; i < numAc; i++) {
+        for (j = 1; j < numAc - i; j++) {
+            if (tmp[j - 1] > tmp[j]) {
+                SWAP_U16(tmp[j - 1], tmp[j]);
+                SWAP_U8(Adapter->wmm.queuePriority[j - 1],
+                        Adapter->wmm.queuePriority[j]);
+            } else if (tmp[j - 1] == tmp[j]) {
+                if (Adapter->wmm.queuePriority[j - 1]
+                    < Adapter->wmm.queuePriority[j]) {
+                    SWAP_U8(Adapter->wmm.queuePriority[j - 1],
+                            Adapter->wmm.queuePriority[j]);
+                }
+            }
+        }
+    }
+
+    HEXDUMP("WMM: avg_back_off, sort", (u8 *) tmp, sizeof(tmp));
+    HEXDUMP("WMM: queuePriority, sort", Adapter->wmm.queuePriority,
+            sizeof(Adapter->wmm.queuePriority));
+}
+
+/** 
+ *  @brief pop up the highest skb from wmm queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_pop_highest_prio_skb(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    u8 ac;
+
+    ENTER();
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        ac = Adapter->wmm.queuePriority[i];
+        if (!list_empty((struct list_head *) &Adapter->wmm.txSkbQ[ac])) {
+            PRINTM(DATA, "WMM: Highest prio pkt in AC Queue %d\n", i);
+            Adapter->CurrentTxSkb = Adapter->wmm.txSkbQ[ac].next;
+            Adapter->wmm.packetsOut[ac]++;
+            list_del((struct list_head *) Adapter->wmm.txSkbQ[ac].next);
+            break;
+        }
+    }
+
+    LEAVE();
+}
+
+/** 
+ *  @brief Evaluate whether or not an AC is to be downgraded
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param evalAC   AC to evaluate for downgrading
+ *
+ *  @return WMM AC the evalAC traffic is to be sent on.  
+ */
+static wlan_wmm_ac_e
+wmm_eval_downgrade_ac(wlan_private * priv, wlan_wmm_ac_e evalAC)
+{
+    wlan_wmm_ac_e downAC;
+    wlan_wmm_ac_e retAC;
+    WmmAcStatus_t *pACStatus;
+
+    pACStatus = &priv->adapter->wmm.acStatus[evalAC];
+
+    if (pACStatus->Disabled == FALSE) {
+        /* Okay to use this AC, its enabled */
+        return evalAC;
+    }
+
+    /* Setup a default return value of the lowest priority */
+    retAC = WMM_AC_BK;
+
+    /*
+     *  Find the highest AC that is enabled and does not require admission
+     *    control.  The spec disallows downgarding to an AC which is enabled
+     *    due to a completed admission control.  Unadmitted traffic is not 
+     *    to be sent on an AC with admitted traffic.
+     */
+    for (downAC = WMM_AC_BK; downAC < evalAC; downAC++) {
+        pACStatus = &priv->adapter->wmm.acStatus[downAC];
+
+        if ((pACStatus->Disabled == FALSE)
+            && (pACStatus->FlowRequired == FALSE)) {
+            /* AC is enabled and does not require admission control */
+            retAC = downAC;
+        }
+    }
+
+    return retAC;
+}
+
+/** 
+ *  @brief Downgrade WMM priority queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_setup_ac_downgrade(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_wmm_ac_e acVal;
+
+    PRINTM(INFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
+
+    if (Adapter->wmm.enabled == FALSE) {
+        /* WMM is not enabled, default priorities */
+        for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+            for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+                Adapter->wmm.acDowngradedVals[acVal] = acVal;
+            }
+        }
+    } else {
+        for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+            Adapter->wmm.acDowngradedVals[acVal]
+                = wmm_eval_downgrade_ac(priv, acVal);
+            PRINTM(INFO, "WMM: AC PRIO %d maps to %d\n",
+                   acVal, Adapter->wmm.acDowngradedVals[acVal]);
+        }
+    }
+}
+
+/** 
+ *  @brief Convert the IP TOS field to an WMM AC Queue assignment
+ *
+ *  @param tos  IP TOS field
+ *
+ *  @return     WMM AC Queue mapping of the IP TOS field
+ */
+wlan_wmm_ac_e
+wmm_convert_tos_to_ac(int tos)
+{
+    u8 tosIdx;
+
+    /* Map of TOS UP values to WMM AC */
+    const wlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
+        WMM_AC_BK,
+        WMM_AC_BK,
+        WMM_AC_BE,
+        WMM_AC_VI,
+        WMM_AC_VI,
+        WMM_AC_VO,
+        WMM_AC_VO
+    };
+
+    tosIdx = tos >> IPTOS_OFFSET;
+
+    if (tosIdx >= NELEMENTS(tos_to_ac)) {
+        return WMM_AC_BE;
+    }
+
+    return tos_to_ac[tosIdx];
+}
+
+/** 
+ *  @brief  Evaluate a given AC and downgrade it to a lower AC if the
+ *          WMM Parameter IE received from the AP indicates that the AP
+ *          is disabled (due to call admission control (ACM bit)
+ *
+ *  @param priv   Pointer to the wlan_private driver data struct
+ *  @param acVal  AC to evaulate for downgrading
+ *
+ *  @return       Same AC as input if downgrading not required or
+ *                the AC the traffic for the given AC should be downgraded to 
+ */
+wlan_wmm_ac_e
+wmm_downgrade_ac(wlan_private * priv, wlan_wmm_ac_e acVal)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    return (Adapter->wmm.acDowngradedVals[acVal]);
+}
+
+/** 
+ *  @brief  Map the IP TOS field to a user priority value
+ *
+ *  @param tos  IP TOS field
+ *
+ *  @return     User priority tos input parameter maps to
+ */
+static u8
+wmm_tos_to_priority(u8 tos)
+{
+    u8 tosIdx;
+    const u8 tos_to_priority[] = {
+        /* Priority   DSCP_P2   DSCP_P1  DSCP_P0   WMM_AC   */
+        0x00,                   /*    0         0        0       AC_BE   */
+        0x01,                   /*    0         0        1       AC_BK   */
+        0x02,                   /*    0         1        0       AC_BK   */
+        0x03,                   /*    0         1        1       AC_BE   */
+        0x04,                   /*    1         0        0       AC_VI   */
+        0x05,                   /*    1         0        1       AC_VI   */
+        0x06,                   /*    1         1        0       AC_VO   */
+        0x07                    /*    1         1        1       AC_VO   */
+    };
+
+    tosIdx = tos >> IPTOS_OFFSET;
+
+    if (tosIdx >= NELEMENTS(tos_to_priority)) {
+        return WMM_AC_BE;
+    }
+
+    return tos_to_priority[tosIdx];
+}
+
+/**
+ *  @brief  Process a transfer of a data packet to the firmware from the 
+ *          driver queue in order to manipulate flow control in the driver.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_process_fw_iface_tx_xfer_start(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    if (--Adapter->wmm.packetsQueued < WMM_QUEUED_PACKET_LOWER_LIMIT) {
+        PRINTM(DATA, "WMM: FW OS+: %d\n", Adapter->wmm.packetsQueued);
+        os_start_queue(priv);
+    }
+}
+
+/**
+ *  @brief  Process the completion of a data packet transfer to the firmware 
+ *          from the driver queue in order to manipulate flow control in the
+ *          driver.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ *
+ */
+void
+wmm_process_fw_iface_tx_xfer_end(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    if (Adapter->wmm.packetsQueued) {
+        PRINTM(DATA, "WMM: FW OS-: %d\n", Adapter->wmm.packetsQueued);
+        os_stop_queue(priv);
+    }
+}
+
+/**
+ *  @brief  Process a transfer of a data packet from the OS to the driver
+ *          queue in order to manipulate flow control in the driver.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_process_app_iface_tx(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    Adapter->wmm.packetsQueued++;
+
+    if ((!priv->wlan_dev.dnld_sent && (Adapter->PSState != PS_STATE_SLEEP))
+        || (Adapter->wmm.packetsQueued >= WMM_QUEUED_PACKET_UPPER_LIMIT)) {
+        PRINTM(DATA, "WMM: APP OS-: %d\n", Adapter->wmm.packetsQueued);
+        os_stop_queue(priv);
+    }
+}
+
+/**
+ *  @brief  Stop the WMM data queues.  Traffic is still accepted from the
+ *          OS until the buffer limits are reached.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_stop_queue(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    PRINTM(DATA, "WMM: Q-: %d\n", Adapter->wmm.packetsQueued);
+    Adapter->wmm.queueStopped = TRUE;
+}
+
+/**
+ *  @brief  Start/re-start the WMM data queues and indicate to the OS layer 
+ *          that data is being accepted again.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_start_queue(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    PRINTM(DATA, "WMM: Q+: %d\n", Adapter->wmm.packetsQueued);
+    Adapter->wmm.queueStopped = FALSE;
+    if (Adapter->wmm.packetsQueued) {
+        wake_up_interruptible(&priv->MainThread.waitQ);
+    }
+    os_carrier_on(priv);
+    os_start_queue(priv);
+}
+
+/** 
+ *  @brief  Query the status of the WMM queues.  Determine if the driver data
+ *          path is active or not.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      TRUE if WMM queues have been stopped, FALSE if still active
+ */
+int
+wmm_is_queue_stopped(wlan_private * priv)
+{
+    return (priv->adapter->wmm.queueStopped == TRUE);
+}
+
+/** 
+ *  @brief Initialize the WMM state information and the WMM data path queues.
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+void
+wmm_init(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    memset(&Adapter->wmm, 0x00, sizeof(Adapter->wmm));
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        INIT_LIST_HEAD((struct list_head *) &Adapter->wmm.txSkbQ[i]);
+    }
+
+    Adapter->wmm.required = FALSE;
+
+    Adapter->gen_null_pkg = TRUE;       /*Enable NULL Pkg generation */
+}
+
+/** 
+ *  @brief Setup the queue priorities and downgrade any queues as required
+ *         by the WMM info.  Setups default values if WMM is not active
+ *         for this association.
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+void
+wmm_setup_queues(wlan_private * priv)
+{
+    wmm_setup_queue_priorities(priv);
+    wmm_setup_ac_downgrade(priv);
+}
+
+/** 
+ *  @brief implement WMM enable command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param wrq      Pointer to user data
+ *
+ *  @return         WLAN_STATUS_SUCCESS if success; otherwise <0
+ */
+int
+wlan_wmm_enable_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+    int data, data1;
+    int *val;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    switch (data) {
+    case CMD_DISABLED:         /* disable */
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            return -EPERM;
+        }
+
+        spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
+        Adapter->wmm.required = FALSE;
+        if (!Adapter->wmm.enabled) {
+            spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+            data1 = Adapter->wmm.required;
+            val = (int *) wrq->u.name;
+            *val = data;
+            return WLAN_STATUS_SUCCESS;
+        } else {
+            Adapter->wmm.enabled = 0;
+        }
+
+        if (Adapter->CurrentTxSkb) {
+            kfree_skb(Adapter->CurrentTxSkb);
+            OS_INT_DISABLE;
+            Adapter->CurrentTxSkb = NULL;
+            OS_INT_RESTORE;
+            priv->stats.tx_dropped++;
+        }
+
+        spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+        break;
+
+    case CMD_ENABLED:          /* enable */
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            return -EPERM;
+        }
+        spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
+        Adapter->wmm.required = TRUE;
+        spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+        break;
+
+    case CMD_GET:
+        break;
+    default:
+        PRINTM(INFO, "Invalid option\n");
+        return -EINVAL;
+    }
+
+    data = Adapter->wmm.required;
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Implement cmd HostCmd_CMD_WMM_GET_STATUS
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      Pointer to CMD buffer 
+ *  @param InfoBuf  Pointer to cmd data
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_get_status(wlan_private * priv,
+                        HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    PRINTM(INFO, "WMM: WMM_GET_STATUS cmd sent\n");
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Send a command to firmware to retrieve the current WMM status
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+sendWMMStatusChangeCmd(wlan_private * priv)
+{
+    return PrepareAndSendCommand(priv, HostCmd_CMD_WMM_GET_STATUS,
+                                 0, 0, 0, NULL);
+}
+
+/** 
+ *  @brief Check if wmm TX queue is empty
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         FALSE if not empty; TRUE if empty
+ */
+int
+wmm_lists_empty(wlan_private * priv)
+{
+    int i;
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        if (!list_empty((struct list_head *) &priv->adapter->wmm.txSkbQ[i])) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/** 
+ *  @brief Cleanup wmm TX queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+void
+wmm_cleanup_queues(wlan_private * priv)
+{
+    int i;
+    struct sk_buff *delNode, *Q;
+
+    ENTER();
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        Q = &priv->adapter->wmm.txSkbQ[i];
+
+        while (!list_empty((struct list_head *) Q)) {
+            delNode = Q->next;
+            list_del((struct list_head *) delNode);
+            kfree_skb(delNode);
+        }
+    }
+
+    priv->adapter->wmm.packetsQueued = 0;
+
+    LEAVE();
+}
+
+/** 
+ *  @brief Add skb to WMM queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param skb      Pointer to sk_buff
+ *
+ *  @return         void
+ */
+void
+wmm_map_and_add_skb(wlan_private * priv, struct sk_buff *skb)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    struct ethhdr *eth;
+    struct timeval tstamp;
+    u8 tos;
+    wlan_wmm_ac_e ac;
+    wlan_wmm_ac_e ac_down;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+    struct iphdr *iph;
+#endif
+    eth = (struct ethhdr *) skb->data;
+
+    switch (eth->h_proto) {
+    case __constant_htons(ETH_P_IP):
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+        iph = ip_hdr(skb);
+        tos = IPTOS_PREC(iph->tos);
+#else
+        tos = IPTOS_PREC(skb->nh.iph->tos);
+#endif
+        PRINTM(DATA, "packet type ETH_P_IP: %04x, tos=%#x prio=%#x\n",
+               eth->h_proto, tos, skb->priority);
+        break;
+    case __constant_htons(ETH_P_ARP):
+        PRINTM(DATA, "ARP packet %04x\n", eth->h_proto);
+    default:
+        tos = 0;
+        break;
+    }
+
+    ac = wmm_convert_tos_to_ac(tos);
+    ac_down = wmm_downgrade_ac(priv, ac);
+
+    skb->priority = wmm_tos_to_priority(tos);
+    PRINTM(DATA, "wmm_map: tos=%#x, ac=%#x ac_down=%#x, priority=%#x\n",
+           tos, ac, ac_down, skb->priority);
+
+    list_add_tail((struct list_head *) skb,
+                  (struct list_head *) &Adapter->wmm.txSkbQ[ac_down]);
+
+    wmm_process_app_iface_tx(priv);
+
+    /* Record the current time the packet was queued; used to determine
+     *   the amount of time the packet was queued in the driver before it 
+     *   was sent to the firmware.  The delay is then sent along with the 
+     *   packet to the firmware for aggregate delay calculation for stats
+     *   and MSDU lifetime expiry.
+     */
+    do_gettimeofday(&tstamp);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+    skb->tstamp = timeval_to_ktime(tstamp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+    skb_set_timestamp(skb, &tstamp);
+#else
+    memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
+#endif
+}
+
+/**
+ *  @brief Process the GET_WMM_STATUS command response from firmware
+ *
+ *  The GET_WMM_STATUS command returns multiple TLVs for:
+ *      - Each AC Queue status
+ *      - Current WMM Parameter IE
+ *
+ *  This function parses the TLVs and then calls further functions
+ *   to process any changes in the queue prioritization or state.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer including TLVs
+ *                 TLVs for each queue and the WMM Parameter IE.
+ * 
+ *  @return WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmdresp_wmm_get_status(wlan_private * priv,
+                            const HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u8 *pCurrent = (u8 *) & resp->params.getWmmStatus;
+    u32 respLen = resp->Size;
+    int valid = TRUE;
+    int enableData = TRUE;
+
+    MrvlIEtypes_Data_t *pTlvHdr;
+    MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
+    IEEEtypes_WmmParameter_t *pWmmParamIe;
+    WmmAcStatus_t *pACStatus;
+
+    PRINTM(INFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", respLen);
+    HEXDUMP("CMD_RESP: WMM_GET_STATUS", pCurrent, respLen);
+
+    while ((respLen >= sizeof(pTlvHdr->Header)) && valid) {
+        pTlvHdr = (MrvlIEtypes_Data_t *) pCurrent;
+        pTlvHdr->Header.Len = wlan_le16_to_cpu(pTlvHdr->Header.Len);
+
+        switch (wlan_le16_to_cpu(pTlvHdr->Header.Type)) {
+        case TLV_TYPE_WMMQSTATUS:
+            pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
+            PRINTM(INFO,
+                   "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
+                   pTlvWmmQStatus->QueueIndex, pTlvWmmQStatus->FlowRequired,
+                   pTlvWmmQStatus->Disabled);
+
+            pACStatus = &Adapter->wmm.acStatus[pTlvWmmQStatus->QueueIndex];
+            pACStatus->Disabled = pTlvWmmQStatus->Disabled;
+            pACStatus->FlowRequired = pTlvWmmQStatus->FlowRequired;
+            pACStatus->FlowCreated = pTlvWmmQStatus->FlowCreated;
+            break;
+
+        case WMM_IE:
+            /*
+             * Point the regular IEEE IE 2 bytes into the Marvell IE
+             *   and setup the IEEE IE type and length byte fields
+             */
+
+            HEXDUMP("WMM: WMM TLV:", (u8 *) pTlvHdr, pTlvHdr->Header.Len + 4);
+
+            pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pCurrent + 2);
+            pWmmParamIe->VendHdr.Len = pTlvHdr->Header.Len;
+            pWmmParamIe->VendHdr.ElementId = WMM_IE;
+
+            PRINTM(INFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
+                   pWmmParamIe->QoSInfo.ParaSetCount);
+
+            memcpy((u8 *) & Adapter->CurBssParams.BSSDescriptor.wmmIE,
+                   pWmmParamIe, pWmmParamIe->VendHdr.Len + 2);
+
+            break;
+
+        default:
+            valid = FALSE;
+            break;
+        }
+
+        pCurrent += (pTlvHdr->Header.Len + sizeof(pTlvHdr->Header));
+        respLen -= (pTlvHdr->Header.Len + sizeof(pTlvHdr->Header));
+    }
+
+    wmm_setup_queue_priorities(priv);
+    wmm_setup_ac_downgrade(priv);
+
+    if (enableData) {
+        wmm_start_queue(priv);
+        os_carrier_on(priv);
+        os_start_queue(priv);
+    }
+
+    send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Call back from the command module to allow insertion of a WMM TLV
+ *   
+ *  If the BSS we are associating to supports WMM, add the required WMM
+ *    Information IE to the association request command buffer in the form
+ *    of a Marvell extended IEEE IE.
+ *     
+ *  @param priv        Pointer to the wlan_private driver data struct
+ *  @param ppAssocBuf  Output parameter: Pointer to the TLV output buffer,
+ *                     modified on return to point after the appended WMM TLV
+ *  @param pWmmIE      Pointer to the WMM IE for the BSS we are joining
+ * 
+ *  @return Length of data appended to the association tlv buffer
+ */
+u32
+wlan_wmm_process_association_req(wlan_private * priv,
+                                 u8 ** ppAssocBuf,
+                                 IEEEtypes_WmmParameter_t * pWmmIE)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypes_WmmParamSet_t *pWmmTlv;
+    u32 retLen = 0;
+
+    /* Null checks */
+    if (ppAssocBuf == 0)
+        return 0;
+    if (*ppAssocBuf == 0)
+        return 0;
+    if (pWmmIE == 0)
+        return 0;
+
+    PRINTM(INFO, "WMM: process assoc req: bss->wmmIe=%x\n",
+           pWmmIE->VendHdr.ElementId);
+
+    if (Adapter->wmm.required && pWmmIE->VendHdr.ElementId == WMM_IE) {
+        pWmmTlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
+        pWmmTlv->Header.Type = (u16) wmm_info_ie[0];
+        pWmmTlv->Header.Type = wlan_cpu_to_le16(pWmmTlv->Header.Type);
+        pWmmTlv->Header.Len = (u16) wmm_info_ie[1];
+        pWmmTlv->Header.Len = wlan_cpu_to_le16(pWmmTlv->Header.Len);
+
+        memcpy(pWmmTlv->WmmIE, &wmm_info_ie[2], pWmmTlv->Header.Len);
+#define QOS_INFO_PARA_MASK 0x0f
+        if (pWmmIE->QoSInfo.QosUAPSD
+            && ((Adapter->wmm.qosinfo & QOS_INFO_PARA_MASK) != 0)) {
+            memcpy((u8 *) (pWmmTlv->WmmIE + pWmmTlv->Header.Len
+                           - sizeof(Adapter->wmm.qosinfo)),
+                   &Adapter->wmm.qosinfo, sizeof(Adapter->wmm.qosinfo));
+        }
+        retLen = sizeof(pWmmTlv->Header) + pWmmTlv->Header.Len;
+
+        HEXDUMP("ASSOC_CMD: WMM IE", (u8 *) pWmmTlv, retLen);
+        *ppAssocBuf += retLen;
+    }
+
+    return retLen;
+}
+
+/**
+ *   @brief Compute the time delay in the driver queues for a given skb.
+ *
+ *   When the skb is received at the OS/Driver interface, the current 
+ *     time is set in the skb structure.  The difference between the present
+ *     time and that received time is computed in this function and limited
+ *     based on pre-compiled limits in the driver.
+ *
+ *   @param skb  Pointer to a sk_buff which has been previously timestamped
+ *
+ *   @return Time delay of the packet in 2ms units after having limit applied
+ */
+u8
+wmm_compute_driver_packet_delay(const struct sk_buff * skb)
+{
+    u8 retVal;
+    struct timeval in_tv;
+    struct timeval out_tv;
+    int queue_delay;
+
+    retVal = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+    skb_get_timestamp(skb, &in_tv);
+#else
+    memcpy(&in_tv, &skb->stamp, sizeof(in_tv));
+#endif
+    do_gettimeofday(&out_tv);
+
+    queue_delay = timeval_diff_in_ms(&out_tv, &in_tv);
+
+    /* Queue delay is passed as a uint8 in units of 2ms (ms shifted
+     *  by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+     *
+     * Pass max value if queue_delay is beyond the uint8 range 
+     */
+    retVal = MIN(queue_delay, DRV_PKT_DELAY_TO_FW_LIMIT) >> 1;
+
+    PRINTM(DATA, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
+           queue_delay, retVal);
+
+    return retVal;
+}
+
+/** 
+ *  @brief Transmit the highest priority packet awaiting in the WMM Queues
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *
+ *  @return        void
+ */
+void
+wmm_process_tx(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    if ((Adapter->PSState == PS_STATE_SLEEP)
+        || (Adapter->PSState == PS_STATE_PRE_SLEEP)) {
+        PRINTM(INFO, "In PS State %d"
+               " - Not sending the packet\n", Adapter->PSState);
+        LEAVE();
+
+        return;
+    }
+
+    spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
+
+    if (priv->wlan_dev.dnld_sent) {
+        spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+
+        LEAVE();
+
+        return;
+    }
+
+    UpdateTransStart(priv->wlan_dev.netdev);
+    wmm_pop_highest_prio_skb(priv);
+
+    spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+
+    if (Adapter->CurrentTxSkb) {
+        wlan_process_tx(priv);
+    }
+
+    LEAVE();
+}
+
+/**
+ *  @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ *  Return the following information for each WMM AC:
+ *        - WMM IE Acm Required
+ *        - Firmware Flow Required 
+ *        - Firmware Flow Established
+ *        - Firmware Queue Enabled
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_queue_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_wmm_queue_status_t qstatus;
+    wlan_wmm_ac_e acVal;
+    WmmAcStatus_t *pACStatus;
+    IEEEtypes_WmmAcParameters_t *pWmmIeAC;
+
+    for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+        pACStatus = &Adapter->wmm.acStatus[acVal];
+        pWmmIeAC = &Adapter->CurBssParams.BSSDescriptor.wmmIE.AcParams[acVal];
+
+        /* Acm bit */
+        qstatus.acStatus[acVal].wmmAcm = pWmmIeAC->AciAifsn.Acm;
+
+        /* Firmware status */
+        qstatus.acStatus[acVal].flowRequired = pACStatus->FlowRequired;
+        qstatus.acStatus[acVal].flowCreated = pACStatus->FlowCreated;
+        qstatus.acStatus[acVal].disabled = pACStatus->Disabled;
+    }
+
+    if (copy_to_user(wrq->u.data.pointer, &qstatus, sizeof(qstatus))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ *  Receive a ADDTS command from the application.  The command structure
+ *    contains a TSPEC and timeout in milliseconds.  The timeout is performed
+ *    in the firmware after the ADDTS command frame is sent.  
+ *
+ *  The TSPEC is received in the API as an opaque block whose length is 
+ *    calculated from the IOCTL data length.  The firmware will send the 
+ *    entire data block, including the bytes after the TSPEC.  This is done
+ *    to allow extra IEs to be packaged with the TSPEC in the ADDTS action
+ *    frame.
+ *
+ *  The IOCTL structure contains two return fields: 
+ *    - The firmware command result which indicates failure and timeouts
+ *    - The IEEE Status code which contains the corresponding value from
+ *      any ADDTS response frame received.
+ *
+ *  In addition, the opaque TSPEC data block passed in is replaced with the 
+ *    TSPEC recieved in the ADDTS response frame.  In case of failure, the
+ *    AP may modify the TSPEC on return and in the case of success, the 
+ *    medium time is returned as calculated by the AP.  Along with the TSPEC,
+ *    any IEs that are sent in the ADDTS response are also returned and can be
+ *    parsed using the IOCTL length as an indicator of extra elements.
+ *
+ *  The return value to the application layer indicates a driver execution
+ *    success or failure.  A successful return could still indicate a firmware
+ *    failure or AP negotiation failure via the commandResult field copied
+ *    back to the application.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_addts_req_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    static int dialogTok = 0;
+    wlan_ioctl_wmm_addts_req_t addtsIoctl;
+    wlan_cmd_wmm_addts_req_t addtsCmd;
+    int retcode;
+
+    if (copy_from_user(&addtsIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(addtsIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "TSPEC: ADDTS copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memset(&addtsCmd, 0x00, sizeof(addtsCmd));
+        addtsCmd.dialogToken = ++dialogTok;
+        addtsCmd.timeout_ms = addtsIoctl.timeout_ms;
+        addtsCmd.tspecDataLen = (wrq->u.data.length
+                                 - sizeof(addtsCmd.timeout_ms)
+                                 - sizeof(addtsCmd.commandResult)
+                                 - sizeof(addtsCmd.ieeeStatusCode));
+        memcpy(addtsCmd.tspecData,
+               addtsIoctl.tspecData, addtsCmd.tspecDataLen);
+
+        retcode = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_WMM_ADDTS_REQ, 0,
+                                        HostCmd_OPTION_WAITFORRSP, 0,
+                                        &addtsCmd);
+
+        wrq->u.data.length = (sizeof(addtsIoctl.timeout_ms)
+                              + sizeof(addtsIoctl.commandResult)
+                              + sizeof(addtsIoctl.ieeeStatusCode)
+                              + addtsCmd.tspecDataLen);
+
+        addtsIoctl.commandResult = addtsCmd.commandResult;
+        addtsIoctl.ieeeStatusCode = addtsCmd.ieeeStatusCode;
+        memcpy(addtsIoctl.tspecData,
+               addtsCmd.tspecData, addtsCmd.tspecDataLen);
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         &addtsIoctl, sizeof(addtsIoctl))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+
+        if (retcode) {
+            return -EFAULT;
+        }
+    }
+
+    return retcode;
+}
+
+/**
+ *  @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ *  Receive a DELTS command from the application.  The command structure
+ *    contains a TSPEC and reason code along with space for a command result
+ *    to be returned.  The information is packaged is sent to the wlan_cmd.c
+ *    firmware command prep and send routines for execution in the firmware.
+ *
+ *  The reason code is not used for WMM implementations but is indicated in
+ *    the 802.11e specification.
+ *
+ *  The return value to the application layer indicates a driver execution
+ *    success or failure.  A successful return could still indicate a firmware
+ *    failure via the commandResult field copied back to the application.
+ *  
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_delts_req_t struct for this DELTS request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_delts_req_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_delts_req_t deltsIoctl;
+    wlan_cmd_wmm_delts_req_t deltsCmd;
+    int retcode;
+
+    if (copy_from_user(&deltsIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(deltsIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "TSPEC: DELTS copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memset(&deltsCmd, 0x00, sizeof(deltsCmd));
+
+        /* Dialog token unused for WMM implementations */
+        deltsCmd.dialogToken = 0;
+
+        deltsCmd.ieeeReasonCode = deltsIoctl.ieeeReasonCode;
+
+        /* Calculate the length of the TSPEC and any other IEs */
+        deltsCmd.tspecDataLen = (wrq->u.data.length
+                                 - sizeof(deltsCmd.commandResult)
+                                 - sizeof(deltsCmd.ieeeReasonCode));
+        memcpy(deltsCmd.tspecData,
+               deltsIoctl.tspecData, deltsCmd.tspecDataLen);
+
+        /* Send the DELTS request to firmware, wait for a response */
+        retcode = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_WMM_DELTS_REQ, 0,
+                                        HostCmd_OPTION_WAITFORRSP, 0,
+                                        &deltsCmd);
+
+        /* Return the firmware command result back to the application layer */
+        deltsIoctl.commandResult = deltsCmd.commandResult;
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         &deltsCmd,
+                         MIN(wrq->u.data.length, sizeof(deltsIoctl)))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+
+        if (retcode) {
+            retcode = -EFAULT;
+        }
+    }
+
+    return retcode;
+}
+
+/**
+ *  @brief Process the ADDTS_REQ command response from firmware
+ *
+ *  Return the ADDTS firmware response to the calling thread that sent 
+ *    the command.  The result is then relayed back the app layer.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer including the 
+ *                 command result and any returned ADDTS response TSPEC
+ *                 elements 
+ * 
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ */
+int
+wlan_cmdresp_wmm_addts_req(wlan_private * priv,
+                           const HostCmd_DS_COMMAND * resp)
+{
+    wlan_cmd_wmm_addts_req_t *pAddTsCmd;
+    const HostCmd_DS_WMM_ADDTS_REQ *pCmdResp;
+    u32 u32tSpecDataLen = 0;
+
+    /* Cast the NULL pointer of the buffer the IOCTL sent in the command req */
+    pAddTsCmd = (wlan_cmd_wmm_addts_req_t *) priv->adapter->CurCmd->pdata_buf;
+
+    /* Convenience variable for the ADDTS response from the firmware */
+    pCmdResp = &resp->params.addTsReq;
+
+    /* Assign return data */
+
+    pAddTsCmd->commandResult = pCmdResp->commandResult;
+
+    if (pCmdResp->commandResult == TSPEC_RESULT_SUCCESS) {
+        /* The tspecData field is potentially variable in size due to extra IEs
+         *   that may have been in the ADDTS response action frame.  Calculate
+         *   the data length from the firmware command response.
+         */
+        pAddTsCmd->tspecDataLen = (resp->Size
+                                   - sizeof(pCmdResp->commandResult)
+                                   - sizeof(pCmdResp->timeout_ms)
+                                   - sizeof(pCmdResp->dialogToken)
+                                   - sizeof(pCmdResp->ieeeStatusCode)
+                                   - S_DS_GEN);
+
+        u32tSpecDataLen = MAX(pAddTsCmd->tspecDataLen,
+                              sizeof(pAddTsCmd->tspecData)
+                              + sizeof(pAddTsCmd->addtsExtraIEBuf));
+
+        if (u32tSpecDataLen <= WMM_TSPEC_SIZE) {
+
+            /* Copy back the TSPEC data including any extra IEs after the TSPEC */
+            memcpy(pAddTsCmd->tspecData,
+                   pCmdResp->tspecData, u32tSpecDataLen);
+            pAddTsCmd->dialogToken = pCmdResp->dialogToken;
+            pAddTsCmd->ieeeStatusCode = pCmdResp->ieeeStatusCode;
+        } else {
+            PRINTM(INFO, "Invalid tspect data length =%d\n", u32tSpecDataLen);
+            return WLAN_STATUS_FAILURE;
+        }
+    } else {
+        pAddTsCmd->tspecDataLen = 0;
+        pAddTsCmd->dialogToken = 0;
+        pAddTsCmd->ieeeStatusCode = 0;
+    }
+
+    PRINTM(INFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
+           pAddTsCmd->commandResult, pAddTsCmd->ieeeStatusCode,
+           pAddTsCmd->tspecDataLen);
+
+    HEXDUMP("TSPEC: ADDTS data",
+            pAddTsCmd->tspecData, pAddTsCmd->tspecDataLen);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the DELTS_REQ command response from firmware
+ *
+ *  Return the DELTS firmware response to the calling thread that sent 
+ *    the command.  The result is then relayed back the app layer.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer with the command
+ *                 result.  No other response information is passed back 
+ *                 to the driver.
+ * 
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ */
+int
+wlan_cmdresp_wmm_delts_req(wlan_private * priv,
+                           const HostCmd_DS_COMMAND * resp)
+{
+    wlan_cmd_wmm_delts_req_t *pDelTsCmd;
+
+    /* Cast the NULL pointer of the buffer the IOCTL sent in the command req */
+    pDelTsCmd = (wlan_cmd_wmm_delts_req_t *) priv->adapter->CurCmd->pdata_buf;
+
+    pDelTsCmd->commandResult =
+        wlan_le16_to_cpu(resp->params.delTsReq.commandResult);
+
+    PRINTM(INFO, "TSPEC: DELTS result = %d\n", pDelTsCmd->commandResult);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Implement cmd HostCmd_DS_WMM_ADDTS_REQ
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param cmd     Pointer to CMD buffer 
+ *  @param InfoBuf Pointer to cmd data
+ *
+ *  @return        WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ */
+int
+wlan_cmd_wmm_addts_req(wlan_private * priv,
+                       HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    wlan_cmd_wmm_addts_req_t *pAddTsCmd;
+    int tspecCopySize;
+
+    pAddTsCmd = (wlan_cmd_wmm_addts_req_t *) InfoBuf;
+
+    cmd->params.addTsReq.timeout_ms = pAddTsCmd->timeout_ms;
+    cmd->params.addTsReq.dialogToken = pAddTsCmd->dialogToken;
+
+    tspecCopySize = MIN(pAddTsCmd->tspecDataLen,
+                        sizeof(cmd->params.addTsReq.tspecData));
+    memcpy(&cmd->params.addTsReq.tspecData,
+           pAddTsCmd->tspecData, tspecCopySize);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
+    cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.addTsReq.dialogToken)
+                                 + sizeof(cmd->params.addTsReq.timeout_ms)
+                                 + sizeof(cmd->params.addTsReq.commandResult)
+                                 + sizeof(cmd->params.addTsReq.ieeeStatusCode)
+                                 + tspecCopySize + S_DS_GEN);
+
+    cmd->params.addTsReq.timeout_ms
+        = wlan_cpu_to_le32(cmd->params.addTsReq.timeout_ms);
+
+    PRINTM(INFO, "WMM: ADDTS Cmd: Data Len = %d\n", pAddTsCmd->tspecDataLen);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Implement cmd HostCmd_DS_WMM_DELTS_REQ
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      Pointer to CMD buffer 
+ *  @param InfoBuf  Void pointer cast of a wlan_cmd_wmm_delts_req_t struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ */
+int
+wlan_cmd_wmm_delts_req(wlan_private * priv,
+                       HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    wlan_cmd_wmm_delts_req_t *pDelTsCmd;
+    int tspecCopySize;
+
+    pDelTsCmd = (wlan_cmd_wmm_delts_req_t *) InfoBuf;
+
+    cmd->params.delTsReq.dialogToken = pDelTsCmd->dialogToken;
+    cmd->params.delTsReq.ieeeReasonCode = pDelTsCmd->ieeeReasonCode;
+
+    tspecCopySize = MIN(pDelTsCmd->tspecDataLen,
+                        sizeof(cmd->params.delTsReq.tspecData));
+    memcpy(&cmd->params.delTsReq.tspecData,
+           pDelTsCmd->tspecData, tspecCopySize);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
+    cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.delTsReq.dialogToken)
+                                 + sizeof(cmd->params.delTsReq.commandResult)
+                                 + sizeof(cmd->params.delTsReq.ieeeReasonCode)
+                                 + tspecCopySize + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: DELTS Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Prepare the firmware command buffer for the WMM_QUEUE_CONFIG command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      Pointer to CMD buffer 
+ *  @param InfoBuf  Void pointer cast of a wlan_cmd_wmm_queue_config_t struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_queue_config(wlan_private * priv,
+                          HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    wlan_cmd_wmm_queue_config_t *pQConfigCmd;
+    int tlvCopySize;
+
+    pQConfigCmd = (wlan_cmd_wmm_queue_config_t *) InfoBuf;
+
+    cmd->params.queueConfig.action = pQConfigCmd->action;
+    cmd->params.queueConfig.accessCategory = pQConfigCmd->accessCategory;
+    cmd->params.queueConfig.msduLifetimeExpiry
+        = wlan_cpu_to_le16(pQConfigCmd->msduLifetimeExpiry);
+
+    tlvCopySize = MIN(pQConfigCmd->tlvBufLen,
+                      sizeof(cmd->params.queueConfig.tlvBuffer));
+    memcpy(&cmd->params.queueConfig.tlvBuffer,
+           pQConfigCmd->tlvBuffer, tlvCopySize);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
+    cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.queueConfig.action)
+                                 +
+                                 sizeof(cmd->params.queueConfig.
+                                        accessCategory)
+                                 +
+                                 sizeof(cmd->params.queueConfig.
+                                        msduLifetimeExpiry)
+                                 + tlvCopySize + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: QUEUE CONFIG Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the WMM_QUEUE_CONFIG command response from firmware
+ *
+ *  Return the firmware command response to the blocked IOCTL caller function.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer with:
+ *                      - action code
+ *                      - access category
+ *                      - collected statistics if requested 
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_queue_config_ioctl
+ */
+int
+wlan_cmdresp_wmm_queue_config(wlan_private * priv,
+                              const HostCmd_DS_COMMAND * resp)
+{
+    wlan_cmd_wmm_queue_config_t *pQConfigCmd;
+    const HostCmd_DS_WMM_QUEUE_CONFIG *pCmdResp;
+
+    pQConfigCmd =
+        (wlan_cmd_wmm_queue_config_t *) (priv->adapter->CurCmd->pdata_buf);
+    pCmdResp = &resp->params.queueConfig;
+
+    pQConfigCmd->action = pCmdResp->action;
+    pQConfigCmd->accessCategory = pCmdResp->accessCategory;
+    pQConfigCmd->msduLifetimeExpiry
+        = wlan_le16_to_cpu(pCmdResp->msduLifetimeExpiry);
+
+    pQConfigCmd->tlvBufLen = (resp->Size - sizeof(pCmdResp->action)
+                              - sizeof(pCmdResp->accessCategory)
+                              - sizeof(pCmdResp->msduLifetimeExpiry)
+                              - S_DS_GEN);
+
+    memcpy(pQConfigCmd->tlvBuffer,
+           pCmdResp->tlvBuffer, pQConfigCmd->tlvBufLen);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ *  Receive a AC Queue configuration command which is used to get, set, or 
+ *    default the parameters associated with a specific WMM AC Queue.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_config_t struct
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_queue_config_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_queue_config_t queueConfigIoctl;
+    wlan_cmd_wmm_queue_config_t queueConfigCmd;
+    int retcode;
+
+    PRINTM(INFO, "WMM: Queue Config IOCTL Enter\n");
+
+    if (copy_from_user(&queueConfigIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length,
+                           sizeof(queueConfigIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "WMM: Queue Config: copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memset(&queueConfigCmd, 0x00, sizeof(queueConfigCmd));
+
+        queueConfigCmd.action = queueConfigIoctl.action;
+        queueConfigCmd.accessCategory = queueConfigIoctl.accessCategory;
+        queueConfigCmd.msduLifetimeExpiry
+            = queueConfigIoctl.msduLifetimeExpiry;
+
+        /* Create a rates TLV from the supportedRates[] ioctl field */
+        queueConfigCmd.tlvBufLen = 0;
+
+        retcode = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_WMM_QUEUE_CONFIG, 0,
+                                        HostCmd_OPTION_WAITFORRSP, 0,
+                                        &queueConfigCmd);
+        if (retcode) {
+            retcode = -EFAULT;
+        } else {
+            memset(&queueConfigIoctl, 0x00, sizeof(queueConfigIoctl));
+
+            queueConfigIoctl.action = queueConfigCmd.action;
+            queueConfigIoctl.accessCategory = queueConfigCmd.accessCategory;
+            queueConfigIoctl.msduLifetimeExpiry
+                = queueConfigCmd.msduLifetimeExpiry;
+
+            wrq->u.data.length = sizeof(queueConfigIoctl);
+
+            if (copy_to_user(wrq->u.data.pointer,
+                             &queueConfigIoctl, sizeof(queueConfigIoctl))) {
+                PRINTM(INFO, "Copy to user failed\n");
+                retcode = -EFAULT;
+            }
+        }
+    }
+
+    return retcode;
+}
+
+/** 
+ *  @brief Prepare the firmware command buffer for the WMM_QUEUE_STATS command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      pointer to CMD buffer 
+ *  @param InfoBuf  void pointer cast of a HostCmd_CMD_WMM_QUEUE_STATS struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_queue_stats(wlan_private * priv,
+                         HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    memcpy(&cmd->params.queueStats, InfoBuf, sizeof(cmd->params.queueStats));
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
+                                 + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: QUEUE STATS Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the WMM_QUEUE_STATS command response from firmware
+ *
+ *  Return the firmware command response to the blocked IOCTL caller function.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer with:
+ *                      - action code
+ *                      - access category
+ *                      - collected statistics if requested 
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_queue_stats_ioctl
+ */
+int
+wlan_cmdresp_wmm_queue_stats(wlan_private * priv,
+                             const HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_WMM_QUEUE_STATS *pQueueStats =
+        (HostCmd_DS_WMM_QUEUE_STATS *) priv->adapter->CurCmd->pdata_buf;
+
+    memcpy(pQueueStats, &resp->params.queueStats, (resp->Size - S_DS_GEN));
+
+    pQueueStats->pktCount = wlan_le16_to_cpu(pQueueStats->pktCount);
+    pQueueStats->pktLoss = wlan_le16_to_cpu(pQueueStats->pktLoss);
+    pQueueStats->avgQueueDelay = wlan_le32_to_cpu(pQueueStats->avgQueueDelay);
+    pQueueStats->avgTxDelay = wlan_le32_to_cpu(pQueueStats->avgTxDelay);
+    pQueueStats->usedTime = wlan_le32_to_cpu(pQueueStats->usedTime);
+
+    PRINTM(INFO, "WMM: Queue Stats response: %d\n", resp->Size - S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
+ *
+ *  Receive a AC Queue statistics command from the application for a specific
+ *    WMM AC.  The command can:
+ *         - Turn stats on
+ *         - Turn stats off
+ *         - Collect and clear the stats 
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_stats_t struct
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_queue_stats_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_queue_stats_t queueStatsIoctl;
+    HostCmd_DS_WMM_QUEUE_STATS queueStatsCmd;
+    int retcode;
+
+    if (copy_from_user(&queueStatsIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length,
+                           sizeof(queueStatsIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "WMM: Queue Stats: copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memcpy(&queueStatsCmd, &queueStatsIoctl, sizeof(queueStatsCmd));
+
+        PRINTM(INFO, "WMM: QUEUE STATS Ioctl: %d, %d\n",
+               queueStatsCmd.action, queueStatsCmd.accessCategory);
+
+        retcode = PrepareAndSendCommand(priv,
+                                        HostCmd_CMD_WMM_QUEUE_STATS, 0,
+                                        HostCmd_OPTION_WAITFORRSP, 0,
+                                        &queueStatsCmd);
+        if (retcode) {
+            retcode = -EFAULT;
+        } else {
+            if (copy_to_user(wrq->u.data.pointer,
+                             &queueStatsCmd,
+                             MIN(wrq->u.data.length,
+                                 sizeof(queueStatsCmd)))) {
+                PRINTM(INFO, "Copy to user failed\n");
+                retcode = -EFAULT;
+            }
+        }
+    }
+
+    if (retcode != WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "WMM: QUEUE STATS Ioctl FAILED: %d, %d\n",
+               queueStatsIoctl.action, queueStatsIoctl.accessCategory);
+    }
+
+    return retcode;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wmm.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wmm.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8686_v9/wlan/wlan_wmm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8686_v9/wlan/wlan_wmm.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,125 @@
+/** @file wlan_wmm.h
+ * @brief This file contains related macros, enum, and struct
+ * of wmm functionalities
+ *
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+    09/26/05: add Doxygen format comments 
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+****************************************************/
+
+#ifndef __WLAN_WMM_H
+#define __WLAN_WMM_H
+
+/** Custom indiciation message sent to the application layer for WMM changes */
+#define WMM_CONFIG_CHANGE_INDICATION  "WMM_CONFIG_CHANGE.indication"
+
+/** Highest priority setting for a packet (uses voice AC) */
+#define WMM_HIGHEST_PRIORITY  7
+
+#ifdef __KERNEL__
+
+/** struct of WMM DESC */
+typedef struct
+{
+    u8 required;
+    u8 enabled;
+    u8 packetsQueued;
+    u8 queueStopped;
+    u32 packetsOut[MAX_AC_QUEUES];
+    u32 userPriPktTxCtrl[WMM_HIGHEST_PRIORITY + 1];     /* UP: 0 to 7 */
+
+    struct sk_buff txSkbQ[MAX_AC_QUEUES];
+    WmmAcStatus_t acStatus[MAX_AC_QUEUES];
+    wlan_wmm_ac_e acDowngradedVals[MAX_AC_QUEUES];
+
+    /** wmm queue priority table*/
+    u8 queuePriority[MAX_AC_QUEUES];
+
+    u8 qosinfo;
+} __ATTRIB_PACK__ WMM_DESC;
+
+extern void wmm_map_and_add_skb(wlan_private * priv, struct sk_buff *);
+extern u8 wmm_compute_driver_packet_delay(const struct sk_buff *skb);
+#endif
+
+extern int sendWMMStatusChangeCmd(wlan_private * priv);
+extern int wmm_lists_empty(wlan_private * priv);
+extern void wmm_cleanup_queues(wlan_private * priv);
+extern void wmm_process_tx(wlan_private * priv);
+
+extern void wmm_init(wlan_private * priv);
+extern void wmm_setup_queues(wlan_private * priv);
+extern void wmm_start_queue(wlan_private * priv);
+extern void wmm_stop_queue(wlan_private * priv);
+extern int wmm_is_queue_stopped(wlan_private * priv);
+
+extern void wmm_process_fw_iface_tx_xfer_start(wlan_private * priv);
+extern void wmm_process_fw_iface_tx_xfer_end(wlan_private * priv);
+extern void wmm_process_app_iface_tx(wlan_private * priv);
+extern wlan_wmm_ac_e wmm_convert_tos_to_ac(int tos);
+extern wlan_wmm_ac_e wmm_downgrade_ac(wlan_private * priv,
+                                      wlan_wmm_ac_e acVal);
+
+extern u32 wlan_wmm_process_association_req(wlan_private * priv,
+                                            u8 ** ppAssocBuf,
+                                            IEEEtypes_WmmParameter_t *
+                                            pWmmIE);
+
+/* 
+ *  Functions used in the cmd handling routine
+ */
+extern int wlan_cmd_wmm_get_status(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_addts_req(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_delts_req(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_queue_config(wlan_private * priv,
+                                     HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_queue_stats(wlan_private * priv,
+                                    HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+
+/* 
+ *  Functions used in the cmdresp handling routine
+ */
+extern int wlan_cmdresp_wmm_get_status(wlan_private * priv,
+                                       const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_addts_req(wlan_private * priv,
+                                      const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_delts_req(wlan_private * priv,
+                                      const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_queue_config(wlan_private * priv,
+                                         const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_queue_stats(wlan_private * priv,
+                                        const HostCmd_DS_COMMAND * resp);
+
+/* 
+ * IOCTLs 
+ */
+extern int wlan_wmm_enable_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_queue_status_ioctl(wlan_private * priv,
+                                       struct iwreq *wrq);
+
+extern int wlan_wmm_addts_req_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_delts_req_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_queue_config_ioctl(wlan_private * priv,
+                                       struct iwreq *wrq);
+extern int wlan_wmm_queue_stats_ioctl(wlan_private * priv, struct iwreq *wrq);
+#endif /* __WLAN_WMM_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_drv.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_drv.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_drv.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_drv.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,491 @@
+/** @file bt_drv.h
+ *  @brief This header file contains global constant/enum definitions,
+ *  global variable declaration.
+ *       
+ *  (c) Copyright 2007, Marvell International Ltd.   
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+
+#ifndef _BT_DRV_H_
+#define _BT_DRV_H_
+
+/** Double-Word(32Bit) Bit definition */
+/** Double-Word bit 0 */
+#define DW_BIT_0	0x00000001
+/** Double-Word bit 1 */
+#define DW_BIT_1	0x00000002
+/** Double-Word bit 2 */
+#define DW_BIT_2	0x00000004
+/** Double-Word bit 3 */
+#define DW_BIT_3	0x00000008
+/** Double-Word bit 4 */
+#define DW_BIT_4	0x00000010
+/** Double-Word bit 5 */
+#define DW_BIT_5	0x00000020
+/** Double-Word bit 6 */
+#define DW_BIT_6	0x00000040
+/** Double-Word bit 7 */
+#define DW_BIT_7	0x00000080
+/** Double-Word bit 8 */
+#define DW_BIT_8	0x00000100
+/** Double-Word bit 9 */
+#define DW_BIT_9	0x00000200
+/** Double-Word bit 10 */
+#define DW_BIT_10	0x00000400
+/** Double-Word bit 11 */
+#define DW_BIT_11       0x00000800
+/** Double-Word bit 12 */
+#define DW_BIT_12       0x00001000
+/** Double-Word bit 13 */
+#define DW_BIT_13       0x00002000
+/** Double-Word bit 14 */
+#define DW_BIT_14       0x00004000
+/** Double-Word bit 15 */
+#define DW_BIT_15       0x00008000
+/** Double-Word bit 16 */
+#define DW_BIT_16       0x00010000
+/** Double-Word bit 17 */
+#define DW_BIT_17       0x00020000
+/** Double-Word bit 18 */
+#define DW_BIT_18       0x00040000
+/** Double-Word bit 19 */
+#define DW_BIT_19       0x00080000
+/** Double-Word bit 20 */
+#define DW_BIT_20       0x00100000
+/** Double-Word bit 21 */
+#define DW_BIT_21       0x00200000
+/** Double-Word bit 22 */
+#define DW_BIT_22       0x00400000
+/** Double-Word bit 23 */
+#define DW_BIT_23       0x00800000
+/** Double-Word bit 24 */
+#define DW_BIT_24       0x01000000
+/** Double-Word bit 25 */
+#define DW_BIT_25       0x02000000
+/** Double-Word bit 26 */
+#define DW_BIT_26       0x04000000
+/** Double-Word bit 27 */
+#define DW_BIT_27       0x08000000
+/** Double-Word bit 28 */
+#define DW_BIT_28       0x10000000
+/** Double-Word bit 29 */
+#define DW_BIT_29       0x20000000
+/** Double-Word bit 30 */
+#define DW_BIT_30	0x40000000
+/** Double-Word bit 31 */
+#define DW_BIT_31	0x80000000
+
+/** Word (16bit) Bit Definition*/
+/** Word bit 0 */
+#define W_BIT_0		0x0001
+/** Word bit 1 */
+#define W_BIT_1		0x0002
+/** Word bit 2 */
+#define W_BIT_2		0x0004
+/** Word bit 3 */
+#define W_BIT_3		0x0008
+/** Word bit 4 */
+#define W_BIT_4		0x0010
+/** Word bit 5 */
+#define W_BIT_5		0x0020
+/** Word bit 6 */
+#define W_BIT_6		0x0040
+/** Word bit 7 */
+#define W_BIT_7		0x0080
+/** Word bit 8 */
+#define W_BIT_8		0x0100
+/** Word bit 9 */
+#define W_BIT_9		0x0200
+/** Word bit 10 */
+#define W_BIT_10	0x0400
+/** Word bit 11 */
+#define W_BIT_11	0x0800
+/** Word bit 12 */
+#define W_BIT_12	0x1000
+/** Word bit 13 */
+#define W_BIT_13	0x2000
+/** Word bit 14 */
+#define W_BIT_14	0x4000
+/** Word bit 15 */
+#define W_BIT_15	0x8000
+
+/** Byte (8Bit) Bit definition*/
+/** Byte bit 0 */
+#define B_BIT_0		0x01
+/** Byte bit 1 */
+#define B_BIT_1		0x02
+/** Byte bit 2 */
+#define B_BIT_2		0x04
+/** Byte bit 3 */
+#define B_BIT_3		0x08
+/** Byte bit 4 */
+#define B_BIT_4		0x10
+/** Byte bit 5 */
+#define B_BIT_5		0x20
+/** Byte bit 6 */
+#define B_BIT_6		0x40
+/** Byte bit 7 */
+#define B_BIT_7		0x80
+
+/** Debug level : Message */
+#define	DBG_MSG			DW_BIT_0
+/** Debug level : Fatal */
+#define DBG_FATAL		DW_BIT_1
+/** Debug level : Error */
+#define DBG_ERROR		DW_BIT_2
+/** Debug level : Command */
+#define DBG_CMD			DW_BIT_3
+/** Debug level : Data */
+#define DBG_DATA		DW_BIT_27
+/** Debug level : Entry */
+#define DBG_ENTRY		DW_BIT_28
+/** Debug level : Warning */
+#define DBG_WARN		DW_BIT_29
+/** Debug level : Informative */
+#define DBG_INFO		DW_BIT_30
+
+#ifdef	DEBUG_LEVEL1
+extern u32 drvdbg;
+
+/** Print informative message */
+#define	PRINTM_INFO(msg...)  {if (drvdbg & DBG_INFO)  printk(KERN_DEBUG msg);}
+/** Print warning message */
+#define	PRINTM_WARN(msg...)  {if (drvdbg & DBG_WARN)  printk(KERN_DEBUG msg);}
+/** Print entry message */
+#define	PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
+/** Print command message */
+#define	PRINTM_CMD(msg...)   {if (drvdbg & DBG_CMD)   printk(KERN_DEBUG msg);}
+/** Print erro message */
+#define	PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
+/** Print fatal message */
+#define	PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
+/** Print message */
+#define	PRINTM_MSG(msg...)   {if (drvdbg & DBG_MSG)   printk(KERN_ALERT msg);}
+
+/** Print message with required level */
+#define	PRINTM(level,msg...) PRINTM_##level(msg)
+
+/** Debug dump buffer length */
+#define DBG_DUMP_BUF_LEN 	64
+/** Maximum number of dump per line */
+#define MAX_DUMP_PER_LINE	16
+/** Maximum data dump length */
+#define MAX_DATA_DUMP_LEN	48
+
+static inline void
+hexdump(char *prompt, u8 * buf, int len)
+{
+    int i;
+    char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+    char *ptr = dbgdumpbuf;
+
+    printk(KERN_DEBUG "%s: len=%d\n", prompt, len);
+    for (i = 1; i <= len; i++) {
+        ptr += sprintf(ptr, "%02x ", *buf);
+        buf++;
+        if (i % MAX_DUMP_PER_LINE == 0) {
+            *ptr = 0;
+            printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+            ptr = dbgdumpbuf;
+        }
+    }
+    if (len % MAX_DUMP_PER_LINE) {
+        *ptr = 0;
+        printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+    }
+}
+
+/** Debug hexdump of debug data */
+#define DBG_HEXDUMP_DBG_DATA(x,y,z)     {if (drvdbg & DBG_DATA) hexdump(x,y,z);}
+
+/** Debug hexdump */
+#define	DBG_HEXDUMP(level,x,y,z)    DBG_HEXDUMP_##level(x,y,z)
+
+/** Mark entry point */
+#define	ENTER()			PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
+							__FILE__, __LINE__)
+/** Mark exit point */
+#define	LEAVE()			PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
+							__FILE__, __LINE__)
+#else
+/** Do nothing */
+#define	PRINTM(level,msg...) do {} while (0)
+/** Do nothing */
+#define DBG_HEXDUMP(level,x,y,z)    do {} while (0)
+/** Do nothing */
+#define	ENTER()  do {} while (0);
+/** Do nothing */
+#define	LEAVE()  do {} while (0);
+#endif //DEBUG_LEVEL1
+
+/** Length of device name */
+#define DEV_NAME_LEN				32
+/** Bluetooth upload size */
+#define	BT_UPLD_SIZE				2312
+/** Bluetooth status success */
+#define BT_STATUS_SUCCESS			(0)
+/** Bluetooth status failure */
+#define BT_STATUS_FAILURE			(-1)
+
+#ifndef	TRUE
+/** True value */
+#define TRUE			1
+#endif
+#ifndef	FALSE
+/** False value */
+#define	FALSE			0
+#endif
+
+/** Set thread state */
+#define OS_SET_THREAD_STATE(x)		set_current_state(x)
+/** Time to wait until Host Sleep state change */
+#define WAIT_UNTIL_HS_STATE_CHANGED (5 * HZ)
+/** Time to wait cmd resp */
+#define WAIT_UNTIL_CMD_RESP	    (5 * HZ)
+
+/** Set interruptible timeout value */
+#define os_wait_interruptible_timeout(waitq, cond, timeout) \
+	wait_event_interruptible_timeout(waitq, cond, timeout)
+
+typedef struct
+{
+    /** Task */
+    struct task_struct *task;
+    /** Queue */
+    wait_queue_head_t waitQ;
+    /** PID */
+    pid_t pid;
+    /** Private structure */
+    void *priv;
+} bt_thread;
+
+static inline void
+bt_activate_thread(bt_thread * thr)
+{
+        /** Record the thread pid */
+    thr->pid = current->pid;
+
+        /** Initialize the wait queue */
+    init_waitqueue_head(&thr->waitQ);
+}
+
+static inline void
+bt_deactivate_thread(bt_thread * thr)
+{
+    thr->pid = 0;
+    return;
+}
+
+static inline void
+bt_create_thread(int (*btfunc) (void *), bt_thread * thr, char *name)
+{
+    thr->task = kthread_run(btfunc, thr, "%s", name);
+}
+
+static inline int
+bt_terminate_thread(bt_thread * thr)
+{
+    /* Check if the thread is active or not */
+    if (!thr->pid) {
+        return -1;
+    }
+    kthread_stop(thr->task);
+    return 0;
+}
+
+static inline void
+os_sched_timeout(u32 millisec)
+{
+    set_current_state(TASK_INTERRUPTIBLE);
+
+    schedule_timeout((millisec * HZ) / 1000);
+}
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+/** Data structure for the Marvell Bluetooth device */
+typedef struct _bt_dev
+{
+        /** device name */
+    char name[DEV_NAME_LEN];
+        /** card pointer */
+    void *card;
+        /** IO port */
+    u32 ioport;
+    /** HCI device */
+    struct hci_dev *hcidev;
+
+    /** Tx download ready flag */
+    u8 tx_dnld_rdy;
+    /** Function */
+    u8 fn;
+    /** Rx unit */
+    u8 rx_unit;
+    /** Power Save mode */
+    u8 psmode;
+    /** Power Save command */
+    u8 pscmd;
+    /** Host Sleep mode */
+    u8 hsmode;
+    /** Host Sleep command */
+    u8 hscmd;
+    /** Low byte is gap, high byte is GPIO */
+    u16 gpio_gap;
+    /** Host Sleep configuration command */
+    u8 hscfgcmd;
+    /** Host Send Cmd Flag		 */
+    u8 sendcmdflag;
+} bt_dev_t, *pbt_dev_t;
+
+typedef struct _bt_adapter
+{
+    /** Temporry Tx buffer */
+    u8 TmpTxBuf[BT_UPLD_SIZE] __ATTRIB_ALIGN__;
+    /** Chip revision ID */
+    u8 chip_rev;
+    /** Surprise removed flag */
+    u8 SurpriseRemoved;
+    /** IRQ number */
+    int irq;
+    /** Interrupt counter */
+    u32 IntCounter;
+    /** Tx packet queue */
+    struct sk_buff_head tx_queue;
+    /** Power Save mode */
+    u8 psmode;
+    /** Power Save state */
+    u8 ps_state;
+    /** Host Sleep state */
+    u8 hs_state;
+    /** Number of wakeup tries */
+    u8 WakeupTries;
+    /** Host Sleep wait queue */
+    wait_queue_head_t cmd_wait_q __ATTRIB_ALIGN__;
+    /** Host Cmd complet state */
+    u8 cmd_complete;
+} bt_adapter, *pbt_adapter;
+
+/** Private structure for the MV device */
+typedef struct _bt_private
+{
+    /** Bluetooth device */
+    bt_dev_t bt_dev;
+    /** Adapter */
+    bt_adapter *adapter;
+    /** Firmware helper */
+    const struct firmware *fw_helper;
+    /** Firmware */
+    const struct firmware *firmware;
+    /** Hotplug device */
+    struct device *hotplug_device;
+        /** thread to service interrupts */
+    bt_thread MainThread;
+    /** Proc directory entry */
+    struct proc_dir_entry *proc_entry;
+    /** Proc mbt directory entry */
+    struct proc_dir_entry *proc_mbt;
+} bt_private, *pbt_private;
+
+/** Marvell vendor packet */
+#define MRVL_VENDOR_PKT			0xFE
+/** Bluetooth command : Sleep mode */
+#define BT_CMD_AUTO_SLEEP_MODE		0x23
+/** Bluetooth command : Host Sleep configuration */
+#define BT_CMD_HOST_SLEEP_CONFIG	0x59
+/** Bluetooth command : Host Sleep enable */
+#define BT_CMD_HOST_SLEEP_ENABLE	0x5A
+/** Bluetooth command : Module Configuration request */
+#define BT_CMD_MODULE_CFG_REQ		0x5B
+/** Sub Command: Module Bring Up Request */
+#define MODULE_BRINGUP_REQ		0xF1
+/** Sub Command: Module Shut Down Request */
+#define MODULE_SHUTDOWN_REQ		0xF2
+/** Sub Command: Host Interface Control Request */
+#define MODULE_INTERFACE_CTRL_REQ	0xF5
+
+/** Bluetooth event : Power State */
+#define BT_EVENT_POWER_STATE		0x20
+
+/** Bluetooth Power State : Enable */
+#define BT_PS_ENABLE			0x02
+/** Bluetooth Power State : Disable */
+#define BT_PS_DISABLE			0x03
+/** Bluetooth Power State : Sleep */
+#define BT_PS_SLEEP			0x01
+/** Bluetooth Power State : Awake */
+#define BT_PS_AWAKE			0x02
+
+/** OGF */
+#define OGF				0x3F
+
+/** Host Sleep activated */
+#define HS_ACTIVATED			0x01
+/** Host Sleep deactivated */
+#define HS_DEACTIVATED			0x00
+
+/** Power Save sleep */
+#define PS_SLEEP			0x01
+/** Power Save awake */
+#define PS_AWAKE			0x00
+
+typedef struct _BT_CMD
+{
+    /** OCF OGF */
+    u16 ocf_ogf;
+    /** Length */
+    u8 length;
+    /** Data */
+    u8 data[4];
+} __ATTRIB_PACK__ BT_CMD;
+
+typedef struct _BT_EVENT
+{
+    /** Event Counter */
+    u8 EC;
+    /** Length */
+    u8 length;
+    /** Data */
+    u8 data[4];
+} BT_EVENT;
+
+/* Prototype of global function */
+bt_private *bt_add_card(void *card);
+int bt_remove_card(void *card);
+void bt_interrupt(struct hci_dev *hdev);
+
+int bt_proc_init(bt_private * priv);
+void bt_proc_remove(bt_private * priv);
+int bt_process_event(bt_private * priv, struct sk_buff *skb);
+int bt_enable_hs(bt_private * priv);
+int bt_prepare_command(bt_private * priv);
+
+int *sbi_register(void);
+void sbi_unregister(void);
+int sbi_register_dev(bt_private * priv);
+int sbi_unregister_dev(bt_private * priv);
+int sbi_host_to_card(bt_private * priv, u8 type, u8 * payload, u16 nb);
+int sbi_enable_host_int(bt_private * priv);
+int sbi_disable_host_int(bt_private * priv);
+int sbi_dowload_fw(bt_private * priv);
+int sbi_get_int_status(bt_private * priv, u8 * ireg);
+int sbi_wakeup_firmware(bt_private * priv);
+int sbi_download_fw(bt_private *priv);
+#endif /* _BT_DRV_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_main.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_main.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_main.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_main.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,820 @@
+/** @file bt_main.c
+  *  
+  * @brief This file contains the major functions in BlueTooth
+  * driver. It includes init, exit, open, close and main
+  * thread etc..
+  * 
+  * (c) Copyright 2007, Marvell International Ltd. 
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+
+#include "include.h"
+
+/** Version */
+#define VERSION "1.15"
+
+/** Bluetooth device private structure */
+bt_private *btpriv = NULL;
+/** Firmware flag */
+int fw = 1;
+
+
+#ifdef	DEBUG_LEVEL1
+u32 drvdbg = DBG_MSG | DBG_FATAL | DBG_ERROR;
+//u32 drvdbg = 0xffffffff;
+#endif
+
+/** Driver lock */
+spinlock_t driver_lock;
+/** Driver lock flags */
+ulong driver_flags;
+
+/** Disable interrupt */
+#define OS_INT_DISABLE	spin_lock_irqsave(&driver_lock, driver_flags)
+/** Enable interrupt */
+#define	OS_INT_RESTORE	spin_unlock_irqrestore(&driver_lock, driver_flags); \
+			driver_lock = SPIN_LOCK_UNLOCKED
+
+/** 
+ *  @brief This function verify the received acl loopback pkt
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param skb     A pointer to rx skb 
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+bt_process_event(bt_private * priv, struct sk_buff *skb)
+{
+    u8 ret = BT_STATUS_SUCCESS;
+    BT_EVENT *pEvent;
+    ENTER();
+    pEvent = (BT_EVENT *) skb->data;
+    if (pEvent->EC != 0xff) {
+        PRINTM(CMD, "Not Marvell Event=%x\n", pEvent->EC);
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+    switch (pEvent->data[0]) {
+    case BT_CMD_AUTO_SLEEP_MODE:
+        if (pEvent->data[2] == BT_STATUS_SUCCESS) {
+            if (pEvent->data[1] == BT_PS_ENABLE)
+                priv->adapter->psmode = 1;
+            else
+                priv->adapter->psmode = 0;
+            PRINTM(CMD, "PS Mode:%s\n",
+                   (priv->adapter->psmode) ? "Enable" : "Disable");
+        } else
+            PRINTM(CMD, "PS Mode Cmd Fail\n");
+        break;
+    case BT_CMD_HOST_SLEEP_CONFIG:
+        if (pEvent->data[3] == BT_STATUS_SUCCESS) {
+            PRINTM(CMD, "gpio=%x,gap=%x\n", pEvent->data[1], pEvent->data[2]);
+        } else
+            PRINTM(CMD, "HSCFG Cmd Fail\n");
+        break;
+    case BT_CMD_HOST_SLEEP_ENABLE:
+        if (pEvent->data[1] == BT_STATUS_SUCCESS) {
+            priv->adapter->hs_state = HS_ACTIVATED;
+            if (priv->adapter->psmode)
+                priv->adapter->ps_state = PS_SLEEP;
+            wake_up_interruptible(&priv->adapter->cmd_wait_q);
+            PRINTM(CMD, "HS ACTIVATED!\n");
+        } else
+            PRINTM(CMD, "HS Enable Fail\n");
+        break;
+    case BT_CMD_MODULE_CFG_REQ:
+        if ((priv->bt_dev.sendcmdflag == TRUE) &&
+            ((pEvent->data[1] == MODULE_BRINGUP_REQ)
+             || (pEvent->data[1] == MODULE_SHUTDOWN_REQ))) {
+            if (pEvent->data[1] == MODULE_BRINGUP_REQ) {
+                PRINTM(CMD, "EVENT:%s\n",
+                       (pEvent->
+                        data[2]) ? "Bring up Fail" : "Bring up success");
+            }
+            if (pEvent->data[1] == MODULE_SHUTDOWN_REQ) {
+                PRINTM(CMD, "EVENT:%s\n",
+                       (pEvent->
+                        data[2]) ? "Shut down Fail" : "Shut down success");
+            }
+            priv->bt_dev.sendcmdflag = FALSE;
+            priv->adapter->cmd_complete = TRUE;
+            wake_up_interruptible(&priv->adapter->cmd_wait_q);
+        } else {
+            PRINTM(CMD, "BT_CMD_MODULE_CFG_REQ resp for APP\n");
+                ret = BT_STATUS_FAILURE;
+        }
+        break;
+    case BT_EVENT_POWER_STATE:
+        if (pEvent->data[1] == BT_PS_SLEEP)
+            priv->adapter->ps_state = PS_SLEEP;
+        PRINTM(CMD, "EVENT:%s\n",
+               (priv->adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE");
+        break;
+    default:
+        PRINTM(CMD, "Unknow Event=%d\n", pEvent->data[0]);
+        ret = BT_STATUS_FAILURE;
+        break;
+    }
+  exit:
+    if (ret == BT_STATUS_SUCCESS)
+        kfree_skb(skb);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function send module cfg cmd to firmware
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param subcmd  sub command 
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+bt_send_module_cfg_cmd(bt_private * priv, int subcmd)
+{
+    struct sk_buff *skb = NULL;
+    u8 ret = BT_STATUS_SUCCESS;
+    BT_CMD *pCmd;
+    ENTER();
+    skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+    if (skb == NULL) {
+        PRINTM(WARN, "No free skb\n");
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+    pCmd = (BT_CMD *) skb->tail;
+    pCmd->ocf_ogf = (OGF << 10) | BT_CMD_MODULE_CFG_REQ;
+    pCmd->length = 1;
+    pCmd->data[0] = subcmd;
+    bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+    skb_put(skb, sizeof(BT_CMD));
+    skb->dev = (void *) priv->bt_dev.hcidev;
+    skb_queue_head(&priv->adapter->tx_queue, skb);
+    priv->bt_dev.sendcmdflag = TRUE;
+    priv->adapter->cmd_complete = FALSE;
+    PRINTM(CMD, "Queue module cfg Command\n");
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    if (!os_wait_interruptible_timeout
+        (priv->adapter->cmd_wait_q, priv->adapter->cmd_complete,
+         WAIT_UNTIL_CMD_RESP)) {
+        ret = BT_STATUS_FAILURE;
+        PRINTM(MSG, "module_cfg_cmd(%x): timeout: %d\n", subcmd,
+               priv->bt_dev.sendcmdflag);
+    }
+    PRINTM(CMD, "module cfg Command done\n");
+  exit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function enable host sleep 
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+bt_enable_hs(bt_private * priv)
+{
+    struct sk_buff *skb = NULL;
+    u8 ret = BT_STATUS_SUCCESS;
+    BT_CMD *pCmd;
+    ENTER();
+    skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+    if (skb == NULL) {
+        PRINTM(WARN, "No free skb\n");
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+    pCmd = (BT_CMD *) skb->tail;
+    pCmd->ocf_ogf = (OGF << 10) | BT_CMD_HOST_SLEEP_ENABLE;
+    pCmd->length = 0;
+    bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+    skb_put(skb, sizeof(BT_CMD));
+    skb->dev = (void *) priv->bt_dev.hcidev;
+    skb_queue_head(&priv->adapter->tx_queue, skb);
+    PRINTM(CMD, "Queue hs enable Command\n");
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    if (!os_wait_interruptible_timeout
+        (priv->adapter->cmd_wait_q, priv->adapter->hs_state,
+         WAIT_UNTIL_HS_STATE_CHANGED)) {
+        ret = BT_STATUS_FAILURE;
+        PRINTM(MSG, "bt_enable_hs: timeout: %d, %d,%d\n",
+               priv->adapter->hs_state, priv->adapter->ps_state,
+               priv->adapter->WakeupTries);
+    }
+  exit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function used to send command to firmware
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return        BT_STATUS_SUCCESS
+ */
+int
+bt_prepare_command(bt_private * priv)
+{
+    struct sk_buff *skb = NULL;
+    u8 ret = BT_STATUS_SUCCESS;
+    BT_CMD *pCmd;
+    ENTER();
+    if (priv->bt_dev.hscfgcmd) {
+        priv->bt_dev.hscfgcmd = 0;
+        skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+        if (skb == NULL) {
+            PRINTM(WARN, "No free skb\n");
+            ret = BT_STATUS_FAILURE;
+            goto exit;
+        }
+        pCmd = (BT_CMD *) skb->tail;
+        pCmd->ocf_ogf = (OGF << 10) | BT_CMD_HOST_SLEEP_CONFIG;
+        pCmd->length = 2;
+        pCmd->data[0] = (priv->bt_dev.gpio_gap & 0xff00) >> 8;
+        pCmd->data[1] = (u8) (priv->bt_dev.gpio_gap & 0x00ff);
+        bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+        skb_put(skb, sizeof(BT_CMD));
+        skb->dev = (void *) priv->bt_dev.hcidev;
+        skb_queue_head(&priv->adapter->tx_queue, skb);
+        PRINTM(CMD, "Queue HSCFG Command,gpio=%x,gap=%x\n", pCmd->data[0],
+               pCmd->data[1]);
+    }
+    if (priv->bt_dev.pscmd) {
+        priv->bt_dev.pscmd = 0;
+        skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
+        if (skb == NULL) {
+            PRINTM(WARN, "No free skb\n");
+            ret = BT_STATUS_FAILURE;
+            goto exit;
+        }
+        pCmd = (BT_CMD *) skb->tail;
+        pCmd->ocf_ogf = (OGF << 10) | BT_CMD_AUTO_SLEEP_MODE;
+        pCmd->length = 1;
+        if (priv->bt_dev.psmode)
+            pCmd->data[0] = BT_PS_ENABLE;
+        else
+            pCmd->data[0] = BT_PS_DISABLE;
+        bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+        skb_put(skb, sizeof(BT_CMD));
+        skb->dev = (void *) priv->bt_dev.hcidev;
+        skb_queue_head(&priv->adapter->tx_queue, skb);
+        PRINTM(CMD, "Queue PSMODE Command:%d\n", pCmd->data[0]);
+    }
+    if (priv->bt_dev.hscmd) {
+        priv->bt_dev.hscmd = 0;
+        if (priv->bt_dev.hsmode)
+            ret = bt_enable_hs(priv);
+        else {
+            ret = sbi_wakeup_firmware(priv);
+            priv->adapter->hs_state = HS_DEACTIVATED;
+        }
+    }
+  exit:
+    LEAVE();
+    return ret;
+}
+
+/**  @brief This function processes a single packet 
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param skb     A pointer to skb which includes TX packet
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+SendSinglePacket(bt_private * priv, struct sk_buff *skb)
+{
+    u8 ret;
+    bt_adapter *Adapter = priv->adapter;
+    ENTER();
+    if (!skb->len || ((skb->len + SDIO_HEADER_LEN) > BT_UPLD_SIZE)) {
+        PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
+               BT_UPLD_SIZE);
+        return BT_STATUS_FAILURE;
+    }
+    /*  This is SDIO specific header
+     *  length: byte[3][2][1], 
+     *  type: byte[0] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) 
+     */
+    priv->adapter->TmpTxBuf[0] = (skb->len + SDIO_HEADER_LEN) & 0xff;
+    priv->adapter->TmpTxBuf[1] = ((skb->len + SDIO_HEADER_LEN) >> 8) & 0xff;
+    priv->adapter->TmpTxBuf[2] = ((skb->len + SDIO_HEADER_LEN) >> 16) & 0xff;
+    priv->adapter->TmpTxBuf[3] = bt_cb(skb)->pkt_type;
+    memcpy(&priv->adapter->TmpTxBuf[SDIO_HEADER_LEN], skb->data, skb->len);
+    ret =
+        sbi_host_to_card(priv, MVSD_DAT, Adapter->TmpTxBuf,
+                         skb->len + SDIO_HEADER_LEN);
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function initializes the adapter structure
+ *  and set default value to the member of adapter.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   n/a
+ */
+static void
+bt_init_adapter(bt_private * priv)
+{
+    ENTER();
+    skb_queue_head_init(&priv->adapter->tx_queue);
+    priv->adapter->ps_state = PS_AWAKE;
+    init_waitqueue_head(&priv->adapter->cmd_wait_q);
+    LEAVE();
+}
+
+/** 
+ *  @brief This function initializes firmware
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+bt_init_fw(bt_private * priv)
+{
+    int ret = BT_STATUS_SUCCESS;
+    ENTER();
+    if (fw == 0) {
+        sbi_enable_host_int(priv);
+        goto done;
+    }
+    sbi_disable_host_int(priv);
+
+    if (sbi_download_fw(priv)) {
+        PRINTM(ERROR, "FW failed to be download!\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+
+    mdelay(100);
+    sbi_enable_host_int(priv);
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function frees the structure of adapter
+ *    
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   n/a
+ */
+static void
+bt_free_adapter(bt_private * priv)
+{
+    bt_adapter *Adapter = priv->adapter;
+    ENTER();
+    skb_queue_purge(&priv->adapter->tx_queue);
+    /* Free the adapter object itself */
+    kfree(Adapter);
+    priv->adapter = NULL;
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function handle the ioctl 
+ *  
+ *  @param hev     A pointer to hci_dev structure
+ *  @cmd	   ioctl cmd 
+ *  @arg	    
+ *  @return 	   -ENOIOCTLCMD
+ */
+static int
+bt_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+    ENTER();
+    LEAVE();
+    return -ENOIOCTLCMD;
+}
+
+/** 
+ *  @brief This function handle destruct 
+ *  
+ *  @param hev     A pointer to hci_dev structure
+ *  
+ *  @return 	   n/a
+ */
+static void
+bt_destruct(struct hci_dev *hdev)
+{
+    ENTER();
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function handle the transmit
+ *  
+ *  @param skb     A pointer to sk_buffer structure
+ *  
+ *  @return 	   BT_STATUS_SUCCESS or other   
+ */
+static int
+bt_send_frame(struct sk_buff *skb)
+{
+    struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+    bt_private *priv = (bt_private *) hdev->driver_data;
+
+    ENTER();
+    PRINTM(INFO, "bt_send_frame: Type=%d, len=%d\n", skb->pkt_type, skb->len);
+    DBG_HEXDUMP(DBG_DATA, "bt_send_frame", skb->data, skb->len);
+    if (!hdev) {
+        PRINTM(ERROR, "Frame for unknown HCI device (hdev=NULL)\n");
+        LEAVE();
+        return -ENODEV;
+    }
+    if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+        PRINTM(ERROR, "Fail test HCI_RUNING,flag=%lx\n", hdev->flags);
+        LEAVE();
+        return -EBUSY;
+    }
+    switch (bt_cb(skb)->pkt_type) {
+    case HCI_COMMAND_PKT:
+        hdev->stat.cmd_tx++;
+        break;
+    case HCI_ACLDATA_PKT:
+        hdev->stat.acl_tx++;
+        break;
+    case HCI_SCODATA_PKT:
+        hdev->stat.sco_tx++;
+        break;
+    }
+    skb_queue_tail(&priv->adapter->tx_queue, skb);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function flush the transmit queue
+ *  
+ *  @param hev     A pointer to hci_dev structure
+ *  
+ *  @return 	   BT_STATUS_SUCCESS   
+ */
+static int
+bt_flush(struct hci_dev *hdev)
+{
+    bt_private *priv = (bt_private *) hdev->driver_data;
+    ENTER();
+    skb_queue_purge(&priv->adapter->tx_queue);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function close the bluetooth device
+ *  
+ *  @param hev     A pointer to hci_dev structure
+ *  
+ *  @return 	   BT_STATUS_SUCCESS   
+ */
+static int
+bt_close(struct hci_dev *hdev)
+{
+    bt_private *priv = (bt_private *) hdev->driver_data;
+    ENTER();
+    if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) {
+        LEAVE();
+        return BT_STATUS_SUCCESS;
+    }
+    skb_queue_purge(&priv->adapter->tx_queue);
+    module_put(THIS_MODULE);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function open the bluetooth device
+ *  
+ *  @param hev     A pointer to hci_dev structure
+ *  
+ *  @return 	   BT_STATUS_SUCCESS  or other
+ */
+static int
+bt_open(struct hci_dev *hdev)
+{
+    ENTER();
+    if (try_module_get(THIS_MODULE) == 0)
+        return BT_STATUS_FAILURE;
+    set_bit(HCI_RUNNING, &hdev->flags);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function hanldes the major job in bluetooth driver.
+ *  it handles the event generated by firmware, rx data received
+ *  from firmware and tx data sent from kernel.
+ *  
+ *  @param data    A pointer to bt_thread structure
+ *  @return        BT_STATUS_SUCCESS
+ */
+static int
+bt_service_main_thread(void *data)
+{
+    bt_thread *thread = data;
+    bt_private *priv = thread->priv;
+    bt_adapter *Adapter = priv->adapter;
+    wait_queue_t wait;
+    u8 ireg = 0;
+    struct sk_buff *skb;
+    ENTER();
+    bt_activate_thread(thread);
+    init_waitqueue_entry(&wait, current);
+    current->flags |= PF_NOFREEZE;
+
+    for (;;) {
+        add_wait_queue(&thread->waitQ, &wait);
+        OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
+        if (priv->adapter->WakeupTries ||
+            ((!priv->adapter->IntCounter) &&
+             (!priv->bt_dev.tx_dnld_rdy ||
+              skb_queue_empty(&priv->adapter->tx_queue)))) {
+            PRINTM(INFO, "Main: Thread sleeping...\n");
+            schedule();
+        }
+        OS_SET_THREAD_STATE(TASK_RUNNING);
+        remove_wait_queue(&thread->waitQ, &wait);
+        if (kthread_should_stop() || Adapter->SurpriseRemoved) {
+            PRINTM(INFO, "main-thread: break from main thread: "
+                   "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
+            break;
+        }
+
+        PRINTM(INFO, "Main: Thread waking up...\n");
+        if (priv->adapter->IntCounter) {
+		OS_INT_DISABLE;
+		Adapter->IntCounter = 0;
+		OS_INT_RESTORE;
+		//sbi_get_int_status(priv, &ireg);
+        } else if ((priv->adapter->ps_state == PS_SLEEP) &&
+                   !skb_queue_empty(&priv->adapter->tx_queue)) {
+		priv->adapter->WakeupTries++;
+		sbi_wakeup_firmware(priv);
+		continue;
+        }
+		
+        if (priv->adapter->ps_state == PS_SLEEP)
+  		continue;
+        if (priv->bt_dev.tx_dnld_rdy == TRUE) {
+            if (!skb_queue_empty(&priv->adapter->tx_queue)) {
+                skb = skb_dequeue(&priv->adapter->tx_queue);
+                if (skb) {
+                    if (SendSinglePacket(priv, skb))
+                        priv->bt_dev.hcidev->stat.err_tx++;
+                    else
+                        priv->bt_dev.hcidev->stat.byte_tx += skb->len;
+                    kfree_skb(skb);
+                }
+            }
+        }
+    }
+    bt_deactivate_thread(thread);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the interrupt. it will change PS
+ *  state if applicable. it will wake up main_thread to handle
+ *  the interrupt event as well.
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        n/a
+ */
+void
+bt_interrupt(struct hci_dev *hdev)
+{
+    bt_private *priv = (bt_private *) hdev->driver_data;
+    ENTER();
+    priv->adapter->ps_state = PS_AWAKE;
+    priv->adapter->hs_state = HS_DEACTIVATED;
+    priv->adapter->WakeupTries = 0;
+    priv->adapter->IntCounter++;
+    /* masked by feng */
+    //wake_up_interruptible(&priv->MainThread.waitQ);
+    LEAVE();
+
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the bt_priv and initialize the device. 
+ *  
+ *  @param card    A pointer to card
+ *  @return        A pointer to bt_private structure
+ */
+
+bt_private *
+bt_add_card(void *card)
+{
+    struct hci_dev *hdev = NULL;
+    bt_private *priv = NULL;
+    int ret;
+
+    ENTER();
+
+    priv = kzalloc(sizeof(bt_private), GFP_KERNEL);
+    if (!priv) {
+        PRINTM(FATAL, "Can't allocate priv\n");
+        LEAVE();
+        return NULL;
+    }
+    
+    /* allocate buffer for bt_adapter */
+    if (!(priv->adapter = kzalloc(sizeof(bt_adapter), GFP_KERNEL))) {
+        PRINTM(FATAL, "Allocate buffer for bt_adapter failed!\n");
+        goto err_kmalloc;
+    }
+
+    bt_init_adapter(priv);
+
+    /*Register to HCI Core */
+    hdev = hci_alloc_dev();
+    if (!hdev) {
+        PRINTM(FATAL, "Can't allocate HCI device\n");
+        goto err_kmalloc;
+    }
+
+    PRINTM(INFO, "Starting kthread...\n");
+    priv->MainThread.priv = priv;
+    spin_lock_init(&driver_lock);
+
+    bt_create_thread(bt_service_main_thread, &priv->MainThread,
+                     "bt_main_service");
+
+    /* wait for mainthread to up */
+    while (!priv->MainThread.pid) {
+        os_sched_timeout(1);
+    }
+    priv->bt_dev.hcidev = hdev;
+    priv->bt_dev.card = card;
+    btpriv = priv;
+    ((struct sdio_mmc_card *)card)->priv = priv;
+    /*
+     * Register the device. Fillup the private data structure with
+     * relevant information from the card and request for the required
+     * IRQ. 
+     */
+    if (sbi_register_dev(priv) < 0) {
+        PRINTM(FATAL, "Failed to register bt device!\n");
+        goto err_registerdev;
+    }
+    if (bt_init_fw(priv)) {
+        PRINTM(FATAL, "Firmware Init Failed\n");
+        goto err_init_fw;
+    }
+    priv->bt_dev.tx_dnld_rdy = TRUE;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+    hdev->type = HCI_SDIO;
+#else
+    hdev->type = HCI_PCCARD;
+#endif
+    hdev->driver_data = priv;
+
+    hdev->open = bt_open;
+    hdev->close = bt_close;
+    hdev->flush = bt_flush;
+    hdev->send = bt_send_frame;
+    hdev->destruct = bt_destruct;
+    hdev->ioctl = bt_ioctl;
+
+    hdev->owner = THIS_MODULE;
+    bt_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+    ret = hci_register_dev(hdev);
+    if (ret < 0) {
+        PRINTM(FATAL, "Can't register HCI device\n");
+        goto err_init_fw;
+    }
+    bt_proc_init(priv);
+    LEAVE();
+    return priv;
+  err_init_fw:
+    sbi_unregister_dev(priv);
+  err_registerdev:
+    /* Stop the thread servicing the interrupts */
+    priv->adapter->SurpriseRemoved = TRUE;
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    while (priv->MainThread.pid) {
+        os_sched_timeout(1);
+    }
+  err_kmalloc:
+    if (hdev)
+        hci_free_dev(hdev);
+    bt_free_adapter(priv);
+    kfree(priv);
+    btpriv = NULL;
+    LEAVE();
+    return NULL;
+}
+
+/** 
+ *  @brief This function removes the card.
+ *  
+ *  @param priv    A pointer to card
+ *  @return        BT_STATUS_SUCCESS
+ */
+
+int
+bt_remove_card(void *card)
+{
+    struct hci_dev *hdev;
+    bt_private *priv;
+    ENTER();
+
+    if (!btpriv) {
+        LEAVE();
+        return BT_STATUS_SUCCESS;
+    }
+    hdev = btpriv->bt_dev.hcidev;
+    priv = (bt_private *) hdev->driver_data;
+    /* Disable interrupts on the card */
+    sbi_disable_host_int(priv);
+    wake_up_interruptible(&priv->adapter->cmd_wait_q);
+    priv->adapter->SurpriseRemoved = TRUE;
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    while (priv->MainThread.pid) {
+        os_sched_timeout(1);
+    }
+    bt_proc_remove(priv);
+    PRINTM(INFO, "unregester dev\n");
+    sbi_unregister_dev(priv);
+
+    /* UnRegister to HCI Core */
+    if (hci_unregister_dev(hdev) < 0)
+        PRINTM(ERROR, "Can't unregister HCI device %s\n", hdev->name);
+    hci_free_dev(hdev);
+    btpriv->bt_dev.hcidev = NULL;
+    bt_free_adapter(priv);
+    if (btpriv) {
+        kfree(btpriv);
+        btpriv = NULL;
+    }
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function initializes module.
+ *  
+ *  @param     n/a    A pointer to bt_private structure
+ *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+bt_init_module(void)
+{
+    int ret = BT_STATUS_SUCCESS;
+    ENTER();
+    if (sbi_register() == NULL) {
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function cleans module
+ *  
+ *  @param priv    n/a
+ *  @return        n/a
+ */
+static void
+bt_exit_module(void)
+{
+    ENTER();
+    if (btpriv) {
+        bt_send_module_cfg_cmd(btpriv, MODULE_SHUTDOWN_REQ);
+    }
+    sbi_unregister();
+    LEAVE();
+}
+
+module_param(fw, int, 1);
+module_init(bt_init_module);
+module_exit(bt_exit_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell Bluetooth Driver Ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_proc.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_proc.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_proc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_proc.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,444 @@
+/** @file bt_proc.c
+  *  
+  * @brief This file handle the functions for proc files
+  * 
+  * (c) Copyright 2007, Marvell International Ltd. 
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+
+#include "include.h"
+struct proc_data
+{
+    /** Read length */
+    int rdlen;
+    /** Read buffer */
+    char *rdbuf;
+    /** Write length */
+    int wrlen;
+    /** Maximum write length */
+    int maxwrlen;
+    /** Write buffer */
+    char *wrbuf;
+    void (*on_close) (struct inode *, struct file *);
+};
+
+struct item_data
+{
+    /** Name */
+    char name[32];
+    /** Size */
+    u32 size;
+    /** Address */
+    u32 addr;
+    /** Offset */
+    u32 offset;
+    /** Flag */
+    u32 flag;
+};
+
+struct proc_private_data
+{
+    /** Name */
+    char name[32];
+    /** File flag */
+    u32 fileflag;
+    /** Buffer size */
+    u32 bufsize;
+    /** Number of items */
+    u32 num_items;
+    /** Item data */
+    struct item_data *pdata;
+    /** Private structure */
+    bt_private *pbt;
+    /** File operations */
+    struct file_operations *fops;
+};
+
+/** Default file permission */
+#define DEFAULT_FILE_PERM  0644
+
+/** Bluetooth device offset */
+#define OFFSET_BT_DEV		0x01
+/** Bluetooth adapter offset */
+#define OFFSET_BT_ADAPTER	0x02
+/** Show integer */
+#define SHOW_INT		0x10
+/** Show hex */
+#define SHOW_HEX		0x20
+
+/** Device size */
+#define item_dev_size(n) (sizeof ((bt_dev_t *)0)->n)
+/** Device address */
+#define item_dev_addr(n) ((u32) &((bt_dev_t *)0)->n)
+
+/** Adapter size */
+#define item_adapter_size(n) (sizeof ((bt_adapter *)0)->n)
+/** Adapter address */
+#define item_adapter_addr(n) ((u32) &((bt_adapter *)0)->n)
+static struct item_data config_items[] = {
+    {"drvdbg", sizeof(u32), (u32) & drvdbg, 0, SHOW_HEX}
+    ,
+    {"psmode", item_dev_size(psmode), 0, item_dev_addr(psmode),
+     OFFSET_BT_DEV | SHOW_INT}
+    ,
+    {"pscmd", item_dev_size(pscmd), 0, item_dev_addr(pscmd),
+     OFFSET_BT_DEV | SHOW_INT}
+    ,
+    {"hsmode", item_dev_size(hsmode), 0, item_dev_addr(hsmode),
+     OFFSET_BT_DEV | SHOW_INT}
+    ,
+    {"hscmd", item_dev_size(hscmd), 0, item_dev_addr(hscmd),
+     OFFSET_BT_DEV | SHOW_INT}
+    ,
+    {"gpio_gap", item_dev_size(gpio_gap), 0, item_dev_addr(gpio_gap),
+     OFFSET_BT_DEV | SHOW_HEX}
+    ,
+    {"hscfgcmd", item_dev_size(hscfgcmd), 0, item_dev_addr(hscfgcmd),
+     OFFSET_BT_DEV | SHOW_INT}
+    ,
+};
+
+static struct item_data status_items[] = {
+    {"tx_dnld_rdy", item_dev_size(tx_dnld_rdy), 0, item_dev_addr(tx_dnld_rdy),
+     OFFSET_BT_DEV | SHOW_INT},
+    {"psmode", item_adapter_size(psmode), 0, item_adapter_addr(psmode),
+     OFFSET_BT_ADAPTER | SHOW_INT},
+    {"hs_state", item_adapter_size(hs_state), 0, item_adapter_addr(hs_state),
+     OFFSET_BT_ADAPTER | SHOW_INT},
+    {"ps_state", item_adapter_size(ps_state), 0, item_adapter_addr(ps_state),
+     OFFSET_BT_ADAPTER | SHOW_INT},
+};
+
+/** 
+ *  @brief convert string to number
+ *
+ *  @param s   	   pointer to numbered string
+ *  @return 	   converted number from string s
+ */
+u32
+string_to_number(char *s)
+{
+    u32 r = 0;
+    u32 base = 0;
+
+    if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0))
+        base = 16;
+    else
+        base = 10;
+    if (base == 16)
+        s += 2;
+    for (s = s; *s != 0; s++) {
+        if ((*s >= 48) && (*s <= 57))
+            r = (r * base) + (*s - 48);
+        else if ((*s >= 65) && (*s <= 70))
+            r = (r * base) + (*s - 55);
+        else if ((*s >= 97) && (*s <= 102))
+            r = (r * base) + (*s - 87);
+        else
+            break;
+    }
+    return r;
+}
+
+/** 
+ *  @brief This function handle generic proc file close
+ *  
+ *  @param inode   A pointer to inode structure
+ *  @param file    A pointer to file structure
+ *  @return 	   BT_STATUS_SUCCESS
+ */
+static int
+proc_close(struct inode *inode, struct file *file)
+{
+    struct proc_data *pdata = file->private_data;
+    ENTER();
+    if (pdata) {
+        if (pdata->on_close != NULL)
+            pdata->on_close(inode, file);
+        if (pdata->rdbuf)
+            kfree(pdata->rdbuf);
+        if (pdata->wrbuf)
+            kfree(pdata->wrbuf);
+        kfree(pdata);
+    }
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handle generic proc file read
+ *  
+ *  @param file    A pointer to file structure
+ *  @param buffer  A pointer to output buffer
+ *  @param len     number of byte to read
+ *  @param offset  A pointer to offset of file
+ *  @return 	   number of output data
+ */
+static ssize_t
+proc_read(struct file *file,
+          char __user * buffer, size_t len, loff_t * offset)
+{
+    loff_t pos = *offset;
+    struct proc_data *pdata = (struct proc_data *) file->private_data;
+    if ((!pdata->rdbuf) || (pos < 0))
+        return -EINVAL;
+    if (pos >= pdata->rdlen)
+        return 0;
+    if (len > pdata->rdlen - pos)
+        len = pdata->rdlen - pos;
+    if (copy_to_user(buffer, pdata->rdbuf + pos, len))
+        return -EFAULT;
+    *offset = pos + len;
+    return len;
+}
+
+/** 
+ *  @brief This function handle generic proc file write
+ *  
+ *  @param file    A pointer to file structure
+ *  @param buffer  A pointer to input buffer
+ *  @param len     number of byte to write
+ *  @param offset  A pointer to offset of file
+ *  @return 	   number of input data
+ */
+static ssize_t
+proc_write(struct file *file,
+           const char __user * buffer, size_t len, loff_t * offset)
+{
+    loff_t pos = *offset;
+    struct proc_data *pdata = (struct proc_data *) file->private_data;
+
+    if (!pdata->wrbuf || (pos < 0))
+        return -EINVAL;
+    if (pos >= pdata->maxwrlen)
+        return 0;
+    if (len > pdata->maxwrlen - pos)
+        len = pdata->maxwrlen - pos;
+    if (copy_from_user(pdata->wrbuf + pos, buffer, len))
+        return -EFAULT;
+    if (pos + len > pdata->wrlen)
+        pdata->wrlen = len + file->f_pos;
+    *offset = pos + len;
+    return len;
+}
+
+/** 
+ *  @brief This function handle the generic file close 
+ *  
+ *  @param inode   A pointer to inode structure
+ *  @param file    A pointer to file structure
+ *  @return 	   BT_STATUS_SUCCESS or other 
+ */
+static void
+proc_on_close(struct inode *inode, struct file *file)
+{
+    struct proc_dir_entry *entry = PDE(inode);
+    struct proc_private_data *priv = entry->data;
+    struct proc_data *pdata = file->private_data;
+    char *line;
+    int i;
+
+    if (!pdata->wrlen)
+        return;
+    line = pdata->wrbuf;
+    while (line[0]) {
+        for (i = 0; i < priv->num_items; i++) {
+            if (!strncmp
+                (line, priv->pdata[i].name, strlen(priv->pdata[i].name))) {
+                line += strlen(priv->pdata[i].name) + 1;
+                if (priv->pdata[i].size == 1)
+                    *((u8 *) priv->pdata[i].addr) =
+                        (u8) string_to_number(line);
+                else if (priv->pdata[i].size == 2)
+                    *((u16 *) priv->pdata[i].addr) =
+                        (u16) string_to_number(line);
+                else if (priv->pdata[i].size == 4)
+                    *((u32 *) priv->pdata[i].addr) =
+                        (u32) string_to_number(line);
+            }
+        }
+        while (line[0] && line[0] != '\n')
+            line++;
+        if (line[0])
+            line++;
+    }
+    if (priv->pbt->bt_dev.hscmd || priv->pbt->bt_dev.pscmd
+        || priv->pbt->bt_dev.hscfgcmd) {
+        bt_prepare_command(priv->pbt);
+        wake_up_interruptible(&priv->pbt->MainThread.waitQ);
+    }
+    return;
+}
+
+/** 
+ *  @brief This function handle the generic file open
+ *  
+ *  @param inode   A pointer to inode structure
+ *  @param file    A pointer to file structure
+ *  @return 	   BT_STATUS_SUCCESS or other 
+ */
+static int
+proc_open(struct inode *inode, struct file *file)
+{
+    struct proc_dir_entry *entry = PDE(inode);
+    struct proc_private_data *priv = entry->data;
+    struct proc_data *pdata;
+    int i;
+    char *p;
+    u32 val = 0;
+    ENTER();
+    if ((file->private_data =
+         kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) {
+        PRINTM(ERROR, "Can not alloc mem for proc_data\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+    pdata = (struct proc_data *) file->private_data;
+    if ((pdata->rdbuf = kmalloc(priv->bufsize, GFP_KERNEL)) == NULL) {
+        PRINTM(ERROR, "Can not alloc mem for rdbuf\n");
+        kfree(file->private_data);
+        LEAVE();
+        return -ENOMEM;
+    }
+    if (priv->fileflag == DEFAULT_FILE_PERM) {
+        if ((pdata->wrbuf = kzalloc(priv->bufsize, GFP_KERNEL)) == NULL) {
+            PRINTM(ERROR, "Can not alloc mem for wrbuf\n");
+            kfree(pdata->rdbuf);
+            kfree(file->private_data);
+            return -ENOMEM;
+        }
+        pdata->maxwrlen = priv->bufsize;
+        pdata->on_close = proc_on_close;
+    }
+    p = pdata->rdbuf;
+    for (i = 0; i < priv->num_items; i++) {
+        if (priv->pdata[i].size == 1)
+            val = *((u8 *) priv->pdata[i].addr);
+        else if (priv->pdata[i].size == 2)
+            val = *((u16 *) priv->pdata[i].addr);
+        else if (priv->pdata[i].size == 4)
+            val = *((u32 *) priv->pdata[i].addr);
+        if (priv->pdata[i].flag & SHOW_INT)
+            p += sprintf(p, "%s=%d\n", priv->pdata[i].name, val);
+        else if (priv->pdata[i].flag & SHOW_HEX)
+            p += sprintf(p, "%s=0x%x\n", priv->pdata[i].name, val);
+    }
+    pdata->rdlen = strlen(pdata->rdbuf);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+static struct file_operations proc_read_ops = {
+    .read = proc_read,
+    .open = proc_open,
+    .release = proc_close
+};
+
+static struct file_operations proc_rw_ops = {
+    .read = proc_read,
+    .write = proc_write,
+    .open = proc_open,
+    .release = proc_close
+};
+
+static struct proc_private_data proc_files[] = {
+    {"status", S_IRUGO, 1024, sizeof(status_items) / sizeof(status_items[0]),
+     &status_items[0], NULL, &proc_read_ops}
+    ,
+    {"config", DEFAULT_FILE_PERM, 512,
+     sizeof(config_items) / sizeof(config_items[0]), &config_items[0], NULL,
+     &proc_rw_ops}
+    ,
+};
+
+/** 
+ *  @brief This function init proc entry
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS
+ */
+int
+bt_proc_init(bt_private * priv)
+{
+    u8 ret = BT_STATUS_SUCCESS;
+    struct proc_dir_entry *entry;
+    int i, j;
+    ENTER();
+    if (!priv->proc_mbt) {
+        priv->proc_mbt = proc_mkdir("mbt", init_net.proc_net);
+        if (!priv->proc_mbt) {
+            PRINTM(ERROR, "Could not mkdir mbt!\n");
+            ret = BT_STATUS_FAILURE;
+            goto done;
+        }
+        priv->proc_entry =
+            proc_mkdir(priv->bt_dev.hcidev->name, priv->proc_mbt);
+        if (!priv->proc_entry) {
+            PRINTM(ERROR, "Could not mkdir %s!\n", priv->bt_dev.hcidev->name);
+            ret = BT_STATUS_FAILURE;
+            goto done;
+        }
+        for (j = 0; j < sizeof(proc_files) / sizeof(proc_files[0]); j++) {
+            for (i = 0; i < proc_files[j].num_items; i++) {
+                if (proc_files[j].pdata[i].flag & OFFSET_BT_DEV)
+                    proc_files[j].pdata[i].addr =
+                        proc_files[j].pdata[i].offset + (u32) & priv->bt_dev;
+                if (proc_files[j].pdata[i].flag & OFFSET_BT_ADAPTER)
+                    proc_files[j].pdata[i].addr =
+                        proc_files[j].pdata[i].offset + (u32) priv->adapter;
+            }
+            proc_files[j].pbt = priv;
+            entry =
+                create_proc_entry(proc_files[j].name,
+                                  S_IFREG | proc_files[j].fileflag,
+                                  priv->proc_entry);
+            if (entry) {
+                entry->data = &proc_files[j];
+                entry->owner = THIS_MODULE;
+                entry->proc_fops = proc_files[j].fops;
+            }
+        }
+    }
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief remove proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @return 	   N/A
+ */
+void
+bt_proc_remove(bt_private * priv)
+{
+    int j;
+    ENTER();
+    if (priv->proc_mbt) {
+        if (priv->proc_entry) {
+            for (j = 0; j < sizeof(proc_files) / sizeof(proc_files[0]); j++) {
+                remove_proc_entry(proc_files[j].name, priv->proc_entry);
+            }
+        }
+        remove_proc_entry(priv->bt_dev.hcidev->name, priv->proc_mbt);
+        remove_proc_entry("mbt", init_net.proc_net);
+        priv->proc_entry = NULL;
+        priv->proc_mbt = NULL;
+    }
+    LEAVE();
+    return;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_sdio.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_sdio.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_sdio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_sdio.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1261 @@
+/** @file bt_sdio.c
+ *  @brief This file contains SDIO IF (interface) module
+ *  related functions.
+ * 
+ * (c) Copyright 2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+
+#include "include.h"
+
+/** Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY	2
+/** Helper name */
+char *helper_name = NULL;
+/** Firmware name */
+char *fw_name = NULL;
+module_param(helper_name, charp, 0);
+module_param(fw_name, charp, 0);
+/** Default helper name */
+#define DEFAULT_HELPER_NAME "mrvl/helper_sd.bin"
+/** Default firmware name */
+#define DEFAULT_FW_NAME "mrvl/sd8688.bin"
+
+/** Function number 2 */
+#define FN2			2
+/** SD_CLASS_BT_A*/
+#define SD_CLASS_BT_A		0x02
+//#define SD_DEVICE_ID_8688_BT    0xfe03 
+
+
+extern bt_private *btpriv;
+/********************************************************
+		Global Variables
+********************************************************/
+
+/** 
+ *  @brief This function get rx_unit value
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_get_rx_unit(bt_private * priv)
+{
+	int ret = BT_STATUS_SUCCESS;
+	u8 reg;
+	struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+	ENTER();
+	reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
+	if (ret == BT_STATUS_SUCCESS)
+		priv->bt_dev.rx_unit = reg;
+	LEAVE();
+	return ret;
+}
+
+/** 
+ *  @brief This function reads fwstatus registers
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param dat	   A pointer to keep returned data
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_read_firmware_status(bt_private * priv, u16 * dat)
+{
+	int ret = BT_STATUS_SUCCESS;
+	u8 fws0;
+	u8 fws1;
+	struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+	umd_enter();
+	ENTER();
+	fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);
+	if (ret < 0)
+		return BT_STATUS_FAILURE;
+
+	fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
+	if (ret < 0)
+		return BT_STATUS_FAILURE;
+
+	*dat = (((u16) fws1) << 8) | fws0;
+
+	LEAVE();
+	umd_exit();
+	return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function reads rx length
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param dat	   A pointer to keep returned data
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_read_rx_len(bt_private * priv, u16 * dat)
+{
+	int ret = BT_STATUS_SUCCESS;
+	u8 reg;
+	struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+	ENTER()
+		
+	reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
+	if (ret == BT_STATUS_SUCCESS) {
+		*dat = (u16) reg << priv->bt_dev.rx_unit;
+	}
+	
+	LEAVE();
+	return ret;
+}
+
+/** 
+ *  @brief This function enables the host interrupts mask
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param mask	   the interrupt mask
+ *  @return 	   BT_STATUS_SUCCESS
+ */
+static int
+sd_enable_host_int_mask(bt_private * priv, u8 mask)
+{
+	int ret = BT_STATUS_SUCCESS;
+	struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+	ENTER();
+
+	sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
+	if (ret) {
+		PRINTM(WARN, "Unable to enable the host interrupt!\n");
+		ret = BT_STATUS_FAILURE;
+	}
+	
+	LEAVE();
+	return ret;
+}
+
+/**  @brief This function disables the host interrupts mask.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param mask	   the interrupt mask
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_disable_host_int_mask(bt_private * priv, u8 mask)
+{
+	int ret = BT_STATUS_FAILURE;
+	u8 host_int_mask;
+	struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+	ENTER();
+	
+	/* Read back the host_int_mask register */
+	host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
+	if (ret) {
+		goto done;
+	}
+
+	/* Update with the mask and write back to the register */
+	host_int_mask &= ~mask;
+	sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
+	if (ret < 0) {
+		PRINTM(WARN, "Unable to diable the host interrupt!\n");
+		goto done;
+	}
+	ret = BT_STATUS_SUCCESS;
+	
+done:
+	LEAVE();
+	return ret;
+}
+
+/** 
+ *  @brief This function polls the card status register.
+ *  
+ *  @param priv    	A pointer to bt_private structure
+ *  @param fn   	function number
+ *  @param bits    	the bit mask
+ *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_poll_card_status(bt_private * priv, u8 bits)
+{
+	int tries;
+	int rval;
+	struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+	u8 cs;
+	ENTER();
+	
+	for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
+		cs = sdio_readb(card->func, CARD_STATUS_REG, &rval);
+		if (rval != 0)
+	    		break;
+		if (rval == 0 && (cs & bits) == bits) {
+	    		LEAVE();
+	    		return BT_STATUS_SUCCESS;
+		}
+		udelay(1);
+	}
+	
+	PRINTM(WARN, "mv_sdio_poll_card_status: FAILED!:%d\n", rval);
+	LEAVE();
+	return BT_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief This function probe the card
+ *  
+ *  @param dev     A pointer to structure _sd_device
+ *  @param id	   A pointer to structure sd_device_id	
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_probe_card(struct sdio_func *func, const struct sdio_device_id *id)
+{
+	int ret = BT_STATUS_SUCCESS;
+	bt_private *priv = NULL;
+	struct sdio_mmc_card *card = NULL;
+	ENTER();
+	
+	PRINTM(INFO, "vendor=%x,device=%x,class=%d,fn=%d\n", id->vendor,
+		id->device, id->class, func->num);
+	umd_dbg("vendor=%x,device=%x,class=%d,fn=%d\n", id->vendor,
+		id->device, id->class, func->num);
+	card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+	if (!card) {
+		ret = -ENOMEM;
+		goto done;
+	}
+	card->func = func;
+	priv = bt_add_card(card);
+	if (!priv) {
+		ret = BT_STATUS_FAILURE;
+		kfree(card);
+	}
+	card->priv = priv;
+done:
+	LEAVE();
+	return ret;
+}
+
+/** 
+ *  @brief This function checks if the firmware is ready to accept
+ *  command or not.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param pollnum  number of times to polling fw status 
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_verify_fw_download(bt_private * priv, int pollnum)
+{
+	int ret = BT_STATUS_FAILURE;
+	u16 firmwarestat;
+	int tries;
+
+	ENTER();
+	/* Wait for firmware initialization event */
+	for (tries = 0; tries < pollnum; tries++) {
+		if (sd_read_firmware_status(priv, &firmwarestat) < 0)
+	    		continue;
+		if (firmwarestat == FIRMWARE_READY) {
+	    		ret = BT_STATUS_SUCCESS;
+	    		break;
+		} else {
+	    		mdelay(10);
+	    		ret = BT_STATUS_FAILURE;
+		}
+	}
+	
+	if (ret < 0) {
+		PRINTM(ERROR, "Timeout waiting for FW to become active\n");
+		umd_dbg("Timeout waiting for FW to become active\n");
+		goto done;
+	}
+	ret = BT_STATUS_SUCCESS;
+	
+done:
+	LEAVE();
+	return ret;
+}
+
+/** 
+ *  @brief This function programs the firmware image.
+ *  
+ *  @param priv    	A pointer to bt_private structure
+ *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_dowload_helper(bt_private * priv)
+{
+    struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+    const struct firmware *fw_helper = NULL;
+    u8 *helper = NULL;
+    int helperlen;
+    int ret = BT_STATUS_SUCCESS;
+    void *tmphlprbuf = NULL;
+    int tmphlprbufsz;
+    u8 *hlprbuf;
+    int hlprblknow;
+    u32 tx_len;
+#ifdef FW_DOWNLOAD_SPEED
+    u32 tv1, tv2;
+#endif
+    ENTER();
+	
+    if ((ret =
+         request_firmware(&fw_helper, helper_name,
+                          priv->hotplug_device)) < 0) {
+        PRINTM(FATAL,
+               "request_firmware() failed (helper), error code = %#x\n", ret);
+        goto done;
+    }
+
+    if (fw_helper) {
+        helper = fw_helper->data;
+        helperlen = fw_helper->size;
+    } else {
+        PRINTM(MSG, "No helper image found! Terminating download.\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+
+    PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
+           helperlen, SD_BLOCK_SIZE_FW_DL);
+
+#ifdef FW_DOWNLOAD_SPEED
+    tv1 = get_utimeofday();
+#endif
+
+    tmphlprbufsz = BT_UPLD_SIZE;
+    tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+    if (!tmphlprbuf) {
+        PRINTM(ERROR,
+               "Unable to allocate buffer for helper. Terminating download\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+    memset(tmphlprbuf, 0, tmphlprbufsz);
+
+    hlprbuf = (u8 *) tmphlprbuf;
+
+    /* Perform helper data transfer */
+    tx_len =
+        (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE_FW_DL) - SDIO_HEADER_LEN;
+    hlprblknow = 0;
+    do {
+        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+        ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+        if (ret < 0) {
+            PRINTM(FATAL, "Helper download poll status timeout @ %d\n",
+                   hlprblknow);
+            goto done;
+        }
+
+        /* More data? */
+        if (hlprblknow >= helperlen)
+            break;
+
+        /* Set blocksize to transfer - checking for last block */
+        if (helperlen - hlprblknow < tx_len)
+            tx_len = helperlen - hlprblknow;
+
+        hlprbuf[0] = ((tx_len & 0x000000ff) >> 0);      /* Little-endian */
+        hlprbuf[1] = ((tx_len & 0x0000ff00) >> 8);
+        hlprbuf[2] = ((tx_len & 0x00ff0000) >> 16);
+        hlprbuf[3] = ((tx_len & 0xff000000) >> 24);
+
+        /* Copy payload to buffer */
+        memcpy(&hlprbuf[SDIO_HEADER_LEN], &helper[hlprblknow], tx_len);
+
+        PRINTM(INFO, ".");
+
+        /* Send data */
+        ret = sdio_writesb(card->func, priv->bt_dev.ioport,
+                           hlprbuf,
+                           FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE_FW_DL);
+
+        if (ret < 0) {
+            PRINTM(FATAL, "IO error during helper download @ %d\n",
+                   hlprblknow);
+            goto done;
+        }
+
+        hlprblknow += tx_len;
+    } while (TRUE);
+
+#ifdef FW_DOWNLOAD_SPEED
+    tv2 = get_utimeofday();
+    PRINTM(INFO, "helper: %ld.%03ld.%03ld ", tv1 / 1000000,
+           (tv1 % 1000000) / 1000, tv1 % 1000);
+    PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+    tv2 -= tv1;
+    PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+#endif
+
+    /* Write last EOF data */
+    PRINTM(INFO, "\nTransferring helper image EOF block\n");
+    memset(hlprbuf, 0x0, SD_BLOCK_SIZE_FW_DL);
+
+    ret =
+        sdio_writesb(card->func, priv->bt_dev.ioport, hlprbuf,
+                     SD_BLOCK_SIZE_FW_DL);
+
+    if (ret < 0) {
+        PRINTM(FATAL, "IO error in writing helper image EOF block\n");
+        goto done;
+    }
+
+    ret = BT_STATUS_SUCCESS;
+
+  done:
+    if (tmphlprbuf)
+        kfree(tmphlprbuf);
+    if (fw_helper)
+        release_firmware(fw_helper);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function downloads firmware image to the card.
+ *  
+ *  @param priv    	A pointer to bt_private structure
+ *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sd_download_firmware_w_helper(bt_private * priv)
+{
+    struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
+    const struct firmware *fw_firmware = NULL;
+    u8 *firmware = NULL;
+    int firmwarelen;
+    u8 base0;
+    u8 base1;
+    int ret = BT_STATUS_SUCCESS;
+    int offset;
+    void *tmpfwbuf = NULL;
+    int tmpfwbufsz;
+    u8 *fwbuf;
+    u16 len;
+    int txlen = 0;
+    int tx_blocks = 0;
+    int i = 0;
+    int tries = 0;
+#ifdef FW_DOWNLOAD_SPEED
+    u32 tv1, tv2;
+#endif
+
+    ENTER();
+    if ((ret =
+         request_firmware(&fw_firmware, fw_name, priv->hotplug_device)) < 0) {
+        PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
+        goto done;
+    }
+
+    if (fw_firmware) {
+        firmware = fw_firmware->data;
+        firmwarelen = fw_firmware->size;
+    } else {
+        PRINTM(MSG, "No firmware image found! Terminating download.\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+
+    PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
+
+#ifdef FW_DOWNLOAD_SPEED
+    tv1 = get_utimeofday();
+#endif
+
+    tmpfwbufsz = BT_UPLD_SIZE;
+    tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+    if (!tmpfwbuf) {
+        PRINTM(ERROR,
+               "Unable to allocate buffer for firmware. Terminating download.\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+    memset(tmpfwbuf, 0, tmpfwbufsz);
+
+    fwbuf = (u8 *) tmpfwbuf;
+
+    /* Perform firmware data transfer */
+    offset = 0;
+    do {
+        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+        ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+        if (ret < 0) {
+            PRINTM(FATAL,
+                   "FW download with helper poll status timeout @ %d\n",
+                   offset);
+            goto done;
+        }
+
+        /* More data? */
+        if (offset >= firmwarelen)
+            break;
+
+        for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+            base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+            if (ret) {
+                PRINTM(WARN, "Dev BASE0 register read failed:"
+                       " base0=0x%04X(%d). Terminating download.\n", base0,
+                       base0);
+                ret = BT_STATUS_FAILURE;
+                goto done;
+            }
+            base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+            if (ret) {
+                PRINTM(WARN, "Dev BASE1 register read failed:"
+                       " base1=0x%04X(%d). Terminating download.\n", base1,
+                       base1);
+                ret = BT_STATUS_FAILURE;
+                goto done;
+            }
+            len = (((u16) base1) << 8) | base0;
+
+            if (len != 0)
+                break;
+            udelay(10);
+        }
+
+        if (len == 0)
+            break;
+        else if (len > BT_UPLD_SIZE) {
+            PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
+                   offset, len);
+            ret = BT_STATUS_FAILURE;
+            goto done;
+        }
+
+        txlen = len;
+
+        if (len & B_BIT_0) {
+            i++;
+            if (i > MAX_WRITE_IOMEM_RETRY) {
+                PRINTM(FATAL,
+                       "FW download failure @ %d, over max retry count\n",
+                       offset);
+                ret = BT_STATUS_FAILURE;
+                goto done;
+            }
+            PRINTM(ERROR, "FW CRC error indicated by the helper:"
+                   " len = 0x%04X, txlen = %d\n", len, txlen);
+            len &= ~B_BIT_0;
+            /* Setting this to 0 to resend from same offset */
+            txlen = 0;
+        } else
+            i = 0;
+
+        /* Set blocksize to transfer - checking for last block */
+        if (firmwarelen - offset < txlen) {
+            txlen = firmwarelen - offset;
+        }
+        PRINTM(INFO, ".");
+
+        tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL;
+
+        /* Copy payload to buffer */
+        memcpy(fwbuf, &firmware[offset], txlen);
+
+        /* Send data */
+        ret =
+            sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf,
+                         tx_blocks * SD_BLOCK_SIZE_FW_DL);
+
+        if (ret < 0) {
+            PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
+                   offset);
+            sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
+            if (ret) {
+                PRINTM(ERROR, "write ioreg failed (CFG)\n");
+            }
+        }
+
+        offset += txlen;
+    } while (TRUE);
+
+    PRINTM(INFO, "\nFW download over, size %d bytes\n", firmwarelen);
+
+    ret = BT_STATUS_SUCCESS;
+  done:
+#ifdef FW_DOWNLOAD_SPEED
+    tv2 = get_utimeofday();
+    PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
+           (tv1 % 1000000) / 1000, tv1 % 1000);
+    PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+    tv2 -= tv1;
+    PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
+           (tv2 % 1000000) / 1000, tv2 % 1000);
+#endif
+    if (tmpfwbuf)
+        kfree(tmpfwbuf);
+    if (fw_firmware)
+        release_firmware(fw_firmware);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function reads data from the card.
+ *  
+ *  @param priv    	A pointer to bt_private structure
+ *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static int
+sd_card_to_host(bt_private * priv)
+{
+    int ret = BT_STATUS_SUCCESS;
+    u16 buf_len = 0;
+    int buf_block_len;
+    int blksz;
+    struct sk_buff *skb = NULL;
+    u32 type;
+    u8 *payload = NULL;
+    struct hci_dev *hdev = priv->bt_dev.hcidev;
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    ENTER();
+    if (!card || !card->func) {
+        PRINTM(ERROR, "card or function is NULL!\n");
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+
+    /* Read the length of data to be transferred */
+    ret = sd_read_rx_len(priv, &buf_len);
+    if (ret < 0) {
+        PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+
+    /* Allocate buffer */
+    blksz = SD_BLOCK_SIZE;
+    buf_block_len = (buf_len + blksz - 1) / blksz;
+    if (buf_len <= SDIO_HEADER_LEN ||
+        (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
+        PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+    skb = bt_skb_alloc(buf_block_len * blksz, GFP_ATOMIC);
+    if (skb == NULL) {
+        PRINTM(WARN, "No free skb\n");
+        goto exit;
+    }
+    payload = skb->tail;
+    ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport,
+                      buf_block_len * blksz);
+    if (ret < 0) {
+        PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
+        ret = BT_STATUS_FAILURE;
+        goto exit;
+    }
+    DBG_HEXDUMP(DBG_DATA, "SDIO Blk Rd", payload, blksz * buf_block_len);
+    /*  This is SDIO specific header
+     *  length: byte[2][1][0], 
+     *  type: byte[3] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) 
+     */
+    buf_len = payload[0];
+    buf_len |= (u16) payload[1] << 8;
+    type = payload[3];
+    switch (type) {
+    case HCI_ACLDATA_PKT:
+    case HCI_SCODATA_PKT:
+    case HCI_EVENT_PKT:
+        bt_cb(skb)->pkt_type = type;
+        skb->dev = (void *) hdev;
+        skb_put(skb, buf_len);
+        skb_pull(skb, SDIO_HEADER_LEN);
+        hci_recv_frame(skb);
+        hdev->stat.byte_rx += buf_len;
+        break;
+    case MRVL_VENDOR_PKT:
+        bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
+        skb->dev = (void *) hdev;
+        skb_put(skb, buf_len);
+        skb_pull(skb, SDIO_HEADER_LEN);
+        if (BT_STATUS_SUCCESS != bt_process_event(priv, skb))
+            hci_recv_frame(skb);
+        hdev->stat.byte_rx += buf_len;
+        break;
+    default:
+        /* Driver specified event and command resp should be handle here */
+        PRINTM(INFO, "Unknow PKT type:%d\n", type);
+        kfree_skb(skb);
+        skb = NULL;
+        break;
+    }
+  exit:
+    if (ret) {
+        hdev->stat.err_rx++;
+        if (skb)
+            kfree_skb(skb);
+    }
+    LEAVE();
+    return ret;
+}
+
+#ifdef CONFIG_PM
+/** 
+ *  @brief This function handle the suspend fuction
+ *  
+ *  @param dev    A pointer to _sd_device structure
+ *  @return	   BT_STATUS_SUCCESS
+ */
+int
+sd_suspend(struct sdio_func *func)
+{
+    struct hci_dev *hcidev;
+    ENTER();
+    if (!btpriv) {
+        LEAVE();
+        return BT_STATUS_SUCCESS;
+    }
+    if (btpriv->adapter->hs_state != HS_ACTIVATED) {
+        if (BT_STATUS_SUCCESS != bt_enable_hs(btpriv)) {
+            LEAVE();
+            return BT_STATUS_FAILURE;
+        }
+    }
+    hcidev = btpriv->bt_dev.hcidev;
+    hci_suspend_dev(hcidev);
+    skb_queue_purge(&btpriv->adapter->tx_queue);
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handle the resume fuction
+ *  
+ *  @param dev    A pointer to _sd_device structure
+ *  @return	  BT_STATUS_SUCCESS
+ */
+int
+sd_resume(struct sdio_func *func)
+{
+    struct hci_dev *hcidev;
+    ENTER();
+    if (!btpriv) {
+        LEAVE();
+        return BT_STATUS_SUCCESS;
+    }
+    hcidev = btpriv->bt_dev.hcidev;
+    hci_resume_dev(hcidev);
+    //if (is_bt_the_wakeup_src()){
+    {
+        PRINTM(MSG, "WAKEUP SRC: BT\n");
+        if ((btpriv->bt_dev.gpio_gap & 0x00ff) == 0xff) {
+            sbi_wakeup_firmware(btpriv);
+            btpriv->adapter->hs_state = HS_DEACTIVATED;
+        }
+    }
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+#endif
+
+/** 
+ *  @brief This function removes the card
+ *  
+ *  @param card    A pointer to the card
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+static void
+sd_remove_card(struct sdio_func *func)
+{
+	struct sdio_mmc_card *card;
+	ENTER();
+	if (func) {
+		card = sdio_get_drvdata(func);
+		if (card) {
+	    		bt_remove_card(card);
+	    		kfree(card);
+		}
+	}
+	LEAVE();
+}
+
+/** 
+ *  @brief This function handles the interrupt.
+ *  
+ *  @param irq 	   The irq of device.
+ *  @param dev_id  A pointer to net_device structure
+ *  @param fp	   A pointer to pt_regs structure
+ *  @return 	   n/a
+ */
+static void
+sd_interrupt(struct sdio_func *func)
+{
+    bt_private *priv;
+    struct hci_dev *hcidev;
+    struct sdio_mmc_card *card;
+    u8 ireg = 0;
+    ENTER();
+    
+    card = sdio_get_drvdata(func);
+    if (card && card->priv) {
+        priv = card->priv;
+        hcidev = priv->bt_dev.hcidev;
+	bt_interrupt(hcidev);
+	if (sbi_get_int_status(priv, &ireg)) {
+            PRINTM(ERROR, "%s: reading HOST_INT_STATUS_REG failed\n",
+                   __FUNCTION__);
+        } else
+            PRINTM(INFO, "%s: HOST_INT_STATUS_REG %#x\n", __FUNCTION__, ireg);
+        wake_up_interruptible(&priv->MainThread.waitQ);
+    }
+    else {
+	//umd_dbg("card = 0x%08x, priv = 0x%08x", card, card->priv);
+	//umd_dbg("get a interrupt without a card to handle it");
+	}
+
+    LEAVE();
+}
+
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+static const struct sdio_device_id bt_ids[] = {
+//      { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SD_DEVICE_ID_8688_BT) },
+    {SDIO_DEVICE_CLASS(SD_CLASS_BT_A)},
+    {}
+};
+
+MODULE_DEVICE_TABLE(sdio, bt_ids);
+
+static struct sdio_driver sdio_bt = {
+    .name = "bt_sdio",
+    .id_table = bt_ids,
+    .probe = sd_probe_card,
+    .remove = sd_remove_card,
+//ifdef CONFIG_PM
+//      .suspend        = sd_suspend,
+//      .resume         = sd_resume, 
+//#endif
+};
+
+/** 
+ *  @brief This function registers the bt module in bus driver.
+ *  
+ *  @return	   An int pointer that keeps returned value
+ */
+int *
+sbi_register(void)
+{
+    int *ret;
+    ENTER();
+    if (sdio_register_driver(&sdio_bt) != 0) {
+        PRINTM(FATAL, "SD Driver Registration Failed \n");
+        return NULL;
+    } else
+        ret = (int *) 1;
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function de-registers the bt module in bus driver.
+ *  
+ *  @return 	   n/a
+ */
+void
+sbi_unregister(void)
+{
+    ENTER();
+    sdio_unregister_driver(&sdio_bt);
+    LEAVE();
+}
+
+/** 
+ *  @brief This function registers the device.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_register_dev(bt_private * priv)
+{
+    int ret = BT_STATUS_SUCCESS;
+    u8 reg;
+    u8 chiprev;
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    struct sdio_func *func;
+    ENTER();
+    if (!card || !card->func) {
+        PRINTM(ERROR, "Error: card or function is NULL!\n");
+        goto failed;
+    }
+    func = card->func;
+    priv->hotplug_device = &func->dev;
+    if (helper_name == NULL) {
+        helper_name = DEFAULT_HELPER_NAME;
+    }
+    if (fw_name == NULL) {
+        fw_name = DEFAULT_FW_NAME;
+    }
+    /* Initialize the private structure */
+    strncpy(priv->bt_dev.name, "bt_sdio0", sizeof(priv->bt_dev.name));
+    priv->bt_dev.ioport = 0;
+    priv->bt_dev.fn = func->num;
+
+    sdio_claim_host(func);
+    ret = sdio_enable_func(func);
+    if (ret) {
+        PRINTM(FATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+        goto release_host;
+    }
+
+    ret = sdio_claim_irq(func, sd_interrupt);
+    if (ret) {
+        PRINTM(FATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+        goto disable_func;
+    }
+
+    ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE);
+    if (ret) {
+        PRINTM(FATAL, "%s: cannot set SDIO block size\n", __FUNCTION__);
+        goto release_irq;
+    }
+
+    /* read Revision Register to get the chip revision number */
+    chiprev = sdio_readb(func, CARD_REVISION_REG, &ret);
+    if (ret) {
+        PRINTM(FATAL, "cannot read CARD_REVISION_REG\n");
+        goto release_irq;
+    }
+    priv->adapter->chip_rev = chiprev;
+    PRINTM(INFO, "revision=%#x\n", chiprev);
+    umd_dbg("revision=%#x\n", chiprev);
+
+    /* Read the IO port */
+    reg = sdio_readb(func, IO_PORT_0_REG, &ret);
+    if (ret < 0)
+        goto release_irq;
+    else
+        priv->bt_dev.ioport |= reg;
+
+    reg = sdio_readb(func, IO_PORT_1_REG, &ret);
+    if (ret < 0)
+        goto release_irq;
+    else
+        priv->bt_dev.ioport |= (reg << 8);
+
+    reg = sdio_readb(func, IO_PORT_2_REG, &ret);
+    if (ret < 0)
+        goto release_irq;
+    else
+        priv->bt_dev.ioport |= (reg << 16);
+
+    umd_dbg("SDIO FUNC%d IO port: 0x%x\n", priv->bt_dev.fn,
+           priv->bt_dev.ioport);
+    PRINTM(INFO, "SDIO FUNC%d IO port: 0x%x\n", priv->bt_dev.fn,
+           priv->bt_dev.ioport);
+    sdio_set_drvdata(func, card);
+    sdio_release_host(func);
+    return BT_STATUS_SUCCESS;
+  release_irq:
+    sdio_release_irq(func);
+  disable_func:
+    sdio_disable_func(func);
+  release_host:
+    sdio_release_host(func);
+  failed:
+    return BT_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief This function de-registers the device.
+ *  
+ *  @param priv    A pointer to  bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS
+ */
+int
+sbi_unregister_dev(bt_private * priv)
+{
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    ENTER();
+    if (card && card->func) {
+        sdio_claim_host(card->func);
+        sdio_release_irq(card->func);
+        sdio_disable_func(card->func);
+        sdio_release_host(card->func);
+        sdio_set_drvdata(card->func, NULL);
+    }
+    LEAVE();
+    return BT_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function enables the host interrupts.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS
+ */
+int
+sbi_enable_host_int(bt_private * priv)
+{
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    int ret;
+    ENTER();
+
+    if (!card || !card->func) {
+        LEAVE();
+        return BT_STATUS_FAILURE;
+    }
+    sdio_claim_host(card->func);
+    ret = sd_enable_host_int_mask(priv, HIM_ENABLE);
+    sd_get_rx_unit(priv);
+    sdio_release_host(card->func);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function disables the host interrupts.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_disable_host_int(bt_private * priv)
+{
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    int ret;
+    ENTER();
+    if (!card || !card->func) {
+        LEAVE();
+        return BT_STATUS_FAILURE;
+    }
+    sdio_claim_host(card->func);
+    ret = sd_disable_host_int_mask(priv, HIM_DISABLE);
+    sdio_release_host(card->func);
+    LEAVE();
+    return ret;
+}
+
+/**  
+ *  @brief This function sends data to the card.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param type	   data or command
+ *  @param payload A pointer to the data/cmd buffer
+ *  @param nb	   the length of data/cmd
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_host_to_card(bt_private * priv, u8 type, u8 * payload, u16 nb)
+{
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    int ret = BT_STATUS_SUCCESS;
+    int buf_block_len;
+    int blksz;
+    int i = 0;
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "card or function is NULL!\n");
+        LEAVE();
+        return BT_STATUS_FAILURE;
+    }
+
+    /* Allocate buffer and copy payload */
+    blksz = SD_BLOCK_SIZE;
+    buf_block_len = (nb + blksz - 1) / blksz;
+    sdio_claim_host(card->func);
+#define MAX_WRITE_IOMEM_RETRY	2
+    do {
+        /* Transfer data to card */
+        ret =
+            sdio_writesb(card->func, priv->bt_dev.ioport,
+                         priv->adapter->TmpTxBuf, buf_block_len * blksz);
+        if (ret < 0) {
+            i++;
+            PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+                   ret);
+            ret = BT_STATUS_FAILURE;
+            if (i > MAX_WRITE_IOMEM_RETRY)
+                goto exit;
+        } else {
+            DBG_HEXDUMP(DBG_DATA, "SDIO Blk Wr", priv->adapter->TmpTxBuf,
+                        blksz * buf_block_len);
+        }
+    } while (ret == BT_STATUS_FAILURE);
+    priv->bt_dev.tx_dnld_rdy = FALSE;
+  exit:
+    sdio_release_host(card->func);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function initializes firmware
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_download_fw(bt_private * priv)
+{
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    int ret = BT_STATUS_SUCCESS;
+
+    ENTER();
+
+    umd_dbg("helper = %s, fw = %s", helper_name, fw_name); 
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "card or function is NULL!\n");
+        LEAVE();
+        return BT_STATUS_FAILURE;
+    }
+
+    sdio_claim_host(card->func);
+
+    if (BT_STATUS_SUCCESS == sd_verify_fw_download(priv, 1)) {
+        PRINTM(INFO, "Firmware already downloaded!\n");
+        goto done;
+    }
+
+	umd_dbg("2222");
+
+
+    if (priv->bt_dev.fn == FN2) {
+        ret = BT_STATUS_FAILURE;
+        PRINTM(INFO, "Firmware is not ready (FN2)!\n");
+        umd_dbg("Firmware is not ready (FN2)!\n");
+        //goto done;
+    }
+
+	umd_dbg("Will download helper");
+
+    /* Download the helper */
+    ret = sd_dowload_helper(priv);
+    if (ret) {
+        PRINTM(INFO, "Fail to download helper!\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+
+	umd_dbg("Will download main FW");
+
+    /* Download the main firmware via the helper firmware */
+    if (sd_download_firmware_w_helper(priv)) {
+        PRINTM(INFO, "Bluetooth FW download failed!\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* check if the fimware is downloaded successfully or not */
+    if (sd_verify_fw_download(priv, MAX_FIRMWARE_POLL_TRIES)) {
+        PRINTM(INFO, "FW failed to be active in time!\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    sdio_release_host(card->func);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function checks the interrupt status and handle it accordingly.
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @param ireg    A pointer to variable that keeps returned value
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_get_int_status(bt_private * priv, u8 * ireg)
+{
+    int ret = BT_STATUS_SUCCESS;
+    u8 sdio_ireg = 0;
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    ENTER();
+    *ireg = 0;
+    sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+    if (ret) {
+        PRINTM(WARN, "sdio_read_ioreg: read int status register failed\n");
+        ret = BT_STATUS_FAILURE;
+        goto done;
+    }
+    if (sdio_ireg) {
+        /*
+         * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+         * Clear the interrupt status register and re-enable the interrupt
+         */
+        PRINTM(INFO, "sdio_ireg = 0x%x\n", sdio_ireg);
+        sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
+                                                UP_LD_HOST_INT_STATUS),
+                    HOST_INTSTATUS_REG, &ret);
+
+        if (ret) {
+            PRINTM(WARN,
+                   "sdio_write_ioreg: clear int status register failed\n");
+            ret = BT_STATUS_FAILURE;
+            goto done;
+        }
+    }
+
+    if (sdio_ireg & DN_LD_HOST_INT_STATUS) {    /* tx_done INT */
+        if (priv->bt_dev.tx_dnld_rdy) { /* tx_done already received */
+            PRINTM(INFO,
+                   "warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",
+                   priv->bt_dev.tx_dnld_rdy, sdio_ireg);
+        } else {
+            priv->bt_dev.tx_dnld_rdy = TRUE;
+        }
+    }
+    if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+	sd_card_to_host(priv);
+    }
+    *ireg = sdio_ireg;
+    ret = BT_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function wakeup firmware
+ *  
+ *  @param priv    A pointer to bt_private structure
+ *  @return 	   BT_STATUS_SUCCESS or BT_STATUS_FAILURE
+ */
+int
+sbi_wakeup_firmware(bt_private * priv)
+{
+    struct sdio_mmc_card *card = priv->bt_dev.card;
+    int ret = BT_STATUS_SUCCESS;
+    ENTER();
+    if (!card || !card->func) {
+        PRINTM(ERROR, "card or function is NULL!\n");
+        LEAVE();
+        return BT_STATUS_FAILURE;
+    }
+    sdio_claim_host(card->func);
+    sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+    sdio_release_host(card->func);
+    PRINTM(CMD, "wake up firmware\n");
+    LEAVE();
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_sdio.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_sdio.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/bt_sdio.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/bt_sdio.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,160 @@
+/** @file bt_sdio.h
+ *  @brief This file contains SDIO (interface) module
+ *  related macros, enum, and structure.
+ *       
+ *  (c) Copyright 2007, Marvell International Ltd.   
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+
+#ifndef _BT_SDIO_H_
+#define _BT_SDIO_H_
+
+/** IRQ return type */
+typedef irqreturn_t IRQ_RET_TYPE;
+/** IRQ return */
+#define IRQ_RET		return IRQ_HANDLED
+/** ISR notifier function */
+typedef IRQ_RET_TYPE(*isr_notifier_fn_t) (s32 irq, void *dev_id,
+                                          struct pt_regs * reg);
+
+/** MVSD type */
+typedef enum _mv_sd_type
+{
+    MVSD_DAT = 0,
+    MVSD_CMD = 1,
+    MVSD_EVENT = 3
+} mv_sd_type;
+
+/** SDIO header length */
+#define SDIO_HEADER_LEN			4
+/** define SD block size for data Tx/Rx */
+#define SD_BLOCK_SIZE			32	
+/** define SD block size for firmware download */
+#define SD_BLOCK_SIZE_FW_DL		32
+/** Number of blocks for firmware transfer */
+#define FIRMWARE_TRANSFER_NBLOCK	2
+
+#ifndef MAX
+/** Return maximum of two */
+#define MAX(a,b)		((a) > (b) ? (a) : (b))
+#endif
+
+/** This is for firmware specific length */
+#define EXTRA_LEN	36
+
+/** Command buffer size for Marvell driver */
+#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
+
+/** Bluetooth Rx packet buffer size for Marvell driver */
+#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \
+	(HCI_MAX_FRAME_SIZE + EXTRA_LEN)
+
+/** Buffer size to allocate */
+#define ALLOC_BUF_SIZE		(((MAX(MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \
+					MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
+					+ SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES			100
+
+/** The number of times to try when waiting for downloaded firmware to 
+     become active. (polling the scratch register). */
+
+#define MAX_FIRMWARE_POLL_TRIES		100
+
+/** HIM disable */
+#define	HIM_DISABLE			0xff
+/** HIM enable */
+#define HIM_ENABLE			0x03
+/** Firmware ready */
+#define FIRMWARE_READY			0xfedc
+
+/* Bus Interface Control Reg 0x07 */
+/** SD BUS width 1 */
+#define SD_BUS_WIDTH_1			0x00
+/** SD BUS width 4 */
+#define SD_BUS_WIDTH_4			0x02
+/** SD BUS width mask */
+#define SD_BUS_WIDTH_MASK		0x03
+/** Asynchronous interrupt mode */
+#define ASYNC_INT_MODE			0x20
+
+/* Host Control Registers */
+/** I/O port 0 register */
+#define IO_PORT_0_REG			0x00
+/** I/O port 1 register */
+#define IO_PORT_1_REG			0x01
+/** I/O port 2 register */
+#define IO_PORT_2_REG			0x02
+/** Configuration register */
+#define CONFIGURATION_REG		0x03
+/** Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST	(0x1U << 2)
+/** Host power up */
+#define HOST_POWER_UP			(0x1U << 1)
+/** Host power down */
+#define HOST_POWER_DOWN			(0x1U << 0)
+/** Host interrupt mask register */
+#define HOST_INT_MASK_REG		0x04
+
+/* Card Control Registers */
+/** SQ read base address of A0 register */
+#define SQ_READ_BASE_ADDRESS_A0_REG  	0x10
+/** SQ read base address of A1 register */
+#define SQ_READ_BASE_ADDRESS_A1_REG  	0x11
+
+/** Host interrupt status register */
+#define HOST_INTSTATUS_REG		0x05
+/** Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS		(0x1U)
+/** Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS		(0x2U)
+
+/** Card status register */
+#define CARD_STATUS_REG              	0x20
+/** Card I/O ready */
+#define CARD_IO_READY              	(0x1U << 3)
+/** CIS card ready */
+#define CIS_CARD_RDY                 	(0x1U << 2)
+/** Upload card ready */
+#define UP_LD_CARD_RDY               	(0x1U << 1)
+/** Download card ready */
+#define DN_LD_CARD_RDY               	(0x1U << 0)
+
+/** Card OCR 0 register */
+#define CARD_OCR_0_REG               	0x34
+/** Card OCR 1 register */
+#define CARD_OCR_1_REG               	0x35
+
+/** Card Control Registers */
+#define CARD_REVISION_REG            	0x3c
+
+/** Firmware status 0 register */
+#define CARD_FW_STATUS0_REG		0x40
+/** Firmware status 1 register */
+#define CARD_FW_STATUS1_REG		0x41
+/** Rx length register */
+#define CARD_RX_LEN_REG			0x42
+/** Rx unit register */
+#define CARD_RX_UNIT_REG		0x43
+
+struct sdio_mmc_card
+{
+    struct sdio_func *func;
+    bt_private *priv;
+};
+
+#endif /* _BT_SDIO_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/include.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/include.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/bt/include.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/bt/include.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,43 @@
+/** @file include.h
+ *  @brief This file contains all the necessary include file.
+ *       
+ *  (c) Copyright 2007, Marvell International Ltd.   
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+
+#ifndef _INCLUDE_H_
+#define _INCLUDE_H_
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/proc_fs.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include  <linux/version.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+#include "bt_drv.h"
+#include "bt_sdio.h"
+#endif /* _INCLUDE_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/gpl.txt linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/gpl.txt
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/gpl.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/gpl.txt	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/Makefile linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/Makefile
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/Makefile	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,39 @@
+#############################################################################
+# Configuration Options
+#############################################################################
+
+# Debug Option
+# DEBUG LEVEL n/1:
+# n: NO DEBUG
+# 1: PRINTM(MSG,...), PRINTM(FATAL,...), PRINTM(WARN,...) and PRINTM(INFO,...)
+CONFIG_DEBUG=1
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+
+EXTRA_CFLAGS += -Ibt
+
+ifeq ($(CONFIG_DEBUG),1)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+endif
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+ifneq ($(KERNELRELEASE),)
+
+BTOBJS = bt/bt_main.o bt/bt_sdio.o bt/bt_proc.o
+
+obj-m := bt8xxx.o
+bt8xxx-objs := $(BTOBJS)
+
+
+# Otherwise we were called directly from the command line; invoke the kernel build system.
+else
+default:
+	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
+endif
+
+# End of file;
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/README linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/README
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_bt/README	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_bt/README	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,89 @@
+===============================================================================
+			U S E R  M A N U A L
+
+ (c) Copyright © 2003-2007, Marvell International Ltd. 
+
+ This software file (the "File") is distributed by Marvell International 
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ (the "License").  You may use, redistribute and/or modify this File in 
+ accordance with the terms and conditions of the License, a copy of which 
+ is available along with the File in the gpl.txt file or by writing to 
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ this warranty disclaimer.
+
+===============================================================================
+
+1) FOR DRIVER BUILD
+
+	Goto source code directory src_xxxx.
+		make [clean] build
+	The driver binaries can be found in ../bin_bt directory.
+
+2) FOR DRIVER INSTALL
+
+	a) Copy helper_sd.bin and sd8688.bin | sd8689.bin | ... to /lib/firmware/mrvl/ 
+	   directory, create the directory if it doesn't exist.
+	b) Install sdio bus driver and bluetooth driver,
+		./load sd8688 | sd8689 | ...
+	c) Uninstall bluetooth driver and sdio bus driver,
+		./unload
+3) cat /proc/net/mbt/hcix/config
+   This command is used to get the current driver settings. 
+
+4) cat /proc/net/mbt/hcix/status
+   This command is used to get driver status
+
+5) proc commands to config bluetooth parameters. 
+
+drvdbg=[n]
+   This command is used to set the bit masks of driver debug message control.
+
+   	bit 0:  MSG  		PRINTM(MSG,...)
+	bit 1:  FATAL		PRINTM(FATAL,...)
+	bit 2:  ERROR		PRINTM(ERROR,...)
+	bit 3:  CMD		PRINTM(CMD,...)
+	bit 27: DATA		DBG_HEXDUMP(DBG_DATA,...)
+	bit 28: ENTRY		PRINTM(ENTRY,...), ENTER(), LEAVE()
+	bit 29: WARN 		PRINTM(WARN,...)
+	bit 30: INFO 		PRINTM(INFO,...)
+
+	Usage:
+		echo "drvdbg=0x7" > /proc/net/mbt/hcix/config		#enable MSG,FATAL,ERROR messages
+
+gpio_gap=[n]
+   This command is used to configure the host sleep parameters.
+	bit 8:0  -- Gap
+	bit 16:8 -- GPIO
+
+	where GPIO is the pin number of GPIO used to wakeup the host. It could be any valid
+		GPIO pin# (e.g. 0-7) or 0xff (Interface, e.g. SDIO will be used instead).
+		
+	where Gap is the gap in milli seconds between wakeup signal and wakeup event 
+		or 0xff for special setting.
+	Usage:
+		echo "gpio_gap=0xff80" > /proc/net/mbt/hcix/config   	# use Interface (e.g. SDIO)
+		echo "hscfgcmd=1" > /proc/net/mbt/hcix/config		# gap = 0x80
+
+		echo "gpio_gap=0x03ff" > /proc/net/mbt/hcix/config   	# use gpio 3
+		echo "hscfgcmd=1" > /proc/net/mbt/hcix/config		# and special host sleep mode
+
+psmode=[n]
+    This command is used to enable/disable auto sleep mode
+	
+	where the option is:
+			1 	-- Enable auto sleep mode
+			0 	-- Disable auto sleep mode
+	Usage:
+		echo "psmode=1" > /proc/net/mbt/hcix/config		#enable power save mode
+		echo "pscmd=1" > /proc/net/mbt/hcix/config
+
+		echo "psmode=0" > /proc/net/mbt/hcix/config		#disable power save mode
+		echo "pscmd=1" > /proc/net/mbt/hcix/config
+		
+						
+==============================================================================
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/gpl.txt linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/gpl.txt
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/gpl.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/gpl.txt	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/Makefile linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/Makefile
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/Makefile	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,187 @@
+# File: Makefile
+#
+# (c) Copyright © 2003-2006, Marvell International Ltd. 
+#
+# This software file (the "File") is distributed by Marvell International 
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+# (the "License").  You may use, redistribute and/or modify this File in 
+# accordance with the terms and conditions of the License, a copy of which 
+# is available along with the File in the gpl.txt file or by writing to 
+# the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+# 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+# ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+# this warranty disclaimer.
+
+#CC=		$(CROSS)gcc
+#LD=		$(CROSS)ld
+#BACKUP=		/root/backup
+#YMD=		`date +%Y%m%d%H%M`
+
+#############################################################################
+# Configuration Options
+#############################################################################
+
+# Debug Option
+# DEBUG LEVEL n/1/2:
+# n: NO DEBUG
+# 1: Only PRINTM(MSG,...), PRINTM(FATAL,...), ...
+# 2: All PRINTM()
+CONFIG_DEBUG=0
+
+# Proc in /proc/net/wlan
+CONFIG_PROC_DEBUG=y
+
+# Re-association in driver
+CONFIG_REASSOCIATION=y
+
+# Manufacturing firmware support
+CONFIG_MFG_CMD_SUPPORT=y
+
+# Big-endian platform
+CONFIG_BIG_ENDIAN=n
+
+#############################################################################
+# Select Platform Tools
+#############################################################################
+
+MODEXT = ko
+EXTRA_CFLAGS += -Idrivers/net/wireless/8688_wlan/wlan
+
+LD += -S
+KERNELVERSION_X86 := 	$(shell uname -r)
+
+
+#############################################################################
+# Compiler Flags
+#############################################################################
+
+	#EXTRA_CFLAGS += -I$(KERNELDIR)/include
+
+	EXTRA_CFLAGS += -DFPNUM='"38"'
+
+ifeq ($(CONFIG_DEBUG),1)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+endif
+
+ifeq ($(CONFIG_DEBUG),2)
+	EXTRA_CFLAGS += -DDEBUG_LEVEL1
+	EXTRA_CFLAGS += -DDEBUG_LEVEL2
+	DBG=	-dbg
+endif
+
+ifeq ($(CONFIG_PROC_DEBUG),y)
+	EXTRA_CFLAGS += -DPROC_DEBUG
+	export CONFIG_PROC_DEBUG
+endif
+
+ifeq ($(CONFIG_REASSOCIATION),y)
+	EXTRA_CFLAGS += -DREASSOCIATION
+endif
+
+ifeq ($(CONFIG_MFG_CMD_SUPPORT),y)
+	EXTRA_CFLAGS += -DMFG_CMD_SUPPORT
+endif
+
+ifeq ($(CONFIG_BIG_ENDIAN),y)
+	EXTRA_CFLAGS += -DBIG_ENDIAN
+endif
+
+#############################################################################
+# Make Targets
+#############################################################################
+
+ifneq ($(KERNELRELEASE),)
+
+WLANOBJS =	wlan/wlan_main.o wlan/wlan_init.o wlan/wlan_wext.o \
+		wlan/wlan_rx.o wlan/wlan_tx.o \
+		wlan/wlan_cmd.o wlan/wlan_cmdresp.o \
+		wlan/wlan_scan.o wlan/wlan_join.o
+
+WLANOBJS += wlan/wlan_wmm.o
+WLANOBJS += wlan/wlan_11d.o
+WLANOBJS += wlan/wlan_11h.o
+WLANOBJS += wlan/wlan_meas.o
+
+ifdef CONFIG_PROC_FS
+WLANOBJS += wlan/wlan_proc.o
+ifeq ($(CONFIG_PROC_DEBUG), y)
+WLANOBJS += wlan/wlan_debug.o
+endif
+endif
+
+WLANOBJS += wlan/wlan_sdio.o
+obj-m := 8688_a2.o
+8688_a2-objs := $(WLANOBJS)
+
+# Otherwise we were called directly from the command line; invoke the kernel build system.
+else
+
+default:
+	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
+
+endif
+
+###############################################################
+
+export		CC LD EXTRA_CFLAGS KERNELDIR
+
+.PHONY: app/wlanconfig wlan clean distclean
+
+
+	@echo "Finished Making Marvell Wlan Linux Driver"
+
+wlan app/wlanconfig:
+	$(MAKE) -C $@
+
+echo:
+	@echo "Please make sure the following are done before building:"
+	@echo "	1. Modify wlan/wlan_drv.h to set correct version number"
+	@echo "	2. Update the README"
+
+build:		echo default
+
+	@if [ ! -d $(BINDIR) ]; then \
+		mkdir $(BINDIR); \
+	fi 
+	cp -f 8688_a2.$(MODEXT) $(BINDIR)/sd8688$(DBG).$(MODEXT)
+
+	cp -f README $(BINDIR)
+	$(MAKE) -C app/wlanconfig $@ INSTALLDIR=$(BINDIR)
+	cp -r config $(BINDIR)
+
+clean:
+	-find . -name "*.o" -exec rm {} \;
+	-find . -name "*.ko" -exec rm {} \;
+	-find . -name ".*.cmd" -exec rm {} \;
+	-find . -name "*.mod.c" -exec rm {} \;
+	-find . -name "Module.symvers" -exec rm {} \;
+	-rm -rf .tmp_versions
+	$(MAKE) -C app/wlanconfig $@
+
+install: default
+
+	cp -f io/sdio/$(PLATFORM)/sdio.$(MODEXT) $(INSTALLDIR)
+	$(MAKE) -C app/wlanconfig $@ INSTALLDIR=$(INSTALLDIR)
+	cp -f 8688_a2.$(MODEXT) $(INSTALLDIR)/sd8688$(DBG).$(MODEXT)
+	echo "sd8688 Driver Installed"
+
+distclean:
+	-find . -name "*.o" -exec rm {} \;
+	-find . -name "*.orig" -exec rm {} \;
+	-find . -name "*.swp" -exec rm {} \;
+	-find . -name "*.*~" -exec rm {} \;
+	-find . -name "*~" -exec rm {} \;
+	-find . -name "*.d" -exec rm {} \;
+	-find . -name "*.a" -exec rm {} \;
+	-find . -name "tags" -exec rm {} \;
+	-find . -name ".*" -exec rm -rf 2> /dev/null \;
+	-find . -name "*.ko" -exec rm {} \;
+	-find . -name ".*.cmd" -exec rm {} \;
+	-find . -name "*.mod.c" -exec rm {} \;
+	-rm -rf .tmp_versions
+	$(MAKE) -C app/wlanconfig $@
+
+# End of file
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11d.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11d.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11d.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11d.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,963 @@
+/** @file wlan_11d.c
+  * @brief This file contains functions for 802.11D.
+  *
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	
+********************************************************/
+#include	"wlan_headers.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+/** Default Tx power */
+#define TX_PWR_DEFAULT	10
+
+static region_code_mapping_t region_code_mapping[] = {
+    {"US ", 0x10},              /* US FCC      */
+    {"CA ", 0x20},              /* IC Canada   */
+    {"SG ", 0x10},              /* Singapore   */
+    {"EU ", 0x30},              /* ETSI        */
+    {"AU ", 0x30},              /* Australia   */
+    {"KR ", 0x30},              /* Republic Of Korea */
+    {"ES ", 0x31},              /* Spain       */
+    {"FR ", 0x32},              /* France      */
+    {"JP ", 0x40},              /* Japan       */
+    {"JP ", 0x41},              /* Japan       */
+};
+
+/* Following 2 structure defines the supported channels */
+/** Channels for 802.11b/g */
+static CHANNEL_FREQ_POWER channel_freq_power_UN_BG[] = {
+    {1, 2412, TX_PWR_DEFAULT},
+    {2, 2417, TX_PWR_DEFAULT},
+    {3, 2422, TX_PWR_DEFAULT},
+    {4, 2427, TX_PWR_DEFAULT},
+    {5, 2432, TX_PWR_DEFAULT},
+    {6, 2437, TX_PWR_DEFAULT},
+    {7, 2442, TX_PWR_DEFAULT},
+    {8, 2447, TX_PWR_DEFAULT},
+    {9, 2452, TX_PWR_DEFAULT},
+    {10, 2457, TX_PWR_DEFAULT},
+    {11, 2462, TX_PWR_DEFAULT},
+    {12, 2467, TX_PWR_DEFAULT},
+    {13, 2472, TX_PWR_DEFAULT},
+    {14, 2484, TX_PWR_DEFAULT}
+};
+
+/** Channels for 802.11a/j */
+static CHANNEL_FREQ_POWER channel_freq_power_UN_AJ[] = {
+    {8, 5040, TX_PWR_DEFAULT},
+    {12, 5060, TX_PWR_DEFAULT},
+    {16, 5080, TX_PWR_DEFAULT},
+    {34, 5170, TX_PWR_DEFAULT},
+    {38, 5190, TX_PWR_DEFAULT},
+    {42, 5210, TX_PWR_DEFAULT},
+    {46, 5230, TX_PWR_DEFAULT},
+    {36, 5180, TX_PWR_DEFAULT},
+    {40, 5200, TX_PWR_DEFAULT},
+    {44, 5220, TX_PWR_DEFAULT},
+    {48, 5240, TX_PWR_DEFAULT},
+    {52, 5260, TX_PWR_DEFAULT},
+    {56, 5280, TX_PWR_DEFAULT},
+    {60, 5300, TX_PWR_DEFAULT},
+    {64, 5320, TX_PWR_DEFAULT},
+    {100, 5500, TX_PWR_DEFAULT},
+    {104, 5520, TX_PWR_DEFAULT},
+    {108, 5540, TX_PWR_DEFAULT},
+    {112, 5560, TX_PWR_DEFAULT},
+    {116, 5580, TX_PWR_DEFAULT},
+    {120, 5600, TX_PWR_DEFAULT},
+    {124, 5620, TX_PWR_DEFAULT},
+    {128, 5640, TX_PWR_DEFAULT},
+    {132, 5660, TX_PWR_DEFAULT},
+    {136, 5680, TX_PWR_DEFAULT},
+    {140, 5700, TX_PWR_DEFAULT},
+    {149, 5745, TX_PWR_DEFAULT},
+    {153, 5765, TX_PWR_DEFAULT},
+    {157, 5785, TX_PWR_DEFAULT},
+    {161, 5805, TX_PWR_DEFAULT},
+    {165, 5825, TX_PWR_DEFAULT},
+/*	{240, 4920, TX_PWR_DEFAULT}, 
+	{244, 4940, TX_PWR_DEFAULT}, 
+	{248, 4960, TX_PWR_DEFAULT}, 
+	{252, 4980, TX_PWR_DEFAULT}, 
+channels for 11J JP 10M channel gap */
+};
+
+/********************************************************
+		Local Functions
+********************************************************/
+/** 
+ *  @brief This function convert Region string to code integer
+ *  @param region     region string
+ *  @return 	      region id
+*/
+static u8
+wlan_region_2_code(s8 * region)
+{
+    u8 i;
+    u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+
+    for (i = 0; i < COUNTRY_CODE_LEN && region[i]; i++)
+        region[i] = toupper(region[i]);
+
+    for (i = 0; i < size; i++) {
+        if (!memcmp(region, region_code_mapping[i].region, COUNTRY_CODE_LEN))
+            return (region_code_mapping[i].code);
+    }
+
+    /* default is US */
+    return (region_code_mapping[0].code);
+}
+
+/** 
+ *  @brief This function converts interger code to region string
+ *  @param code       region code
+ *  @return 	      region string
+*/
+static u8 *
+wlan_code_2_region(u8 code)
+{
+    u8 i;
+    u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
+    for (i = 0; i < size; i++) {
+        if (region_code_mapping[i].code == code)
+            return (region_code_mapping[i].region);
+    }
+    /* default is US */
+    return (region_code_mapping[0].region);
+}
+
+/** 
+ *  @brief This function finds the NoOfChan-th chan after the firstChan
+ *  @param band       band
+ *  @param firstChan  first channel number
+ *  @param NoOfChan   number of channels
+ *  @param chan       pointer to the returned NoOfChan-th chan number
+ *  @return 	      TRUE; FALSE
+*/
+static BOOLEAN
+wlan_get_chan_11d(u8 band, u8 firstChan, u8 NoOfChan, u8 * chan)
+/*find the NoOfChan-th chan after the firstChan*/
+{
+    u8 i;
+    CHANNEL_FREQ_POWER *cfp;
+    u8 cfp_no;
+
+    ENTER();
+
+    if (band & (BAND_B | BAND_G)) {
+        cfp = channel_freq_power_UN_BG;
+        cfp_no = sizeof(channel_freq_power_UN_BG) /
+            sizeof(CHANNEL_FREQ_POWER);
+    } else {
+        if (band & BAND_A) {
+            cfp = channel_freq_power_UN_AJ;
+            cfp_no = sizeof(channel_freq_power_UN_AJ) /
+                sizeof(CHANNEL_FREQ_POWER);
+        } else {
+            PRINTM(INFO, "Wrong Band[%d\n", band);
+            return FALSE;
+        }
+    }
+
+    for (i = 0; i < cfp_no; i++) {
+        if ((cfp + i)->Channel == firstChan) {
+            PRINTM(INFO, "firstChan found\n");
+            break;
+        }
+    }
+
+    if (i < cfp_no) {
+        /*if beyond the boundary */
+        if (i + NoOfChan < cfp_no) {
+            *chan = (cfp + i + NoOfChan)->Channel;
+            return TRUE;
+        }
+    }
+
+    LEAVE();
+    return FALSE;
+}
+
+/** 
+ *  @brief This function Checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t     
+ *  @return 	                TRUE; FALSE
+*/
+BOOLEAN
+wlan_channel_known_11d(u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+    chan_power_11d_t *chanPwr = parsed_region_chan->chanPwr;
+    u8 NoOfChan = parsed_region_chan->NoOfChan;
+    u8 i = 0;
+
+    ENTER();
+    HEXDUMP("11D:parsed_region_chan:", (char *) chanPwr,
+            sizeof(chan_power_11d_t) * NoOfChan);
+
+    for (i = 0; i < NoOfChan; i++) {
+        if (chan == chanPwr[i].chan) {
+            PRINTM(INFO, "11D: Found Chan:%d\n", chan);
+            LEAVE();
+            return TRUE;
+        }
+    }
+
+    PRINTM(INFO, "11D: Not Find Chan:%d\n", chan);
+    LEAVE();
+    return FALSE;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function Converts chan to frequency
+ *  @param chan                 channel number
+ *  @param band                 band
+ *  @return 	                channel frequency
+*/
+u32
+chan_2_freq(u8 chan, u8 band)
+{
+    CHANNEL_FREQ_POWER *cf;
+    u16 cnt;
+    u16 i;
+    u32 freq = 0;
+
+    ENTER();
+
+    if (band & BAND_A) {
+        cf = channel_freq_power_UN_AJ;
+        cnt = sizeof(channel_freq_power_UN_AJ) / sizeof(CHANNEL_FREQ_POWER);
+    } else {
+        cf = channel_freq_power_UN_BG;
+        cnt = sizeof(channel_freq_power_UN_BG) / sizeof(CHANNEL_FREQ_POWER);
+    }
+
+    for (i = 0; i < cnt; i++) {
+        if (chan == cf[i].Channel)
+            freq = cf[i].Freq;
+    }
+
+    LEAVE();
+    return freq;
+}
+
+/** 
+ *  @brief This function generates domaininfo from parsed_region_chan
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t
+ *  @param domaininfo           pointer to wlan_802_11d_domain_reg_t
+ *  @return 	                WLAN_STATUS_SUCCESS
+*/
+int
+wlan_generate_domain_info_11d(parsed_region_chan_11d_t * parsed_region_chan,
+                              wlan_802_11d_domain_reg_t * domaininfo)
+{
+    u8 NoOfSubband = 0;
+
+    u8 NoOfChan = parsed_region_chan->NoOfChan;
+    u8 NoOfParsedChan = 0;
+
+    u8 firstChan = 0, nextChan = 0, maxPwr = 0;
+
+    u8 i, flag = 0;
+
+    ENTER();
+
+    memcpy(domaininfo->CountryCode, parsed_region_chan->CountryCode,
+           COUNTRY_CODE_LEN);
+
+    PRINTM(INFO, "11D:NoOfChan=%d\n", NoOfChan);
+    HEXDUMP("11D:parsed_region_chan:", (char *) parsed_region_chan,
+            sizeof(parsed_region_chan_11d_t));
+
+    for (i = 0; i < NoOfChan; i++) {
+        if (!flag) {
+            flag = 1;
+            nextChan = firstChan = parsed_region_chan->chanPwr[i].chan;
+            maxPwr = parsed_region_chan->chanPwr[i].pwr;
+            NoOfParsedChan = 1;
+            continue;
+        }
+
+        if (parsed_region_chan->chanPwr[i].chan == nextChan + 1 &&
+            parsed_region_chan->chanPwr[i].pwr == maxPwr) {
+            nextChan++;
+            NoOfParsedChan++;
+        } else {
+            domaininfo->Subband[NoOfSubband].FirstChan = firstChan;
+            domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan;
+            domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr;
+            NoOfSubband++;
+            NoOfParsedChan = 1;
+            nextChan = firstChan = parsed_region_chan->chanPwr[i].chan;
+            maxPwr = parsed_region_chan->chanPwr[i].pwr;
+        }
+    }
+
+    if (flag) {
+        domaininfo->Subband[NoOfSubband].FirstChan = firstChan;
+        domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan;
+        domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr;
+        NoOfSubband++;
+    }
+    domaininfo->NoOfSubband = NoOfSubband;
+
+    PRINTM(INFO, "NoOfSubband=%x\n", domaininfo->NoOfSubband);
+    HEXDUMP("11D:domaininfo:", (char *) domaininfo,
+            COUNTRY_CODE_LEN + 1 +
+            sizeof(IEEEtypes_SubbandSet_t) * NoOfSubband);
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region_chan          pointer to REGION_CHANNEL
+ *  @param *parsed_region_chan  pointer to parsed_region_chan_11d_t
+ *  @return 	                N/A
+*/
+void
+wlan_generate_parsed_region_chan_11d(REGION_CHANNEL * region_chan,
+                                     parsed_region_chan_11d_t *
+                                     parsed_region_chan)
+{
+    u8 i;
+    CHANNEL_FREQ_POWER *cfp;
+
+    ENTER();
+
+    if (region_chan == NULL) {
+        PRINTM(INFO, "11D: region_chan is NULL\n");
+        return;
+    }
+
+    cfp = region_chan->CFP;
+    if (cfp == NULL) {
+        PRINTM(INFO, "11D: cfp equal NULL \n");
+        return;
+    }
+
+    parsed_region_chan->band = region_chan->Band;
+    parsed_region_chan->region = region_chan->Region;
+    memcpy(parsed_region_chan->CountryCode,
+           wlan_code_2_region(region_chan->Region), COUNTRY_CODE_LEN);
+
+    PRINTM(INFO, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+           parsed_region_chan->band);
+
+    for (i = 0; i < region_chan->NrCFP; i++, cfp++) {
+        parsed_region_chan->chanPwr[i].chan = cfp->Channel;
+        parsed_region_chan->chanPwr[i].pwr = cfp->MaxTxPower;
+        PRINTM(INFO, "11D: Chan[%d] Pwr[%d]\n",
+               parsed_region_chan->chanPwr[i].chan,
+               parsed_region_chan->chanPwr[i].pwr);
+    }
+    parsed_region_chan->NoOfChan = region_chan->NrCFP;
+
+    PRINTM(INFO, "11D: NoOfChan[%d]\n", parsed_region_chan->NoOfChan);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region               region ID
+ *  @param band                 band
+ *  @param chan                 chan
+ *  @return 	                TRUE;FALSE
+*/
+BOOLEAN
+wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+{
+    CHANNEL_FREQ_POWER *cfp;
+    int cfp_no;
+    u8 idx;
+
+    ENTER();
+
+    if ((cfp = wlan_get_region_cfp_table(region, band, &cfp_no)) == NULL) {
+        return FALSE;
+    }
+
+    for (idx = 0; idx < cfp_no; idx++) {
+        if (chan == (cfp + idx)->Channel) {
+            /* If Mrvl Chip Supported? */
+            if ((cfp + idx)->Unsupported) {
+                return FALSE;
+            } else {
+                return TRUE;
+            }
+        }
+    }
+
+    /*chan is not in the region table */
+    LEAVE();
+    return FALSE;
+}
+
+/** 
+ *  @brief This function checks if chan txpwr is learned from AP/IBSS
+ *  @param CountryInfo          country information
+ *  @param band                 chan band
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t     
+ *  @return 	                WLAN_STATUS_SUCCESS       
+*/
+int
+wlan_parse_domain_info_11d(IEEEtypes_CountryInfoFullSet_t * CountryInfo,
+                           u8 band,
+                           parsed_region_chan_11d_t * parsed_region_chan)
+{
+    u8 NoOfSubband, NoOfChan;
+    u8 lastChan, firstChan, curChan;
+    u8 region;
+
+    u8 idx = 0;                 /*chan index in parsed_region_chan */
+
+    u8 j, i;
+
+    ENTER();
+
+    /*Validation Rules:
+       1. Valid Region Code
+       2. First Chan increment
+       3. Channel range no overlap
+       4. Channel is valid?
+       5. Channel is supported by Region?
+       6. Others
+     */
+
+    HEXDUMP("CountryInfo:", (s8 *) CountryInfo, 30);
+
+    if ((*(CountryInfo->CountryCode)) == 0 ||
+        (CountryInfo->Len <= COUNTRY_CODE_LEN)) {
+        /* No region Info or Wrong region info: treat as No 11D info */
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    /*Step1: check region_code */
+    parsed_region_chan->region = region =
+        wlan_region_2_code((s8 *) CountryInfo->CountryCode);
+
+    PRINTM(INFO, "regioncode=%x\n", (u8) parsed_region_chan->region);
+    HEXDUMP("CountryCode:", (char *) CountryInfo->CountryCode,
+            COUNTRY_CODE_LEN);
+
+    parsed_region_chan->band = band;
+
+    memcpy(parsed_region_chan->CountryCode, CountryInfo->CountryCode,
+           COUNTRY_CODE_LEN);
+
+    NoOfSubband = (CountryInfo->Len - COUNTRY_CODE_LEN) /
+        sizeof(IEEEtypes_SubbandSet_t);
+
+    for (j = 0, lastChan = 0; j < NoOfSubband; j++) {
+
+        if (CountryInfo->Subband[j].FirstChan <= lastChan) {
+            /*Step2&3. Check First Chan Num increment and no overlap */
+            PRINTM(INFO, "11D: Chan[%d>%d] Overlap\n",
+                   CountryInfo->Subband[j].FirstChan, lastChan);
+            continue;
+        }
+
+        firstChan = CountryInfo->Subband[j].FirstChan;
+        NoOfChan = CountryInfo->Subband[j].NoOfChan;
+
+        for (i = 0; idx < MAX_NO_OF_CHAN && i < NoOfChan; i++) {
+            /*step4: channel is supported? */
+
+            if (wlan_get_chan_11d(band, firstChan, i, &curChan)
+                == FALSE) {
+                /* Chan is not found in UN table */
+                PRINTM(INFO, "chan is not supported: %d \n", i);
+                break;
+            }
+
+            lastChan = curChan;
+
+            /*step5: We don't need to Check if curChan is supported by mrvl in region */
+            parsed_region_chan->chanPwr[idx].chan = curChan;
+            parsed_region_chan->chanPwr[idx].pwr =
+                CountryInfo->Subband[j].MaxTxPwr;
+            idx++;
+        }
+
+        /*Step6: Add other checking if any */
+
+    }
+
+    parsed_region_chan->NoOfChan = idx;
+
+    PRINTM(INFO, "NoOfChan=%x\n", parsed_region_chan->NoOfChan);
+    HEXDUMP("11D:parsed_region_chan:", (s8 *) parsed_region_chan,
+            2 + COUNTRY_CODE_LEN + sizeof(parsed_region_chan_11d_t) * idx);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function calculates the scan type for channels
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d_t     
+ *  @return 	                PASSIVE if chan is unknown; ACTIVE if chan is known
+*/
+u8
+wlan_get_scan_type_11d(u8 chan, parsed_region_chan_11d_t * parsed_region_chan)
+{
+    u8 scan_type = HostCmd_SCAN_TYPE_PASSIVE;
+
+    ENTER();
+
+    if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+        PRINTM(INFO, "11D: Found and do Active Scan\n");
+        scan_type = HostCmd_SCAN_TYPE_ACTIVE;
+    } else {
+        PRINTM(INFO, "11D: Not Find and do Passive Scan\n");
+    }
+
+    LEAVE();
+    return scan_type;
+
+}
+
+/** 
+ *  @brief This function gets if 11D is enabled
+ *  @param priv       pointer to wlan_private
+ *  @return 	      ENABLE_11D;DISABLE_11D
+*/
+state_11d_t
+wlan_get_state_11d(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_802_11d_state_t *state = &Adapter->State11D;
+    return (state->Enable11D);
+}
+
+/** 
+ *  @brief initialize internal variable for 11D
+ *  @param priv       pointer to wlan_private
+ *  @return 	      N/A
+*/
+void
+wlan_init_11d(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_802_11d_state_t *state = &Adapter->State11D;
+
+    state->Enable11D = DISABLE_11D;
+
+    memset(&(priv->adapter->parsed_region_chan), 0,
+           sizeof(parsed_region_chan_11d_t));
+
+    return;
+}
+
+/** 
+ *  @brief This function enable/disable 11D
+ *  @param priv       pointer to wlan_private
+ *  @param flag       enable/disable flag
+ *  @return 	      WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+*/
+int
+wlan_enable_11d(wlan_private * priv, state_11d_t flag)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_802_11d_state_t *state = &Adapter->State11D;
+    int ret;
+    state_11d_t enable = flag;
+
+    ENTER();
+
+    state->Enable11D = flag;
+
+    /* send cmd to FW to enable/disable 11D fucntion in FW */
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_SNMP_MIB,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, Dot11D_i, &enable);
+    if (ret) {
+        PRINTM(INFO, "11D: Fail to enable 11D \n");
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sets DOMAIN INFO to FW
+ *  @param priv       pointer to wlan_private
+ *  @return 	      WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+*/
+int
+wlan_set_domain_info_11d(wlan_private * priv)
+{
+    int ret;
+
+    if (!wlan_get_state_11d(priv)) {
+        PRINTM(INFO, "11D: dnld domain Info with 11d disabled\n");
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, 0, NULL);
+    if (ret) {
+        PRINTM(INFO, "11D: Fail to dnld domain Info\n");
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function setups scan channels
+ *  @param priv       pointer to wlan_private
+ *  @param band       band
+ *  @return 	      WLAN_STATUS_SUCCESS
+*/
+int
+wlan_set_universaltable(wlan_private * priv, u8 band)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u16 size = sizeof(CHANNEL_FREQ_POWER);
+    u16 i = 0;
+
+    ENTER();
+
+    memset(Adapter->universal_channel, 0, sizeof(Adapter->universal_channel));
+
+    if (band & (BAND_B | BAND_G)) {
+        Adapter->universal_channel[i].NrCFP =
+            sizeof(channel_freq_power_UN_BG) / size;
+        PRINTM(INFO, "11D: BG-band NrCFP=%d\n",
+               Adapter->universal_channel[i].NrCFP);
+
+        Adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+        Adapter->universal_channel[i].Valid = TRUE;
+        Adapter->universal_channel[i].Region = UNIVERSAL_REGION_CODE;
+        Adapter->universal_channel[i].Band =
+            (band & BAND_G) ? BAND_G : BAND_B;
+        i++;
+    }
+
+    if (band & BAND_A) {
+        Adapter->universal_channel[i].NrCFP =
+            sizeof(channel_freq_power_UN_AJ) / size;
+        PRINTM(INFO, "11D: AJ-band NrCFP=%d\n",
+               Adapter->universal_channel[i].NrCFP);
+        Adapter->universal_channel[i].CFP = channel_freq_power_UN_AJ;
+
+        Adapter->universal_channel[i].Valid = TRUE;
+        Adapter->universal_channel[i].Region = UNIVERSAL_REGION_CODE;
+        Adapter->universal_channel[i].Band = BAND_A;
+        i++;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *  @param priv       pointer to wlan_private
+ *  @param cmd        pointer to cmd buffer
+ *  @param cmdno      cmd ID
+ *  @param CmdOption  cmd action 
+ *  @return 	      WLAN_STATUS_SUCCESS
+*/
+int
+wlan_cmd_802_11d_domain_info(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, u16 cmdno,
+                             u16 CmdOption)
+{
+    HostCmd_DS_802_11D_DOMAIN_INFO *pDomainInfo = &cmd->params.domaininfo;
+    MrvlIEtypes_DomainParamSet_t *domain = &pDomainInfo->Domain;
+    wlan_adapter *Adapter = priv->adapter;
+    u8 NoOfSubband = Adapter->DomainReg.NoOfSubband;
+
+    ENTER();
+
+    PRINTM(INFO, "NoOfSubband=%x\n", NoOfSubband);
+
+    cmd->Command = wlan_cpu_to_le16(cmdno);
+    pDomainInfo->Action = wlan_cpu_to_le16(CmdOption);
+    if (CmdOption == HostCmd_ACT_GEN_GET) {
+        cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN);
+        HEXDUMP("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, (int) (cmd->Size));
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    domain->Header.Type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
+    memcpy(domain->CountryCode, Adapter->DomainReg.CountryCode,
+           sizeof(domain->CountryCode));
+
+    domain->Header.Len =
+        wlan_cpu_to_le16(NoOfSubband * sizeof(IEEEtypes_SubbandSet_t) +
+                         sizeof(domain->CountryCode));
+
+    if (NoOfSubband) {
+        memcpy(domain->Subband, Adapter->DomainReg.Subband,
+               NoOfSubband * sizeof(IEEEtypes_SubbandSet_t));
+
+        cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) +
+                                     domain->Header.Len +
+                                     sizeof(MrvlIEtypesHeader_t) + S_DS_GEN);
+    } else {
+        cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN);
+    }
+
+    HEXDUMP("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int) (cmd->Size));
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function implements private cmd: enable/disable 11D
+ *  @param priv    pointer to wlan_private
+ *  @param wrq     pointer to user data 
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+    int data = 0;
+    int *val;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+    PRINTM(INFO, "Enable 11D: %s\n",
+           (data == CMD_ENABLED) ? "Enable" : "Disable");
+    switch (data) {
+    case CMD_ENABLED:
+        wlan_enable_11d(priv, ENABLE_11D);
+        break;
+    case CMD_DISABLED:
+        wlan_enable_11d(priv, DISABLE_11D);
+        break;
+    default:
+        break;
+    }
+
+    data =
+        (Adapter->State11D.Enable11D ==
+         ENABLE_11D) ? CMD_ENABLED : CMD_DISABLED;
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @param resp    pointer to command response buffer
+ *  @return 	   WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11d_domain_info(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+        * domaininfo = &resp->params.domaininforesp;
+    MrvlIEtypes_DomainParamSet_t * domain = &domaininfo->Domain;
+    u16 Action = wlan_le16_to_cpu(domaininfo->Action);
+    s16 ret = WLAN_STATUS_SUCCESS;
+    u8 NoOfSubband = 0;
+
+    ENTER();
+
+    HEXDUMP("11D DOMAIN Info Rsp Data:", (u8 *) resp, resp->Size);
+
+    NoOfSubband =
+        (wlan_le16_to_cpu(domain->Header.Len) -
+         3) / sizeof(IEEEtypes_SubbandSet_t);
+    /* countrycode 3 bytes */
+
+    PRINTM(INFO, "11D Domain Info Resp: NoOfSubband=%d\n", NoOfSubband);
+
+    if (NoOfSubband > MRVDRV_MAX_SUBBAND_802_11D) {
+        PRINTM(INFO, "Invalid Numrer of Subband returned!!\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    switch (Action) {
+    case HostCmd_ACT_GEN_SET:  /*Proc Set Action */
+        break;
+
+    case HostCmd_ACT_GEN_GET:
+        break;
+    default:
+        PRINTM(INFO, "Invalid Action:%d\n", domaininfo->Action);
+        ret = WLAN_STATUS_FAILURE;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        /* Skip new 11d download when roaming */
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    if (wlan_get_state_11d(priv) == ENABLE_11D) {
+
+        memset(&Adapter->parsed_region_chan, 0,
+               sizeof(parsed_region_chan_11d_t));
+
+        ret =
+            wlan_parse_domain_info_11d(&Adapter->pAttemptedBSSDesc->
+                                       CountryInfo,
+                                       Adapter->pAttemptedBSSDesc->bss_band,
+                                       &Adapter->parsed_region_chan);
+
+        if (ret == WLAN_STATUS_FAILURE) {
+            PRINTM(INFO, "11D: Err Parse domain_info from AP..\n");
+            LEAVE();
+            return ret;
+        }
+
+        memset(&Adapter->DomainReg, 0, sizeof(wlan_802_11d_domain_reg_t));
+        wlan_generate_domain_info_11d(&Adapter->parsed_region_chan,
+                                      &Adapter->DomainReg);
+
+        ret = wlan_set_domain_info_11d(priv);
+
+        if (ret) {
+            PRINTM(INFO, "11D: Err set domainInfo to FW\n");
+            LEAVE();
+            return ret;
+        }
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function generates 11D info from user specified regioncode and download to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_create_dnld_countryinfo_11d(wlan_private * priv)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    REGION_CHANNEL *region_chan;
+    u8 j;
+
+    ENTER();
+    PRINTM(INFO, "11D:CurBssParams.Band[%d]\n", Adapter->CurBssParams.band);
+
+    if (wlan_get_state_11d(priv) == ENABLE_11D) {
+        /* update parsed_region_chan_11; dnld domaininf to FW */
+
+        for (j = 0; j < sizeof(Adapter->region_channel) /
+             sizeof(Adapter->region_channel[0]); j++) {
+            region_chan = &Adapter->region_channel[j];
+
+            PRINTM(INFO, "11D:[%d] region_chan->Band[%d]\n", j,
+                   region_chan->Band);
+
+            if (!region_chan || !region_chan->Valid || !region_chan->CFP)
+                continue;
+            switch (region_chan->Band) {
+            case BAND_A:
+                switch (Adapter->CurBssParams.band) {
+                case BAND_A:
+                    break;
+                default:
+                    continue;
+                }
+                break;
+            case BAND_B:
+            case BAND_G:
+                switch (Adapter->CurBssParams.band) {
+                case BAND_B:
+                case BAND_G:
+                    break;
+                default:
+                    continue;
+                }
+                break;
+            default:
+                continue;
+            }
+            break;
+        }
+
+        if (j >= sizeof(Adapter->region_channel) /
+            sizeof(Adapter->region_channel[0])) {
+            PRINTM(INFO, "11D:region_chan not found. Band[%d]\n",
+                   Adapter->CurBssParams.band);
+            LEAVE();
+            return WLAN_STATUS_FAILURE;
+        }
+
+        memset(&Adapter->parsed_region_chan, 0,
+               sizeof(parsed_region_chan_11d_t));
+        wlan_generate_parsed_region_chan_11d(region_chan,
+                                             &Adapter->parsed_region_chan);
+
+        memset(&Adapter->DomainReg, 0, sizeof(wlan_802_11d_domain_reg_t));
+        wlan_generate_domain_info_11d(&Adapter->parsed_region_chan,
+                                      &Adapter->DomainReg);
+
+        ret = wlan_set_domain_info_11d(priv);
+
+        if (ret) {
+            PRINTM(INFO, "11D: Err set domainInfo to FW\n");
+            LEAVE();
+            return ret;
+        }
+
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11d.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11d.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11d.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11d.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,138 @@
+/** @file wlan_11d.h
+ *  @brief This header file contains data structures and 
+ *  function declarations of 802.11d  
+ *
+ * (c) Copyright © 2003-2006, Marvell International Ltd.  
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change log:
+	09/26/05: add Doxygen format comments 
+ ************************************************************/
+
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+/** Maximum number of channels */
+#define MAX_CHAN_NUM				255
+
+/** Universal region code */
+#define UNIVERSAL_REGION_CODE			0xff
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) 
+ */
+#define MAX_NO_OF_CHAN 				40
+
+/** Preregion channel */
+typedef struct _REGION_CHANNEL *PREGION_CHANNEL;
+
+/** State of 11d */
+typedef enum
+{
+    DISABLE_11D = 0,
+    ENABLE_11D = 1,
+} state_11d_t;
+
+/** domain regulatory information */
+typedef struct _wlan_802_11d_domain_reg
+{
+        /** country Code*/
+    u8 CountryCode[COUNTRY_CODE_LEN];
+        /** No. of subband*/
+    u8 NoOfSubband;
+        /** Subband data */
+    IEEEtypes_SubbandSet_t Subband[MRVDRV_MAX_SUBBAND_802_11D];
+} wlan_802_11d_domain_reg_t;
+
+typedef struct _chan_power_11d
+{
+        /** 11D channel */
+    u8 chan;
+        /** 11D channel power */
+    u8 pwr;
+} __ATTRIB_PACK__ chan_power_11d_t;
+
+typedef struct _parsed_region_chan_11d
+{
+        /** 11d band */
+    u8 band;
+        /** 11d region */
+    u8 region;
+        /** 11d country code */
+    s8 CountryCode[COUNTRY_CODE_LEN];
+        /** 11d channel power per channel */
+    chan_power_11d_t chanPwr[MAX_NO_OF_CHAN];
+        /** 11d number of channels */
+    u8 NoOfChan;
+} __ATTRIB_PACK__ parsed_region_chan_11d_t;
+
+/** Data for state machine */
+typedef struct _wlan_802_11d_state
+{
+        /** True for Enabling  11D*/
+    BOOLEAN Enable11D;
+} wlan_802_11d_state_t;
+
+typedef struct _region_code_mapping
+{
+        /** Region */
+    s8 region[COUNTRY_CODE_LEN];
+        /** Code */
+    u8 code;
+} region_code_mapping_t;
+
+/* function prototypes*/
+int wlan_generate_domain_info_11d(parsed_region_chan_11d_t *
+                                  parsed_region_chan,
+                                  wlan_802_11d_domain_reg_t * domaininfo);
+
+int wlan_parse_domain_info_11d(IEEEtypes_CountryInfoFullSet_t * CountryInfo,
+                               u8 band,
+                               parsed_region_chan_11d_t * parsed_region_chan);
+
+u8 wlan_get_scan_type_11d(u8 chan,
+                          parsed_region_chan_11d_t * parsed_region_chan);
+
+u32 chan_2_freq(u8 chan, u8 band);
+
+int wlan_set_domain_info_11d(wlan_private * priv);
+
+state_11d_t wlan_get_state_11d(wlan_private * priv);
+
+void wlan_init_11d(wlan_private * priv);
+
+int wlan_enable_11d(wlan_private * priv, state_11d_t flag);
+
+int wlan_set_universaltable(wlan_private * priv, u8 band);
+
+void wlan_generate_parsed_region_chan_11d(PREGION_CHANNEL region_chan,
+                                          parsed_region_chan_11d_t *
+                                          parsed_region_chan);
+
+int wlan_cmd_802_11d_domain_info(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * cmd, u16 cmdno,
+                                 u16 CmdOption);
+
+int wlan_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int wlan_ret_802_11d_domain_info(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * resp);
+
+int wlan_parse_dnld_countryinfo_11d(wlan_private * priv);
+
+int wlan_create_dnld_countryinfo_11d(wlan_private * priv);
+
+#endif /* _WLAN_11D_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11h.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11h.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11h.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11h.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1521 @@
+/**
+ * @file wlan_11h.c
+ *
+ *  @brief Implementation of 802.11h wlan_11h module
+ *
+ *  Driver implementation of the 11h standard.  Contains the following:
+ *    - application/driver ioctl interface functions
+ *    - firmware command preparation and response handling
+ *    - 11h element identification for elements passed in scan responses
+ *
+ *  Requires use of the following preprocessor define:
+ *    - ENABLE_802_11H
+ *
+ *  @sa wlan_11h.h
+ *  
+ *  (c) Copyright © 2003-2006, Marvell International Ltd.  
+ *  
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    9/30/05: Added DFS code, reorganized TPC code to match conventions
+   01/11/06: Add connected channel qualification to radar detection
+             requirement determination.  Update doxygen formatting.
+
+************************************************************/
+
+/*
+ * Include(s)
+ */
+#include "wlan_headers.h"
+
+/*
+ * Constants
+ */
+
+//! Default IBSS DFS recovery interval (in TBTTs); used for adhoc start
+#define WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL   100
+
+//! Compiler control flag used to add quiet element to adhoc start command */
+#define WLAN_11H_ADD_QUIET_ELEMENT   1
+
+//! Default 11h power constraint used to offset the maximum transmit power
+#define WLAN_11H_TPC_POWERCONSTRAINT  0
+
+//! 11h TPC Power capability minimum setting, sent in TPC_INFO command to fw
+#define WLAN_11H_TPC_POWERCAPABILITY_MIN     5
+
+//! 11h TPC Power capability maximum setting, sent in TPC_INFO command to fw
+#define WLAN_11H_TPC_POWERCAPABILITY_MAX     20
+
+//! Regulatory requirement for the duration of a channel availability check
+#define WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION    60000  /* in ms */
+
+//! U-NII sub-band config : Start Channel = 36, NumChans = 4
+static const
+    IEEEtypes_SupportChan_Subband_t wlan_11h_unii_lower_band = { 36, 4 };
+
+//! U-NII sub-band config : Start Channel = 52, NumChans = 4
+static const
+    IEEEtypes_SupportChan_Subband_t wlan_11h_unii_middle_band = { 52, 4 };
+
+//! U-NII sub-band config : Start Channel = 100, NumChans = 11
+static const
+    IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band =
+    { 100, 11 };
+
+//! U-NII sub-band config : Start Channel = 149, NumChans = 4
+static const
+    IEEEtypes_SupportChan_Subband_t wlan_11h_unii_upper_band = { 149, 4 };
+
+/*
+ * Local types
+ */
+
+//! Internally passed structure used to send a CMD_802_11_TPC_INFO command
+typedef struct
+{
+    u8 Chan;                    //!< Channel to which the power constraint applies
+    u8 PowerConstraint;         //!< Local power constraint to send to firmware
+} wlan_11h_tpc_info_param_t;
+
+/**
+ *  @brief Utility function to get a random number based on the underlying OS
+ *
+ *  @return random integer
+ */
+static int
+wlan_11h_get_random_num(void)
+{
+    return jiffies;
+}
+
+/**
+ *  @brief Convert an IEEE formatted IE to 16-bit ID/Len Marvell
+ *         proprietary format
+ *
+ *  @param pOutBuf Output parameter: Buffer to output Marvell formatted IE
+ *  @param pInIe   Pointer to IEEE IE to be converted to Marvell format
+ *
+ *  @return        Number of bytes output to pOutBuf parameter return
+ */
+static int
+wlan_11h_convert_ieee_to_mrvl_ie(char *pOutBuf, const char *pInIe)
+{
+    MrvlIEtypesHeader_t mrvlIeHdr;
+    char *pTmpBuf = pOutBuf;
+
+    /* Assign the Element Id and Len to the Marvell struct attributes */
+    mrvlIeHdr.Type = wlan_cpu_to_le16(pInIe[0]);
+    mrvlIeHdr.Len = wlan_cpu_to_le16(pInIe[1]);
+
+    /* If the element ID is zero, return without doing any copying */
+    if (mrvlIeHdr.Type == 0) {
+        return 0;
+    }
+
+    /* Copy the header to the buffer pointer */
+    memcpy(pTmpBuf, &mrvlIeHdr, sizeof(mrvlIeHdr));
+
+    /* Increment the temp buffer pointer by the size appended */
+    pTmpBuf += sizeof(mrvlIeHdr);
+
+    /* Append the data section of the IE; length given by the IEEE IE length */
+    memcpy(pTmpBuf, pInIe + 2, pInIe[1]);
+
+    /* Return the number of bytes appended to pBuf */
+    return (sizeof(mrvlIeHdr) + pInIe[1]);
+}
+
+/**
+ *  @brief Setup the IBSS DFS element passed to the firmware in adhoc start
+ *         and join commands
+ *
+ *  The DFS Owner and recovery fields are set to be our MAC address and
+ *    a predetermined constant recovery value.  If we are joining an adhoc
+ *    network, these values are replaced with the existing IBSS values.
+ *    They are valid only when starting a new IBSS.
+ *
+ *  The IBSS DFS Element is variable in size based on the number of
+ *    channels supported in our current region.
+ *
+ *  @param priv Private driver information structure
+ *  @param pDfs Output parameter: Pointer to the IBSS DFS element setup by
+ *              this function.
+ *
+ *  @return
+ *    - Length of the returned element in pDfs output parameter
+ *    - 0 if returned element is not setup
+ */
+static int
+wlan_11h_set_ibss_dfs_ie(wlan_private * priv, IEEEtypes_IBSS_DFS_t * pDfs)
+{
+    int numChans = 0;
+    MeasRptBasicMap_t initialMap;
+    wlan_adapter *Adapter = priv->adapter;
+
+    PRINTM(INFO, "11h: IBSS DFS Element, 11D parsed region: %c%c (0x%x)\n",
+           Adapter->parsed_region_chan.CountryCode[0],
+           Adapter->parsed_region_chan.CountryCode[1],
+           Adapter->parsed_region_chan.region);
+
+    memset(pDfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+    /*
+     * A basic measurement report is included with each channel in the
+     *   map field.  Initial value for the map for each supported channel
+     *   is with only the unmeasured bit set.
+     */
+    memset(&initialMap, 0x00, sizeof(initialMap));
+    initialMap.unmeasured = 1;
+
+    /* Set the DFS Owner and recovery interval fields */
+    memcpy(pDfs->dfsOwner, Adapter->CurrentAddr, sizeof(pDfs->dfsOwner));
+    pDfs->dfsRecoveryInterval = WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL;
+
+    for (; (numChans < Adapter->parsed_region_chan.NoOfChan)
+         && (numChans < WLAN_11H_MAX_IBSS_DFS_CHANNELS); numChans++) {
+        pDfs->channelMap[numChans].channelNumber =
+            Adapter->parsed_region_chan.chanPwr[numChans].chan;
+
+        /*
+         * Set the inital map field with a basic measurement
+         */
+        pDfs->channelMap[numChans].rptMap = initialMap;
+    }
+
+    /*
+     * If we have an established channel map, include it and return
+     *   a valid DFS element
+     */
+    if (numChans) {
+        PRINTM(INFO, "11h: Added %d channels to IBSS DFS Map\n", numChans);
+
+        pDfs->elementId = IBSS_DFS;
+        pDfs->len =
+            (sizeof(pDfs->dfsOwner) + sizeof(pDfs->dfsRecoveryInterval)
+             + numChans * sizeof(IEEEtypes_ChannelMap_t));
+
+        return (pDfs->len + sizeof(pDfs->len) + sizeof(pDfs->elementId));
+    }
+
+    /* Ensure the element is zeroed out for an invalid return */
+    memset(pDfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
+
+    return 0;
+}
+
+/**
+ *  @brief Setup and return a Quiet element used in the start of an adhoc
+ *         network.
+ *
+ *  11h only allows the creator of an adhoc network, or the AP
+ *    in infrastructure mode, to specify quiet intervals.
+ *
+ *  @param pQuiet Output parameter: Pointer to the Quite Element setup
+ *                by this function.
+ *
+ *  @return
+ *     - Length of the returned element in pQuiet output parameter
+ *     - 0 if returned element is not setup
+ */
+static int
+wlan_11h_set_quiet_ie(IEEEtypes_Quiet_t * pQuiet)
+{
+    int retLen = 0;
+
+    /*
+     * Leave the Quiet element blank for now.  No current requirements
+     *   for its use and its use affects available bandwidth.
+     *
+     * Included to reserve space in the driver/FW interface and adhoc start
+     *   routines for its later usage.
+     */
+    memset(pQuiet, 0x00, sizeof(IEEEtypes_Quiet_t));
+
+#if WLAN_11H_ADD_QUIET_ELEMENT
+    /* Setup a quiet element for testing/demonstration purposes only */
+    pQuiet->elementId = QUIET;
+    pQuiet->len = (sizeof(pQuiet->quietCount) + sizeof(pQuiet->quietPeriod)
+                   + sizeof(pQuiet->quietDuration)
+                   + sizeof(pQuiet->quietOffset));
+
+    pQuiet->quietCount = 100;
+    pQuiet->quietPeriod = 200;
+    pQuiet->quietDuration = wlan_cpu_to_le16(50);
+    pQuiet->quietOffset = wlan_cpu_to_le16(50);
+
+    retLen = (pQuiet->len + sizeof(pQuiet->len) + sizeof(pQuiet->elementId));
+#endif
+
+    return retLen;
+}
+
+/**
+ *  @brief Setup the Supported Channel IE sent in association requests
+ *
+ *  The Supported Channels IE is requird to be sent when the spectrum
+ *    management capability (11h) is enabled.  The element contains a
+ *    starting channel and number of channels tuple for each subband
+ *    the STA supports.  This information is based on the operating region.
+ *
+ *  @param priv     Private driver information structure
+ *  @param pSupChan Output parameter: Pointer to the Supported Chan element
+ *                  setup by thsi function.
+ *
+ *  @return
+ *    - Length of the returned element in pSupChan output parameter
+ *    - 0 if returned element is not setup
+ */
+static int
+wlan_11h_set_supp_channels_ie(wlan_private * priv,
+                              IEEEtypes_SupportedChannels_t * pSupChan)
+{
+    int numSubbands = 0;
+    int retLen = 0;
+
+    memset(pSupChan, 0x00, sizeof(IEEEtypes_SupportedChannels_t));
+
+    /*
+     * Set the supported channel elements based on the region code,
+     *   incrementing numSubbands for each subband we append to the
+     *   element.
+     */
+    switch (priv->adapter->RegionCode) {
+    case 0x10:                 /* USA FCC  */
+    case 0x20:                 /* Canada IC    */
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_lower_band;
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_middle_band;
+#ifdef FCC_DFS_APPROVAL
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_mid_upper_band;
+#endif
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_upper_band;
+        break;
+    case 0x30:                 /* Europe ETSI  */
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_lower_band;
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_middle_band;
+        pSupChan->subband[numSubbands++] = wlan_11h_unii_mid_upper_band;
+        break;
+    default:
+        break;
+    }
+
+    /*
+     * If we have setup any supported subbands in the element, return a
+     *    valid IE along with its size, else return 0.
+     */
+    if (numSubbands) {
+        pSupChan->elementId = SUPPORTED_CHANNELS;
+        pSupChan->len = numSubbands * sizeof(IEEEtypes_SupportChan_Subband_t);
+
+        retLen = (pSupChan->len
+                  + sizeof(pSupChan->len) + sizeof(pSupChan->elementId));
+
+        HEXDUMP("11h: SupChan", (u8 *) pSupChan, retLen);
+    }
+
+    return retLen;
+}
+
+/**
+ *  @brief Prepare CMD_802_11_TPC_ADAPT_REQ firmware command
+ *
+ *  @param priv     Private driver information structure
+ *  @param pCmdPtr  Output parameter: Pointer to the command being prepared
+ *                  for the firmware
+ *  @param pInfoBuf HostCmd_DS_802_11_TPC_ADAPT_REQ passed as void data block
+ *
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_cmd_tpc_request(wlan_private * priv,
+                         HostCmd_DS_COMMAND * pCmdPtr, const void *pInfoBuf)
+{
+    ENTER();
+
+    memcpy(&pCmdPtr->params.tpcReq, pInfoBuf,
+           sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+
+    pCmdPtr->params.tpcReq.req.timeout =
+        wlan_cpu_to_le16(pCmdPtr->params.tpcReq.req.timeout);
+
+    /* Converted to little endian in wlan_11h_cmd_process */
+    pCmdPtr->Size = sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ) + S_DS_GEN;
+
+    HEXDUMP("11h: 11_TPC_ADAPT_REQ:", (u8 *) pCmdPtr, (int) pCmdPtr->Size);
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Prepare CMD_802_11_TPC_INFO firmware command
+ *
+ *  @param priv     Private driver information structure
+ *  @param pCmdPtr  Output parameter: Pointer to the command being prepared 
+ *                  for the firmware
+ *  @param pInfoBuf wlan_11h_tpc_info_param_t passed as void data block
+ *
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_cmd_tpc_info(wlan_private * priv,
+                      HostCmd_DS_COMMAND * pCmdPtr, const void *pInfoBuf)
+{
+    HostCmd_DS_802_11_TPC_INFO *pTpcInfo = &pCmdPtr->params.tpcInfo;
+    MrvlIEtypes_LocalPowerConstraint_t *pConstraint =
+        &pTpcInfo->localConstraint;
+    MrvlIEtypes_PowerCapability_t *pCap = &pTpcInfo->powerCap;
+
+    wlan_11h_state_t *pState = &priv->adapter->state11h;
+    const wlan_11h_tpc_info_param_t *pTpcInfoParam = pInfoBuf;
+
+    ENTER();
+
+    pCap->MinPower = pState->minTxPowerCapability;
+    pCap->MaxPower = pState->maxTxPowerCapability;
+    pCap->Header.Len = wlan_cpu_to_le16(2);
+    pCap->Header.Type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
+
+    pConstraint->Chan = pTpcInfoParam->Chan;
+    pConstraint->Constraint = pTpcInfoParam->PowerConstraint;
+    pConstraint->Header.Type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
+    pConstraint->Header.Len = wlan_cpu_to_le16(2);
+
+    /* Converted to little endian in wlan_11h_cmd_process */
+    pCmdPtr->Size = sizeof(HostCmd_DS_802_11_TPC_INFO) + S_DS_GEN;
+
+    HEXDUMP("11h: TPC INFO", (u8 *) pCmdPtr, (int) pCmdPtr->Size);
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief  Prepare CMD_802_11_CHAN_SW_ANN firmware command
+ *
+ *  @param priv     Private driver information structure
+ *  @param pCmdPtr  Output parameter: Pointer to the command being 
+ *                  prepared to for firmware
+ *  @param pInfoBuf HostCmd_DS_802_11_CHAN_SW_ANN passed as void data block
+ *
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_cmd_chan_sw_ann(wlan_private * priv,
+                         HostCmd_DS_COMMAND * pCmdPtr, const void *pInfoBuf)
+{
+    const HostCmd_DS_802_11_CHAN_SW_ANN *pChSwAnn = pInfoBuf;
+
+    ENTER();
+
+    /* Converted to little endian in wlan_11h_cmd_process */
+    pCmdPtr->Size = sizeof(HostCmd_DS_802_11_CHAN_SW_ANN) + S_DS_GEN;
+
+    memcpy(&pCmdPtr->params.chan_sw_ann, pChSwAnn,
+           sizeof(HostCmd_DS_802_11_CHAN_SW_ANN));
+
+    PRINTM(INFO, "11h: ChSwAnn: %#x-%u, Seq=%u, Ret=%u\n",
+           pCmdPtr->Command, pCmdPtr->Size, pCmdPtr->SeqNum, pCmdPtr->Result);
+    PRINTM(INFO, "11h: ChSwAnn: Ch=%d, Cnt=%d, Mode=%d\n",
+           pChSwAnn->newChan, pChSwAnn->switchCount, pChSwAnn->switchMode);
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Set the local power constraint in the firmware
+ *
+ *  Construct and send a CMD_802_11_TPC_INFO command with the local power
+ *    constraint.
+ *
+ *  @param priv            Private driver information structure
+ *  @param channel         Channel to which the power constraint applies
+ *  @param powerConstraint Power constraint to be applied on the channel
+ *
+ *  @return                WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_11h_set_local_power_constraint(wlan_private * priv,
+                                    u8 channel, u8 powerConstraint)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    wlan_11h_tpc_info_param_t tpcInfoParam;
+
+    tpcInfoParam.Chan = channel;
+    tpcInfoParam.PowerConstraint = powerConstraint;
+
+    PRINTM(INFO, "11h: Set Local Constraint = %d\n",
+           tpcInfoParam.PowerConstraint);
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_TPC_INFO,
+                           HostCmd_ACT_GEN_SET, 0, 0, &tpcInfoParam);
+
+    if (ret) {
+        PRINTM(INFO, "11h: Err: Send TPC_INFO CMD: %d\n", ret);
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief  Utility function to process a join to an infrastructure BSS
+ *
+ *  @param priv        Private driver information structure
+ *  @param ppBuffer    Output parameter: Pointer to the TLV output buffer,
+ *                     modified on return to point after the appended 11h TLVs
+ *  @param channel     Channel on which we are joining the BSS
+ *  @param p11hBssInfo Pointer to the 11h BSS information for this network
+ *                     that was parsed out of the scan response.
+ *
+ *  @return            Integer number of bytes appended to the TLV output
+ *                     buffer (ppBuffer)
+ */
+static int
+wlan_11h_process_infra_join(wlan_private * priv,
+                            u8 ** ppBuffer,
+                            uint channel, wlan_11h_bss_info_t * p11hBssInfo)
+{
+    MrvlIEtypesHeader_t ieHeader;
+    IEEEtypes_SupportedChannels_t supChanIe;
+    int retLen = 0;
+    int supChanLen = 0;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    /* Set the local constraint configured in the firmware */
+    wlan_11h_set_local_power_constraint(priv, channel,
+                                        (p11hBssInfo->
+                                         powerConstraint.localConstraint));
+
+    /* Setup the Supported Channels IE */
+    supChanLen = wlan_11h_set_supp_channels_ie(priv, &supChanIe);
+
+    /*
+     * If we returned a valid Supported Channels IE, wrap and append it
+     */
+    if (supChanLen) {
+        /* Wrap the supported channels IE with a passthrough TLV type */
+        ieHeader.Type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+        ieHeader.Len = supChanLen;
+        memcpy(*ppBuffer, &ieHeader, sizeof(ieHeader));
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += sizeof(ieHeader);
+        retLen += sizeof(ieHeader);
+
+        /* Copy the supported channels IE to the output buf, advance pointer */
+        memcpy(*ppBuffer, &supChanIe, supChanLen);
+        *ppBuffer += supChanLen;
+        retLen += supChanLen;
+    }
+
+    return retLen;
+}
+
+/**
+ *  @brief Utility function to process a start or join to an adhoc network
+ *
+ *  Add the elements to the TLV buffer needed in the start/join adhoc commands:
+ *       - IBSS DFS IE
+ *       - Quiet IE
+ *
+ *  Also send the local constraint to the firmware in a TPC_INFO command.
+ *
+ *  @param priv        Private driver information structure
+ *  @param ppBuffer    Output parameter: Pointer to the TLV output buffer,
+ *                     modified on return to point after the appended 11h TLVs
+ *  @param channel     Channel on which we are starting/joining the IBSS
+ *  @param p11hBssInfo Pointer to the 11h BSS information for this network
+ *                     that was parsed out of the scan response.  NULL
+ *                     indicates we are starting the adhoc network
+ *
+ *  @return            Integer number of bytes appended to the TLV output
+ *                     buffer (ppBuffer)
+ */
+static int
+wlan_11h_process_adhoc(wlan_private * priv,
+                       u8 ** ppBuffer,
+                       uint channel, wlan_11h_bss_info_t * p11hBssInfo)
+{
+    IEEEtypes_IBSS_DFS_t dfsElem;
+    IEEEtypes_Quiet_t quietElem;
+    int sizeAppended;
+    int retLen = 0;
+    s8 localConstraint;
+
+    /* Format our own IBSS DFS Element.  Include our channel map fields */
+    wlan_11h_set_ibss_dfs_ie(priv, &dfsElem);
+
+    if (p11hBssInfo) {
+        /*
+         * Copy the DFS Owner/Recovery Interval from the BSS we are joining
+         */
+        memcpy(dfsElem.dfsOwner,
+               p11hBssInfo->ibssDfs.dfsOwner, sizeof(dfsElem.dfsOwner));
+        dfsElem.dfsRecoveryInterval =
+            p11hBssInfo->ibssDfs.dfsRecoveryInterval;
+    }
+
+    /* Append the dfs element to the TLV buffer */
+    sizeAppended = wlan_11h_convert_ieee_to_mrvl_ie(*ppBuffer,
+                                                    (u8 *) & dfsElem);
+
+    HEXDUMP("11h: IBSS-DFS", (void *) *ppBuffer, sizeAppended);
+    *ppBuffer += sizeAppended;
+    retLen += sizeAppended;
+
+    /*
+     * Check to see if we are joining a network.  Join is indicated by the
+     *   BSS Info pointer being valid (not NULL)
+     */
+    if (p11hBssInfo) {
+        /*
+         * If there was a quiet element, include it in adhoc join command
+         */
+        if (p11hBssInfo->quiet.elementId == QUIET) {
+            sizeAppended
+                = wlan_11h_convert_ieee_to_mrvl_ie(*ppBuffer,
+                                                   (u8 *) & p11hBssInfo->
+                                                   quiet);
+            HEXDUMP("11h: Quiet", (void *) *ppBuffer, sizeAppended);
+            *ppBuffer += sizeAppended;
+            retLen += sizeAppended;
+        }
+
+        /* Copy the local constraint from the network */
+        localConstraint = p11hBssInfo->powerConstraint.localConstraint;
+    } else {
+        /*
+         * If we are the adhoc starter, we can add a quiet element
+         */
+        wlan_11h_set_quiet_ie(&quietElem);
+        sizeAppended = wlan_11h_convert_ieee_to_mrvl_ie(*ppBuffer,
+                                                        (u8 *) & quietElem);
+        HEXDUMP("11h: Quiet", (void *) *ppBuffer, sizeAppended);
+        *ppBuffer += sizeAppended;
+        retLen += sizeAppended;
+
+        /* Use the localConstraint configured in the driver state */
+        localConstraint = priv->adapter->state11h.usrDefPowerConstraint;
+    }
+
+    /* Set the local constraint configured in the firmware */
+    wlan_11h_set_local_power_constraint(priv, channel, localConstraint);
+
+    return retLen;
+}
+
+/**
+ *  @brief Return whether the driver is currently setup to use 11h for
+ *         adhoc start.
+ *
+ *  Association/Join commands are dyanmic in that they enable 11h in the
+ *    driver/firmware when they are detected in the existing BSS.
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return
+ *    - TRUE if 11h is enabled
+ *    - FALSE otherwise
+ */
+static int
+wlan_11h_is_enabled(wlan_private * priv)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+
+    return (pState11h->is11hEnabled ? TRUE : FALSE);
+}
+
+/**
+ *  @brief Query 11h firmware enabled state.
+ *
+ *  Return whether the firmware currently has 11h extensions enabled
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return
+ *    - TRUE if 11h has been activated in the firmware
+ *    - FALSE otherwise
+ *
+ *  @sa wlan_11h_activate
+ */
+int
+wlan_11h_is_active(wlan_private * priv)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+
+    return (pState11h->is11hActive ? TRUE : FALSE);
+}
+
+/**
+ *  @brief Query 11h driver tx enable/disable state at the driver/application
+ *         layer
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return
+ *    - TRUE if 11h has disabled the transmit interface
+ *    - FALSE otherwise
+ */
+int
+wlan_11h_is_tx_disabled(wlan_private * priv)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+
+    return (pState11h->txDisabled);
+}
+
+/**
+ *  @brief Disable the transmit interface and record the state.
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return      void
+ */
+void
+wlan_11h_tx_disable(wlan_private * priv)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+
+    pState11h->txDisabled = TRUE;
+
+    os_carrier_off(priv);
+}
+
+/**
+ *  @brief Enable the transmit interface and record the state.
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return      void
+ */
+void
+wlan_11h_tx_enable(wlan_private * priv)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+
+    os_carrier_on(priv);
+
+    pState11h->txDisabled = FALSE;
+}
+
+/**
+ *  @brief Enable or Disable the 11h extensions in the firmware
+ *
+ *  @param priv  Private driver information structure
+ *  @param flag  Enable 11h if TRUE, disable otherwise
+ *
+ *  @return      WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_11h_activate(wlan_private * priv, int flag)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+    int enable = flag ? 1 : 0;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    /*
+     * Send cmd to FW to enable/disable 11h function in firmware
+     */
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_SNMP_MIB,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, Dot11H_i, &enable);
+
+    if (ret) {
+        ret = WLAN_STATUS_FAILURE;
+    } else {
+        /* Set boolean flag in driver 11h state */
+        pState11h->is11hActive = flag;
+    }
+
+    PRINTM(INFO, "11h: %s\n", enable ? "Activate" : "Deactivate");
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *
+ *  @brief Initialize the 11h parameters and enable 11h when starting an IBSS
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return      void
+ */
+void
+wlan_11h_init(wlan_private * priv)
+{
+    wlan_11h_state_t *pState11h = &priv->adapter->state11h;
+
+    ENTER();
+
+    pState11h->usrDefPowerConstraint = WLAN_11H_TPC_POWERCONSTRAINT;
+    pState11h->minTxPowerCapability = WLAN_11H_TPC_POWERCAPABILITY_MIN;
+    pState11h->maxTxPowerCapability = WLAN_11H_TPC_POWERCAPABILITY_MAX;
+
+    /*
+     * By default, the driver should have its preference set as 11h being
+     *    activated when starting an ad hoc network.  For infrastructre
+     *    and ad hoc join, 11h will be sensed and activated accordingly.
+     */
+    pState11h->is11hEnabled = TRUE;
+
+    /*
+     * On power up, the firmware should have 11h support inactive.
+     */
+    pState11h->is11hActive = FALSE;
+
+    LEAVE();
+}
+
+/**
+ *  @brief Retrieve a randomly selected starting channel if needed for 11h
+ *
+ *  If 11h is enabled enabled and an A-Band channel start band preference
+ *    configured in the driver, the start channel must be random in order
+ *    to meet with
+ *
+ *  @param priv  Private driver information structure
+ *
+ *  @return      Integer starting channel
+ */
+int
+wlan_11h_get_adhoc_start_channel(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    unsigned int startChn;
+    int region;
+    int randEntry;
+    REGION_CHANNEL *chnTbl;
+
+    ENTER();
+
+    /*
+     * Set startChn to the Default.  Used if 11h is disabled or the band
+     *   does not require 11h support.
+     */
+    startChn = DEFAULT_AD_HOC_CHANNEL;
+
+    /*
+     * Check that we are looking for a channel in the A Band
+     */
+    if (Adapter->adhoc_start_band == BAND_A) {
+        /*
+         * Set default to the A Band default. Used if random selection fails
+         *   or if 11h is not enabled
+         */
+        startChn = DEFAULT_AD_HOC_CHANNEL_A;
+
+        /*
+         * Check that 11h is enabled in the driver
+         */
+        if (wlan_11h_is_enabled(priv)) {
+            /*
+             * Search the region_channel tables for a channel table
+             *   that is marked for the A Band.
+             */
+            for (region = 0; (region < MAX_REGION_CHANNEL_NUM); region++) {
+                chnTbl = Adapter->region_channel + region;
+
+                /* Check if table is valid and marked for A Band */
+                if (chnTbl->Valid
+                    && chnTbl->Region == Adapter->RegionCode
+                    && chnTbl->Band & BAND_A) {
+                    /*
+                     * Set the start channel.  Get a random number and
+                     *   use it to pick an entry in the table between 0
+                     *   and the number of channels in the table (NrCFP).
+                     */
+                    randEntry = wlan_11h_get_random_num() % chnTbl->NrCFP;
+                    startChn = chnTbl->CFP[randEntry].Channel;
+                }
+            }
+        }
+    }
+
+    PRINTM(INFO, "11h: %s: AdHoc Channel set to %u\n",
+           wlan_11h_is_enabled(priv) ? "Enabled" : "Disabled", startChn);
+
+    LEAVE();
+
+    return startChn;
+}
+
+/**
+ *  @brief Check if the current region's regulations require the input channel
+ *         to be scanned for radar.
+ *
+ *  Based on staticly defined requirements for sub-bands per regulatory
+ *    agency requirements.
+ *
+ *  Used in adhoc start to determine if channel availabiilty check is required
+ *
+ *  @param priv    Private driver information structure
+ *  @param channel Channel to determine radar detection requirements
+ *
+ *  @return
+ *    - TRUE if radar detection is required
+ *    - FALSE otherwise
+ *
+ *  @sa wlan_11h_radar_detected
+ */
+int
+wlan_11h_radar_detect_required(wlan_private * priv, u8 channel)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int required;
+
+    /*
+     * Assume that radar detection is required unless exempted below.
+     *   No checks for 11h or measurement code  being enabled is placed here
+     *   since regulatory requirements exist whether we support them or not.
+     */
+    required = TRUE;
+
+    switch (priv->adapter->RegionCode) {
+    case 0x10:                 /* USA FCC  */
+    case 0x20:                 /* Canada IC    */
+#ifndef FCC_DFS_APPROVAL
+        /*
+         * FCC does not yet require radar detection in the
+         *   5.25-5.35 (U-NII middle) band
+         */
+        if (channel >= wlan_11h_unii_middle_band.startChan &&
+            channel < wlan_11h_unii_mid_upper_band.startChan) {
+            required = FALSE;
+        }
+
+        /*
+         * Fall through to check other bands
+         */
+#endif
+    case 0x30:                 /* Europe ETSI  */
+        /*
+         * Radar detection is not required in the
+         *   5.15-5.25 (U-NII lower) and 5.725-5.825 (U-NII upper) bands
+         */
+        if (channel < wlan_11h_unii_middle_band.startChan ||
+            channel >= wlan_11h_unii_upper_band.startChan) {
+            /* Radar detection not required */
+            required = FALSE;
+        }
+        break;
+    default:
+        break;
+    }
+
+    PRINTM(INFO, "11h: Radar detection in region %#02x "
+           "is %srequired for channel %d\n",
+           priv->adapter->RegionCode, (required ? "" : "NOT "), channel);
+
+    if (required == TRUE
+        && Adapter->MediaConnectStatus == WlanMediaStateConnected
+        && Adapter->CurBssParams.BSSDescriptor.Channel == channel) {
+        required = FALSE;
+
+        PRINTM(INFO, "11h: Radar detection not required. "
+               "Already operating on the channel");
+    }
+
+    return required;
+}
+
+/**
+ *  @brief Perform a radar measuremnt and report the result if required on
+ *         given channel
+ *
+ *  Check to see if the provided channel requires a channel availability
+ *    check (60 second radar detection measurement).  If required, perform
+ *    measurement, stalling calling thread until the measurement completes
+ *    and then report result.
+ *
+ *  Used when starting an adhoc network.
+ *
+ *  @param priv    Private driver information structure
+ *  @param channel Channel on which to perform radar measurement
+ *
+ *  @return
+ *    - TRUE if radar has been detected
+ *    - FALSE if radar detection is not required or radar has not been detected
+ *
+ *  @sa wlan_11h_radar_detect_required
+ */
+int
+wlan_11h_radar_detected(wlan_private * priv, u8 channel)
+{
+    int ret;
+
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_MEASUREMENT_REQUEST measReq;
+    HostCmd_DS_MEASUREMENT_REPORT measRpt;
+
+    /*
+     * If the channel requires radar, default the return value to it being
+     *   detected.
+     */
+    ret = wlan_11h_radar_detect_required(priv, channel);
+
+    memset(&measReq, 0x00, sizeof(measReq));
+    memset(&measRpt, 0x00, sizeof(measRpt));
+
+    /*
+     * Send a basic measurement request on the indicated channel for the
+     *   required channel availability check time.
+     */
+    measReq.measType = WLAN_MEAS_BASIC;
+    measReq.req.basic.channel = channel;
+    measReq.req.basic.duration = WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION;
+
+    /*
+     * Set the STA that we are requesting the measurement from to our own
+     *   mac address, causing our firmware to perform the measurement itself
+     */
+    memcpy(measReq.macAddr, Adapter->CurrentAddr, sizeof(measReq.macAddr));
+
+    /*
+     * Send the measurement request and timeout duration to wait for
+     *   the command to pend until the measurement report is received
+     *   from the firmware.  If the command fails, the default ret value set
+     *   above will be returned.
+     */
+    if (wlan_meas_util_send_req(priv, &measReq,
+                                measReq.req.basic.duration, &measRpt) == 0) {
+        /*
+         * If the report indicates no measurement was done, leave the default
+         *   return value alone.
+         */
+        if (measRpt.rpt.basic.map.unmeasured == 0) {
+            /*
+             * Set the return value based on the radar indication bit
+             */
+            ret = measRpt.rpt.basic.map.radar ? TRUE : FALSE;
+        }
+    }
+    return ret;
+}
+
+/**
+ *  @brief Process an TLV buffer for a pending BSS Adhoc start command.
+ *
+ *  Activate 11h functionality in the firmware if driver has is enabled
+ *    for 11h (configured by the application via IOCTL).
+ *
+ *  @param priv        Private driver information structure
+ *  @param ppBuffer    Output parameter: Pointer to the TLV output buffer, 
+ *                     modified on return to point after the appended 11h TLVs
+ *  @param pCapInfo    Pointer to the capability info for the BSS to join
+ *  @param channel     Channel on which we are starting the IBSS
+ *  @param p11hBssInfo Input/Output parameter: Pointer to the 11h BSS 
+ *                     information for this network that we are establishing.
+ *                     11h sensed flag set on output if warranted.
+ *
+ *  @return            Integer number of bytes appended to the TLV output
+ *                     buffer (ppBuffer)
+ *
+ */
+int
+wlan_11h_process_start(wlan_private * priv,
+                       u8 ** ppBuffer,
+                       IEEEtypes_CapInfo_t * pCapInfo,
+                       uint channel, wlan_11h_bss_info_t * p11hBssInfo)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = 0;
+
+    if (wlan_11h_is_enabled(priv) && (Adapter->adhoc_start_band == BAND_A)) {
+        if (wlan_get_state_11d(priv) == DISABLE_11D) {
+            /* No use having 11h enabled without 11d enabled */
+            wlan_enable_11d(priv, ENABLE_11D);
+            wlan_create_dnld_countryinfo_11d(priv);
+        }
+
+        /* Activate 11h functions in firmware, turns on capability bit */
+        wlan_11h_activate(priv, TRUE);
+        pCapInfo->SpectrumMgmt = 1;
+
+        /* Set flag indicating this BSS we are starting is using 11h */
+        p11hBssInfo->sensed11h = TRUE;
+
+        ret = wlan_11h_process_adhoc(priv, ppBuffer, channel, NULL);
+    } else {
+        /* Deactivate 11h functions in the firmware */
+        wlan_11h_activate(priv, FALSE);
+        pCapInfo->SpectrumMgmt = 0;
+    }
+
+    return ret;
+}
+
+/**
+ *  @brief Process an TLV buffer for a pending BSS Join command for
+ *         both adhoc and infra networks
+ *
+ *  The TLV command processing for a BSS join for either adhoc or
+ *    infrastructure network is performed with this function.  The
+ *    capability bits are inspected for the IBSS flag and the appropriate
+ *    local routines are called to setup the necessary TLVs.
+ *
+ *  Activate 11h functionality in the firmware if the spectrum management
+ *    capability bit is found in the network infromation for the BSS we are
+ *    joining.
+ *
+ *  @param priv        Private driver information structure
+ *  @param ppBuffer    Output parameter: Pointer to the TLV output buffer, 
+ *                     modified on return to point after the appended 11h TLVs
+ *  @param pCapInfo    Pointer to the capability info for the BSS to join
+ *  @param channel     Channel on which we are joining the BSS
+ *  @param p11hBssInfo Pointer to the 11h BSS information for this
+ *                     network that was parsed out of the scan response.
+ *
+ *  @return            Integer number of bytes appended to the TLV output
+ *                     buffer (ppBuffer), WLAN_STATUS_FAILURE (-1), 
+ *                     or WLAN_STATUS_SUCCESS (0)
+ */
+int
+wlan_11h_process_join(wlan_private * priv,
+                      u8 ** ppBuffer,
+                      IEEEtypes_CapInfo_t * pCapInfo,
+                      uint channel, wlan_11h_bss_info_t * p11hBssInfo)
+{
+    int ret = 0;
+
+    ENTER();
+
+    if (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        if (wlan_11h_is_active(priv) == p11hBssInfo->sensed11h) {
+            /* Assume DFS parameters are the same for roaming as long as
+             *   the current & next APs have the same spectrum mgmt capability
+             *   bit setting
+             */
+            ret = WLAN_STATUS_SUCCESS;
+
+        } else {
+            /* No support for roaming between DFS/non-DFS yet */
+            ret = WLAN_STATUS_FAILURE;
+        }
+
+        LEAVE();
+        return ret;
+    }
+
+    if (p11hBssInfo->sensed11h) {
+        /* No use having 11h enabled without 11d enabled */
+        wlan_enable_11d(priv, ENABLE_11D);
+        wlan_parse_dnld_countryinfo_11d(priv);
+
+        /* Activate 11h functions in firmware, turns on capability bit */
+        wlan_11h_activate(priv, TRUE);
+        pCapInfo->SpectrumMgmt = 1;
+
+        if (pCapInfo->Ibss) {
+            PRINTM(INFO, "11h: Adhoc join: Sensed\n");
+            ret = wlan_11h_process_adhoc(priv, ppBuffer, channel,
+                                         p11hBssInfo);
+        } else {
+            PRINTM(INFO, "11h: Infra join: Sensed\n");
+            ret = wlan_11h_process_infra_join(priv, ppBuffer,
+                                              channel, p11hBssInfo);
+        }
+    } else {
+        /* Deactivate 11h functions in the firmware */
+        wlan_11h_activate(priv, FALSE);
+        pCapInfo->SpectrumMgmt = 0;
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *
+ *  @brief  Prepare the HostCmd_DS_Command structure for an 11h command.
+ *
+ *  Use the Command field to determine if the command being set up is for
+ *     11h and call one of the local command handlers accordingly for:
+ *
+ *        - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ *        - HostCmd_CMD_802_11_TPC_INFO
+ *        - HostCmd_CMD_802_11_CHAN_SW_ANN
+ *
+ *  @param priv     Private driver information structure
+ *  @param pCmdPtr  Output parameter: Pointer to the command being prepared 
+ *                  for the firmware
+ *  @param pInfoBuf Void buffer passthrough with data necessary for a
+ *                  specific command type
+ *
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ *  @sa wlan_11h_cmd_tpc_request
+ *  @sa wlan_11h_cmd_tpc_info
+ *  @sa wlan_11h_cmd_chan_sw_ann
+ */
+int
+wlan_11h_cmd_process(wlan_private * priv,
+                     HostCmd_DS_COMMAND * pCmdPtr, const void *pInfoBuf)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    switch (pCmdPtr->Command) {
+    case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+        ret = wlan_11h_cmd_tpc_request(priv, pCmdPtr, pInfoBuf);
+        break;
+    case HostCmd_CMD_802_11_TPC_INFO:
+        ret = wlan_11h_cmd_tpc_info(priv, pCmdPtr, pInfoBuf);
+        break;
+    case HostCmd_CMD_802_11_CHAN_SW_ANN:
+        ret = wlan_11h_cmd_chan_sw_ann(priv, pCmdPtr, pInfoBuf);
+        break;
+    default:
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    pCmdPtr->Command = wlan_cpu_to_le16(pCmdPtr->Command);
+    pCmdPtr->Size = wlan_cpu_to_le16(pCmdPtr->Size);
+
+    return ret;
+}
+
+/**
+ *  @brief Handle the command response from the firmware if from an 11h command
+ *
+ *  Use the Command field to determine if the command response being
+ *    is for 11h.  Call the local command response handler accordingly for:
+ *
+ *        - HostCmd_CMD_802_11_TPC_ADAPT_REQ
+ *        - HostCmd_CMD_802_11_TPC_INFO
+ *        - HostCmd_CMD_802_11_CHAN_SW_ANN
+ *
+ *  @param priv  Private driver information structure
+ *  @param resp  HostCmd_DS_COMMAND struct returned from the firmware
+ *               command
+ *
+ *  @return      WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_11h_cmdresp_process(wlan_private * priv, const HostCmd_DS_COMMAND * resp)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    switch (resp->Command) {
+    case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+        HEXDUMP("11h: TPC REQUEST Rsp:", (u8 *) resp, (int) resp->Size);
+        memcpy(priv->adapter->CurCmd->pdata_buf,
+               &resp->params.tpcReq, sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
+        break;
+
+    case HostCmd_CMD_802_11_TPC_INFO:
+        HEXDUMP("11h: TPC INFO Rsp Data:", (u8 *) resp, (int) resp->Size);
+        break;
+
+    case HostCmd_CMD_802_11_CHAN_SW_ANN:
+        PRINTM(INFO, "11h: Ret ChSwAnn: Sz=%u, Seq=%u, Ret=%u\n",
+               resp->Size, resp->SeqNum, resp->Result);
+        break;
+
+    default:
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    return ret;
+}
+
+/**
+ *  @brief Process an element from a scan response, copy relevant info for 11h
+ *
+ *  @param p11hBssInfo  Output parameter: Pointer to the 11h BSS information
+ *                      for the network that is being processed
+ *  @param pElement     Pointer to the current IE we are inspecting for 11h
+ *                      relevance
+ *
+ *  @return             WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_11h_process_bss_elem(wlan_11h_bss_info_t * p11hBssInfo,
+                          const u8 * pElement)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    switch (*pElement) {
+    case POWER_CONSTRAINT:
+        PRINTM(INFO, "11h: Power Constraint IE Found\n");
+        p11hBssInfo->sensed11h = 1;
+        memcpy(&p11hBssInfo->powerConstraint, pElement,
+               sizeof(IEEEtypes_PowerConstraint_t));
+        break;
+
+    case POWER_CAPABILITY:
+        PRINTM(INFO, "11h: Power Capability IE Found\n");
+        p11hBssInfo->sensed11h = 1;
+        memcpy(&p11hBssInfo->powerCapability, pElement,
+               sizeof(IEEEtypes_PowerCapability_t));
+        break;
+
+    case TPC_REPORT:
+        PRINTM(INFO, "11h: Tpc Report IE Found\n");
+        p11hBssInfo->sensed11h = 1;
+        memcpy(&p11hBssInfo->tpcReport, pElement,
+               sizeof(IEEEtypes_TPCReport_t));
+        break;
+
+    case CHANNEL_SWITCH_ANN:
+        p11hBssInfo->sensed11h = 1;
+        PRINTM(INFO, "11h: Channel Switch Ann IE Found\n");
+        break;
+
+    case QUIET:
+        PRINTM(INFO, "11h: Quiet IE Found\n");
+        p11hBssInfo->sensed11h = 1;
+        memcpy(&p11hBssInfo->quiet, pElement, sizeof(IEEEtypes_Quiet_t));
+        break;
+
+    case IBSS_DFS:
+        PRINTM(INFO, "11h: Ibss Dfs IE Found\n");
+        p11hBssInfo->sensed11h = 1;
+        memcpy(&p11hBssInfo->ibssDfs, pElement, sizeof(IEEEtypes_IBSS_DFS_t));
+        break;
+
+    case SUPPORTED_CHANNELS:
+    case TPC_REQUEST:
+        /*
+         * These elements are not in beacons/probe responses.  Included here
+         *   to cover set of enumerated 11h elements.
+         */
+        break;
+
+    default:
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    return ret;
+}
+
+/**
+ *  @brief IOCTL handler to send a channel switch announcment via
+ *         firmware command
+ *
+ *  @param priv  Private driver information structure
+ *  @param wrq   OS IOCTL passed structure encoded with a 
+ *               HostCmd_DS_802_11_CHAN_SW_ANN structure
+ *
+ *  @return
+ *    - 0 for success
+ *    - -EPROTO if 11h is not active in the firmware
+ *    - -EFAULT if memory copy from user space
+ *    - Error return from wlan_prepare_cmd routine otherwise
+ *             
+ */
+int
+wlan_11h_ioctl_chan_sw_ann(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_802_11_CHAN_SW_ANN chSwParams;
+    int ret;
+
+    ENTER();
+
+    if (!wlan_11h_is_active(priv)) {
+        ret = -EPROTO;
+    } else if (copy_from_user(&chSwParams, wrq->u.data.pointer,
+                              sizeof(chSwParams)) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "11h: ioctl_chan_sw_ann: copy from user failed\n");
+        ret = -EFAULT;
+    } else {
+        /*
+         * Send the channel switch announcment to firmware
+         */
+
+        ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_CHAN_SW_ANN,
+                               HostCmd_ACT_GEN_SET,
+                               0, 0, (void *) &chSwParams);
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief IOCTL handler to return the user defined local power constraint
+ *
+ *  @param priv Private driver information structure
+ *  @param wrq  Input/Output parameter: OS IOCTL passed structure.  Used to set
+ *              the local power constraint if supplied on input.  Currently
+ *              defined local power constraint provided on output.
+ *
+ *  @return
+ *    - 0 for success in all cases
+ */
+int
+wlan_11h_ioctl_get_local_power(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    s8 *localpowerPtr = &priv->adapter->state11h.usrDefPowerConstraint;
+    int localpower;
+
+    ENTER();
+
+    if (wrq->u.data.length != 0) {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+        *localpowerPtr = (s8) data;
+    }
+
+    localpower = *localpowerPtr;
+    if (copy_to_user(wrq->u.data.pointer, &localpower, sizeof(int))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+
+    return 0;
+}
+
+/**
+ *  @brief IOCTL handler to send a TPC request to a given STA address.
+ *
+ *  @param priv Private driver information structure
+ *  @param wrq  Input/Output parmeter: OS IOCTL passed structure containing:
+ *                 - wlan_ioctl_11h_tpc_req on input
+ *                 - wlan_ioctl_11h_tpc_resp on output if successful
+ *
+ *  @return
+ *    - 0 for success
+ *    - -EPROTO if 11h is not active in the firmware
+ *    - -EFAULT if memory copy from user space 
+ *    - Error return from wlan_prepare_cmd routine otherwise
+ */
+int
+wlan_11h_ioctl_request_tpc(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_11h_tpc_req tpcIoctlReq;
+    wlan_ioctl_11h_tpc_resp tpcIoctlResp;
+    HostCmd_DS_802_11_TPC_ADAPT_REQ tpcReq;
+
+    int ret = 0;
+
+    ENTER();
+
+    if (!wlan_11h_is_active(priv)) {
+        ret = -EPROTO;
+    } else if (copy_from_user(&tpcIoctlReq, wrq->u.data.pointer,
+                              sizeof(tpcIoctlReq)) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "11h: ioctl_request_tpc: copy from user failed\n");
+        ret = -EFAULT;
+    } else {
+        PRINTM(INFO, "11h: ioctl_request_tpc req: "
+               "%02x:%02x:%02x:%02x:%02x:%02x, rateIdx(%d), timeout(%d)\n",
+               tpcIoctlReq.destMac[0], tpcIoctlReq.destMac[1],
+               tpcIoctlReq.destMac[2], tpcIoctlReq.destMac[3],
+               tpcIoctlReq.destMac[4], tpcIoctlReq.destMac[5],
+               tpcIoctlReq.rateIndex, tpcIoctlReq.timeout);
+
+        memset(&tpcReq, 0, sizeof(tpcReq));
+        memset(&tpcIoctlResp, 0, sizeof(tpcIoctlResp));
+
+        memcpy(tpcReq.req.destMac, tpcIoctlReq.destMac,
+               sizeof(tpcReq.req.destMac));
+        tpcReq.req.rateIndex = tpcIoctlReq.rateIndex;
+        tpcReq.req.timeout = tpcIoctlReq.timeout;
+
+        ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_TPC_ADAPT_REQ,
+                               HostCmd_ACT_GEN_SET,
+                               HostCmd_OPTION_WAITFORRSP, 0, &tpcReq);
+
+        if (ret == 0) {
+            tpcIoctlResp.statusCode = tpcReq.resp.tpcRetCode;
+            tpcIoctlResp.txPower = tpcReq.resp.txPower;
+            tpcIoctlResp.linkMargin = tpcReq.resp.linkMargin;
+            tpcIoctlResp.rssi = tpcReq.resp.rssi;
+
+            wrq->u.data.length = sizeof(tpcIoctlResp);
+            if (copy_to_user(wrq->u.data.pointer, &tpcIoctlResp,
+                             wrq->u.data.length)) {
+                PRINTM(INFO, "Copy to user failed\n");
+                return -EFAULT;
+            }
+
+            PRINTM(INFO, "11h: ioctl_request_tpc resp: "
+                   "Ret(%d), TxPwr(%d), LinkMrgn(%d), RSSI(%d)\n",
+                   tpcIoctlResp.statusCode,
+                   tpcIoctlResp.txPower,
+                   tpcIoctlResp.linkMargin, tpcIoctlResp.rssi);
+        }
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ * @brief IOCTL handler to set  min/max power in the 11h power capability IE
+ *
+ *  @param priv  Private driver information structure
+ *  @param wrq   OS IOCTL passed structure
+ *
+ *  @return
+ *    - 0 for success
+ *    - -EFAULT if memory copy from user space fails
+ */
+int
+wlan_11h_ioctl_set_power_cap(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_11h_power_cap powerCapIoctl;
+    int ret = 0;
+
+    ENTER();
+
+    if (copy_from_user(&powerCapIoctl, wrq->u.data.pointer,
+                       sizeof(powerCapIoctl)) == 0) {
+        Adapter->state11h.minTxPowerCapability = powerCapIoctl.minTxPower;
+        Adapter->state11h.maxTxPowerCapability = powerCapIoctl.maxTxPower;
+
+        PRINTM(INFO, "11h: ioctl_set_power_cap, Min(%d) MaxPwr(%d)\n",
+               Adapter->state11h.minTxPowerCapability,
+               Adapter->state11h.maxTxPowerCapability);
+    } else {
+        ret = -EFAULT;
+    }
+
+    LEAVE();
+
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11h.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11h.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_11h.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_11h.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,341 @@
+/** @file wlan_11h.h
+ *
+ *  @brief Interface for the 802.11h wlan_11h module implemented in wlan_11h.c
+ *
+ *  Driver interface functions and type declarations for the 11h module
+ *    implemented in wlan_11h.c.
+ *
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    9/30/05: Added DFS code, reorganized TPC code to match conventions
+
+ ************************************************************/
+
+#ifndef _WLAN_11H
+#define _WLAN_11H
+
+#include "wlan_meas.h"
+
+/*
+ *  #defines used in this header file
+ */
+
+//! Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure
+#define WLAN_11H_MAX_SUBBANDS  5
+
+//! Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t 
+#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25
+
+/*
+ *
+ *  IEEE type definitions
+ *
+ */
+
+//!  IEEE Power Constraint element (7.3.2.15)
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 32
+    u8 len;                     //!< Element length after id and len
+    u8 localConstraint;         //!< Local power constraint applied to 11d chan info
+} __ATTRIB_PACK__ IEEEtypes_PowerConstraint_t;
+
+//!  IEEE Power Capability element (7.3.2.16)
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 33                  
+    u8 len;                     //!< Element length after id and len
+    s8 minTxPowerCapability;    //!< Minimum Transmit power (dBm)
+    s8 maxTxPowerCapability;    //!< Maximum Transmit power (dBm)
+} __ATTRIB_PACK__ IEEEtypes_PowerCapability_t;
+
+//!  IEEE TPC Report element (7.3.2.18)
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 35
+    u8 len;                     //!< Element length after id and len
+    s8 txPower;                 //!< Max power used to transmit the TPC Report frame (dBm)
+    s8 linkmargin;              //!< Link margin when TPC Request received (dB)
+} __ATTRIB_PACK__ IEEEtypes_TPCReport_t;
+
+//!  IEEE Supported Channel sub-band description (7.3.2.19)
+/**  
+ *  Sub-band description used in the supported channels element. 
+ */
+typedef struct
+{
+    u8 startChan;               //!< Starting channel in the subband
+    u8 numChans;                //!< Number of channels in the subband
+
+} __ATTRIB_PACK__ IEEEtypes_SupportChan_Subband_t;
+
+//!  IEEE Supported Channel element (7.3.2.19)
+/**
+ *  Sent in association requests. Details the sub-bands and number
+ *    of channels supported in each subband
+ */
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 36
+    u8 len;                     //!< Element length after id and len
+
+    //! Configured sub-bands information in the element
+    IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS];
+
+} __ATTRIB_PACK__ IEEEtypes_SupportedChannels_t;
+
+//!  Channel Switch Announcment element (7.3.2.20)
+/**
+ *  Sent in action frames and in beacon and probe responses.  Indicates 
+ *    new channel, time until channel switch, and whether or not
+ *    transmissions are allowed while the switch is pending.
+ */
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 37
+    u8 len;                     //!< Element length after id and len
+    u8 channelSwitchMode;       //!< Mode: 1 indicates STA quiet during switch time
+    u8 newChannelNumber;        //!< New channel 
+    u8 channelSwitchCount;      //!< Nubmer of TBTTS until switch
+
+} __ATTRIB_PACK__ IEEEtypes_ChannelSwitchAnn_t;
+
+//!  IEEE Quiet Period Element (7.3.2.23)
+/**
+ *  Provided in beacons and probe responses.  Indicates times during 
+ *    which the STA should not be transmitting data.  Only starting STAs in
+ *    an IBSS and APs are allowed to originate a quiet element. 
+ */
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 40
+    u8 len;                     //!< Element length after id and len
+    u8 quietCount;              //!< Number of TBTTs until beacon with the quiet period
+    u8 quietPeriod;             //!< Regular quiet period, # of TBTTS between periods
+    u16 quietDuration;          //!< Duration of the quiet period in TUs
+    u16 quietOffset;            //!< Offset in TUs from the TBTT for the quiet period
+
+} __ATTRIB_PACK__ IEEEtypes_Quiet_t;
+
+//!  IEEE DFS Channel Map field (7.3.2.24)
+/**
+ *  Used to list supported channels and provide a octet "map" field which 
+ *    contains a basic measurement report for that channel in the 
+ *    IEEEtypes_IBSS_DFS_t element
+ */
+typedef struct
+{
+    u8 channelNumber;           //!< Channel number
+    MeasRptBasicMap_t rptMap;   //!< Basic measurement report for the channel
+
+} __ATTRIB_PACK__ IEEEtypes_ChannelMap_t;
+
+//!  IEEE IBSS DFS Element (7.3.2.24)
+/**
+ *  IBSS DFS element included in ad hoc beacons and probe responses.  
+ *    Provides information regarding the IBSS DFS Owner as well as the
+ *    originating STAs supported channels and basic measurement results.
+ */
+typedef struct
+{
+    u8 elementId;               //!< IEEE Element ID = 41
+    u8 len;                     //!< Element length after id and len
+    u8 dfsOwner[ETH_ALEN];      //!< DFS Owner STA Address
+    u8 dfsRecoveryInterval;     //!< DFS Recovery time in TBTTs
+
+    //! Variable length map field, one Map entry for each supported channel
+    IEEEtypes_ChannelMap_t channelMap[WLAN_11H_MAX_IBSS_DFS_CHANNELS];
+
+} __ATTRIB_PACK__ IEEEtypes_IBSS_DFS_t;
+
+/*
+ *
+ *  Marvell IE Type definitions
+ *
+ */
+
+/*
+ *  11h IOCTL structures
+ */
+
+//! WLAN_11H_REQUESTTPC IOCTL request data structure 
+/**
+ * Structure passed from the application layer to initiate a TPC request 
+ *    command via the firmware to a given STA address
+ */
+typedef struct
+{
+    u8 destMac[ETH_ALEN];       //!< Destination STA address        
+    u8 rateIndex;               //!< Response timeout in ms         
+    u16 timeout;                //!< IEEE Rate index to send request
+
+} __ATTRIB_PACK__ wlan_ioctl_11h_tpc_req;
+
+//! WLAN_11H_REQUESTTPC IOCTL response data structure 
+/**
+ * Structure passed from the driver to the application providing the 
+ *   results of the application initiated TPC Request
+ */
+typedef struct
+{
+    int statusCode;             //!< Firmware command result status code
+    int txPower;                //!< Reported TX Power from the TPC Report
+    int linkMargin;             //!< Reported Link margin from the TPC Report
+    int rssi;                   //!< RSSI of the received TPC Report frame
+
+} __ATTRIB_PACK__ wlan_ioctl_11h_tpc_resp;
+
+//! WLAN_11H_CHANSWANN IOCTL data structure 
+/**
+ * Structure passed from the application to the driver to initiate
+ *   a channel switch announcement in the firmware (include in beacons, send
+ *   action frame, switch own channel)
+ */
+typedef struct
+{
+    u8 switchMode;              //!< Set to 1 for a quiet switch request, no STA tx
+    u8 newChan;                 //!< Requested new channel
+    u8 switchCount;             //!< Number of TBTTs until the switch is to occur
+
+} __ATTRIB_PACK__ wlan_ioctl_11h_chan_sw_ann;
+
+//! WLAN_11H_POWERCAP IOCTL data structure 
+/**
+ * Structure passed from the application to the driver to set the internal
+ *   min/max TX Power capability settings in the driver.  These settings
+ *   are later passed to the firmware for use in association requests
+ */
+typedef struct
+{
+    s8 minTxPower;              //!< Minimum Tx Power capability
+    s8 maxTxPower;              //!< Maximum Tx Power capability
+
+} __ATTRIB_PACK__ wlan_ioctl_11h_power_cap;
+
+//! 802.11h BSS information kept for each BSSID received in scan results
+/**
+ * IEEE BSS information needed from scan results for later processing in
+ *    join commands 
+ */
+typedef struct
+{
+    u8 sensed11h;               //!< Capability bit set or 11h IE found in this BSS
+
+    IEEEtypes_PowerConstraint_t powerConstraint;        //!< Power Constraint IE
+    IEEEtypes_PowerCapability_t powerCapability;        //!< Power Capability IE
+    IEEEtypes_TPCReport_t tpcReport;    //!< TPC Report IE
+    IEEEtypes_Quiet_t quiet;    //!< Quiet IE
+    IEEEtypes_IBSS_DFS_t ibssDfs;       //!< IBSS DFS Element IE
+
+} wlan_11h_bss_info_t;
+
+//! 802.11h State information kept in the wlan_adapter class for the driver
+typedef struct
+{
+    int is11hEnabled;           //!< Enables/disables 11h in the driver (adhoc start)
+    int is11hActive;            //!< Indicates whether 11h is active in the firmware
+    int txDisabled;             //!< Set when driver receives a STOP TX event from fw
+
+    //! Minimum TX Power capability sent to FW for 11h use and fw power control
+    s8 minTxPowerCapability;
+
+    //! Maximum TX Power capability sent to FW for 11h use and fw power control
+    s8 maxTxPowerCapability;
+
+    //! User provisioned local power constraint sent in association requests
+    s8 usrDefPowerConstraint;
+
+} wlan_11h_state_t;
+
+/*
+**  11H APIs
+*/
+
+/* Initialize the 11h software module */
+extern void wlan_11h_init(wlan_private * priv);
+
+/* Return 1 if 11h is active in the firmware, 0 if it is inactive */
+extern int wlan_11h_is_active(wlan_private * priv);
+
+/* Activate 11h extensions in the firmware */
+extern int wlan_11h_activate(wlan_private * priv, int flag);
+
+/* Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_enable(wlan_private * priv);
+
+/* Enable the tx interface and record the new transmit state */
+extern void wlan_11h_tx_disable(wlan_private * priv);
+
+/* Return 1 if 11h has disabled the transmit intervace, 0 otherwise */
+extern int wlan_11h_is_tx_disabled(wlan_private * priv);
+
+/* Check if radar detection is required on the specified channel */
+extern int wlan_11h_radar_detect_required(wlan_private * priv, u8 channel);
+
+/* Perform a standard availibility check on the specified channel */
+extern int wlan_11h_radar_detected(wlan_private * priv, u8 channel);
+
+/* Get an initial random channel to start an adhoc network on */
+extern int wlan_11h_get_adhoc_start_channel(wlan_private * priv);
+
+/* Add any 11h TLVs necessary to complete a join command (adhoc or infra) */
+extern int wlan_11h_process_join(wlan_private * priv,
+                                 u8 ** ppBuffer,
+                                 IEEEtypes_CapInfo_t * pCapInfo,
+                                 uint channel,
+                                 wlan_11h_bss_info_t * p11hBssInfo);
+
+/* Add any 11h TLVs necessary to complete an adhoc start command */
+extern int wlan_11h_process_start(wlan_private * priv,
+                                  u8 ** ppBuffer,
+                                  IEEEtypes_CapInfo_t * pCapInfo,
+                                  uint channel,
+                                  wlan_11h_bss_info_t * p11hBssInfo);
+
+/* Receive IEs from scan processing and record any needed info for 11h */
+int wlan_11h_process_bss_elem(wlan_11h_bss_info_t * p11hBssInfo,
+                              const u8 * pElement);
+
+/* Complete the firmware command preparation for an 11h command function */
+extern int wlan_11h_cmd_process(wlan_private * priv,
+                                HostCmd_DS_COMMAND * pCmdPtr,
+                                const void *pInfoBuf);
+
+/* Process the response of an 11h firmware command */
+extern int wlan_11h_cmdresp_process(wlan_private * priv,
+                                    const HostCmd_DS_COMMAND * resp);
+
+/*
+ *  IOCTL declarations
+ */
+/* Send a channel switch announcment */
+extern int wlan_11h_ioctl_chan_sw_ann(wlan_private * priv, struct iwreq *wrq);
+
+/* Send a TPC request to a specific STA */
+extern int wlan_11h_ioctl_request_tpc(wlan_private * priv, struct iwreq *wrq);
+
+/* Set the power capabilities in the driver to be sent in 11h firmware cmds */
+extern int wlan_11h_ioctl_set_power_cap(wlan_private * priv,
+                                        struct iwreq *wrq);
+
+/* Get the local power constraint setting from the driver */
+extern int wlan_11h_ioctl_get_local_power(wlan_private * priv,
+                                          struct iwreq *wrq);
+
+#endif /*_WLAN_11H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_cmd.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_cmd.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_cmd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_cmd.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,2635 @@
+/** @file wlan_cmd.c
+  *  
+  * @brief This file contains the handling of command.
+  * it prepares command and sends it to firmware when
+  * it is ready.
+  * 
+  * (c) Copyright © 2003-2007, Marvell International Ltd.  
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+    10/04/05: Add Doxygen format comments
+    01/05/06: Add kernel 2.6.x support  
+    01/11/06: Conditionalize new scan/join structures
+    01/31/06: Add support to selectively enabe the FW Scan channel filter
+    02/16/06: Clear scan in progress flag when scan command failed and dropped
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+    04/18/06: Remove old Subscrive Event and add new Subscribe Event
+              implementation through generic hostcmd API
+    05/04/06: Add IBSS coalescing related new hostcmd handling	      
+    08/29/06: Add ledgpio private command
+********************************************************/
+
+#include	"wlan_headers.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+static u16 Commands_Allowed_In_PS[] = {
+    HostCmd_CMD_802_11_RSSI,
+    HostCmd_CMD_802_11_HOST_SLEEP_CFG,
+    HostCmd_CMD_802_11_WAKEUP_CONFIRM,
+};
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function checks if the commans is allowed
+ *  in PS mode not.
+ *  
+ *  @param Command the command ID
+ *  @return 	   TRUE or FALSE
+ */
+static BOOLEAN
+wlan_is_cmd_allowed_in_ps(u16 Command)
+{
+    int count = sizeof(Commands_Allowed_In_PS)
+        / sizeof(Commands_Allowed_In_PS[0]);
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (Command == wlan_cpu_to_le16(Commands_Allowed_In_PS[i]))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/** 
+ *  @brief This function prepares command of get_hw_spec.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param cmd	   A pointer to HostCmd_DS_COMMAND structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_hw_spec(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    HostCmd_DS_GET_HW_SPEC *hwspec = &cmd->params.hwspec;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_HW_SPEC) + S_DS_GEN);
+    memcpy(hwspec->PermanentAddr, priv->adapter->CurrentAddr, ETH_ALEN);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of ps_mode.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 	the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_ps_mode(wlan_private * priv,
+                        HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_802_11_PS_MODE *psm = &cmd->params.psmode;
+    u16 Action = cmd_action;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_PS_MODE) + S_DS_GEN);
+    psm->Action = wlan_cpu_to_le16(cmd_action);
+    psm->MultipleDtim = 0;
+    switch (Action) {
+    case HostCmd_SubCmd_Enter_PS:
+        PRINTM(INFO, "PS Command:" "SubCode- Enter PS\n");
+        PRINTM(INFO, "LocalListenInterval = %d\n",
+               Adapter->LocalListenInterval);
+
+        psm->LocalListenInterval =
+            wlan_cpu_to_le16(Adapter->LocalListenInterval);
+        psm->NullPktInterval = wlan_cpu_to_le16(Adapter->NullPktInterval);
+        psm->MultipleDtim = wlan_cpu_to_le16(priv->adapter->MultipleDtim);
+        psm->BCNMissTimeOut = wlan_cpu_to_le16(priv->adapter->BCNMissTimeOut);
+        if (priv->adapter->InfrastructureMode == Wlan802_11IBSS)
+            psm->AdhocAwakePeriod =
+                wlan_cpu_to_le16(priv->adapter->AdhocAwakePeriod);
+        break;
+
+    case HostCmd_SubCmd_Exit_PS:
+        PRINTM(INFO, "PS Command:" "SubCode- Exit PS\n");
+        break;
+
+    case HostCmd_SubCmd_Sleep_Confirmed:
+        PRINTM(INFO, "PS Command: SubCode- sleep confirm\n");
+        break;
+
+    default:
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of fw_wakeup_method.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 	the action: GET or SET
+ *  @param pdata_buf 	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_fw_wakeup_method(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * cmd,
+                                 int cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &cmd->params.fwwakeupmethod;
+    u16 action = (u16) cmd_action;
+    u16 method = *((u16 *) pdata_buf);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_FW_WAKE_METHOD);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_FW_WAKEUP_METHOD) +
+                         S_DS_GEN);
+    fwwm->Action = wlan_cpu_to_le16(action);
+    switch (action) {
+    case HostCmd_ACT_GEN_SET:
+        fwwm->Method = wlan_cpu_to_le16(method);
+        break;
+    case HostCmd_ACT_GEN_GET:
+    default:
+        fwwm->Method = 0;
+        break;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sends the HS_Activated event to the application
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_host_sleep_activated_event(wlan_private * priv)
+{
+    ENTER();
+
+    priv->adapter->HS_Activated = TRUE;
+    os_carrier_off(priv);
+    os_stop_queue(priv);
+    wmm_stop_queue(priv);
+
+#if WIRELESS_EXT > 14
+    send_iwevcustom_event(priv, CUS_EVT_HS_ACTIVATED);
+#endif /* WIRELESS_EXT */
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sends the HS_DeActivated event to the application
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_host_sleep_deactivated_event(wlan_private * priv)
+{
+    ENTER();
+
+    priv->adapter->HS_Activated = FALSE;
+
+#if WIRELESS_EXT > 14
+    send_iwevcustom_event(priv, CUS_EVT_HS_DEACTIVATED);
+#endif /* WIRELESS_EXT */
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function sends the HS_GPIO_INT event to the application
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+int
+wlan_host_sleep_wakeup_event(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->bHostSleepConfigured) {
+#if WIRELESS_EXT > 14
+        send_iwevcustom_event(priv, CUS_EVT_HS_WAKEUP);
+#endif /* WIRELESS_EXT */
+    } else {
+        PRINTM(INFO, "hs_gpio_int: HS not configured !!!\n");
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of host_sleep_cfg.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf 	A pointer to HostCmd_DS_802_11_HOST_SLEEP_CFG structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_host_sleep_cfg(wlan_private * priv,
+                               HostCmd_DS_COMMAND * cmd,
+                               HostCmd_DS_802_11_HOST_SLEEP_CFG * pdata_buf)
+{
+    HostCmd_DS_802_11_HOST_SLEEP_CFG *phwuc = &cmd->params.hostsleepcfg;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_HOST_SLEEP_CFG);
+    if ((pdata_buf->conditions != HOST_SLEEP_CFG_CANCEL)
+        && ((priv->adapter->ArpFilterSize > 0)
+            && (priv->adapter->ArpFilterSize <= ARP_FILTER_MAX_BUF_SIZE))) {
+        PRINTM(INFO, "Attach %d bytes ArpFilter to HSCfg cmd\n",
+               priv->adapter->ArpFilterSize);
+        memcpy(((u8 *) phwuc) + sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG),
+               priv->adapter->ArpFilter, priv->adapter->ArpFilterSize);
+        cmd->Size =
+            wlan_cpu_to_le16(priv->adapter->ArpFilterSize +
+                             sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG) +
+                             S_DS_GEN);
+    } else
+        cmd->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_HOST_SLEEP_CFG) +
+                             S_DS_GEN);
+    phwuc->conditions = wlan_cpu_to_le32(pdata_buf->conditions);
+    phwuc->gpio = pdata_buf->gpio;
+    phwuc->gap = pdata_buf->gap;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of inactivity_timeout.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   Action: GET SET
+ *  @param pdata_buf 	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * cmd,
+                                   u16 cmd_action, void *pdata_buf)
+{
+    u16 *timeout = (u16 *) pdata_buf;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_INACTIVITY_TIMEOUT);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_INACTIVITY_TIMEOUT) +
+                         S_DS_GEN);
+
+    cmd->params.inactivity_timeout.Action = wlan_cpu_to_le16(cmd_action);
+
+    if (cmd_action)
+        cmd->params.inactivity_timeout.Timeout = wlan_cpu_to_le16(*timeout);
+    else
+        cmd->params.inactivity_timeout.Timeout = 0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of sleep_period.
+ *  
+ *  @param priv    		A pointer to wlan_private structure
+ *  @param cmd	   		A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 		the action: GET or SET
+ *  @param pdata_buf		A pointer to data buffer
+ *  @return 	   		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_sleep_period(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd,
+                             u16 cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_SLEEP_PERIOD *pSleepPeriod = &cmd->params.ps_sleeppd;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SLEEP_PERIOD) +
+                                 S_DS_GEN);
+    memmove(pSleepPeriod, pdata_buf, sizeof(HostCmd_DS_802_11_SLEEP_PERIOD));
+    pSleepPeriod->Action = wlan_cpu_to_le16(pSleepPeriod->Action);
+    pSleepPeriod->Period = wlan_cpu_to_le16(pSleepPeriod->Period);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of wlan_cmd_802_11_crypto
+ *    
+ *  @param priv    		A pointer to wlan_private structure
+ *  @param cmd	   		A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 		the action: GET or SET
+ *  @param pdata_buf		A pointer to data buffer
+ *  @return 	   		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_crypto(wlan_private * priv,
+                       HostCmd_DS_COMMAND * cmd,
+                       u16 cmd_action, void *pdata_buf)
+{
+
+    HostCmd_DS_802_11_CRYPTO *crypto = (HostCmd_DS_802_11_CRYPTO *) pdata_buf;
+    MrvlIEtypes_Data_t *data =
+        (MrvlIEtypes_Data_t *) ((u8 *) pdata_buf +
+                                sizeof(HostCmd_DS_802_11_CRYPTO));
+    int len;
+
+    if (data->Header.Type != TLV_TYPE_CRYPTO_DATA)
+        return WLAN_STATUS_FAILURE;
+    switch (crypto->Algorithm) {
+    case CIPHER_TEST_RC4:
+        if (((crypto->KeyIVLength + crypto->KeyLength) > 256) ||
+            ((crypto->KeyIVLength + crypto->KeyLength) == 0))
+            return WLAN_STATUS_FAILURE;
+        break;
+    case CIPHER_TEST_AES:
+        if ((crypto->KeyLength != 16) && (crypto->KeyLength != 24) &&
+            (crypto->KeyLength != 32))
+            return WLAN_STATUS_FAILURE;
+        break;
+    case CIPHER_TEST_AES_KEY_WRAP:
+        if (crypto->KeyIVLength != 8)
+            return FALSE;
+        if ((crypto->KeyLength != 16) && (crypto->KeyLength != 24) &&
+            (crypto->KeyLength != 32))
+            return WLAN_STATUS_FAILURE;
+        if (data->Header.Len % 8)
+            return WLAN_STATUS_FAILURE;
+        break;
+    default:
+        return WLAN_STATUS_FAILURE;
+
+    }
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_CRYPTO);
+
+    len = data->Header.Len;
+    data->Header.Type = wlan_cpu_to_le16(data->Header.Type);
+    data->Header.Len = wlan_cpu_to_le16(data->Header.Len);
+
+    crypto->EncDec = wlan_cpu_to_le16(crypto->EncDec);
+    crypto->Algorithm = wlan_cpu_to_le16(crypto->Algorithm);
+    crypto->KeyIVLength = wlan_cpu_to_le16(crypto->KeyIVLength);
+    crypto->KeyLength = wlan_cpu_to_le16(crypto->KeyLength);
+
+    memmove(&cmd->params.crypto, pdata_buf, sizeof(HostCmd_DS_802_11_CRYPTO) +
+            len + sizeof(MrvlIEtypesHeader_t));
+
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_CRYPTO) + S_DS_GEN +
+                                 len + sizeof(MrvlIEtypesHeader_t));
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of sleep_params.
+ *  
+ *  @param priv    		A pointer to wlan_private structure
+ *  @param cmd	   		A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 		the action: GET or SET
+ *  @return 	   		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_sleep_params(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_SLEEP_PARAMS *sp = &cmd->params.sleep_params;
+
+    ENTER();
+
+    cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SLEEP_PARAMS)) +
+                                 S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS);
+
+    if (cmd_action == HostCmd_ACT_GEN_GET) {
+        memset(&Adapter->sp, 0, sizeof(SleepParams));
+        memset(sp, 0, sizeof(HostCmd_DS_802_11_SLEEP_PARAMS));
+        sp->Action = wlan_cpu_to_le16(cmd_action);
+    } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+        sp->Action = wlan_cpu_to_le16(cmd_action);
+        sp->Error = wlan_cpu_to_le16(Adapter->sp.sp_error);
+        sp->Offset = wlan_cpu_to_le16(Adapter->sp.sp_offset);
+        sp->StableTime = wlan_cpu_to_le16(Adapter->sp.sp_stabletime);
+        sp->CalControl = (u8) Adapter->sp.sp_calcontrol;
+        sp->ExternalSleepClk = (u8) Adapter->sp.sp_extsleepclk;
+        sp->Reserved = wlan_cpu_to_le16(Adapter->sp.sp_reserved);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** Length of WEP 40 bit key */
+#define WEP_40_BIT_LEN	5
+/** Length of WEP 104 bit key */
+#define WEP_104_BIT_LEN	13
+
+/** 
+ *  @brief This function prepares command of set_wep.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   HostCmd_ACT_ADD or HostCmd_ACT_REMOVE
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_set_wep(wlan_private * priv,
+                        HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_802_11_SET_WEP *wep = &cmd->params.wep;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (cmd_action == HostCmd_ACT_ADD) {
+        cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP);
+        cmd->Size =
+            wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SET_WEP)) + S_DS_GEN);
+        wep->Action = wlan_cpu_to_le16(HostCmd_ACT_ADD);
+
+        /* default tx key index */
+        wep->KeyIndex = wlan_cpu_to_le16(Adapter->CurrentWepKeyIndex &
+                                         HostCmd_WEP_KEY_INDEX_MASK);
+
+        PRINTM(INFO, "Tx Key Index: %u\n", wep->KeyIndex);
+
+        switch (Adapter->WepKey[0].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial,
+                    Adapter->WepKey[0].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial,
+                    Adapter->WepKey[0].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key1 Length = %d is incorrect\n",
+                   Adapter->WepKey[0].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        switch (Adapter->WepKey[1].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial,
+                    Adapter->WepKey[1].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial,
+                    Adapter->WepKey[1].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key2 Length = %d is incorrect\n",
+                   Adapter->WepKey[1].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        switch (Adapter->WepKey[2].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial,
+                    Adapter->WepKey[2].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial,
+                    Adapter->WepKey[2].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key3 Length = %d is incorrect\n",
+                   Adapter->WepKey[2].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        switch (Adapter->WepKey[3].KeyLength) {
+        case WEP_40_BIT_LEN:
+            wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_40_BIT;
+            memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial,
+                    Adapter->WepKey[3].KeyLength);
+            break;
+        case WEP_104_BIT_LEN:
+            wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_104_BIT;
+            memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial,
+                    Adapter->WepKey[3].KeyLength);
+            break;
+        case 0:
+            break;
+        default:
+            PRINTM(INFO, "Key4 Length = %d is incorrect\n",
+                   Adapter->WepKey[3].KeyLength);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    } else if (cmd_action == HostCmd_ACT_REMOVE) {
+        cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP);
+        cmd->Size =
+            wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_SET_WEP)) + S_DS_GEN);
+        wep->Action = wlan_cpu_to_le16(HostCmd_ACT_REMOVE);
+
+        /* default tx key index */
+        wep->KeyIndex = wlan_cpu_to_le16((u16) (Adapter->CurrentWepKeyIndex &
+                                                (u32)
+                                                HostCmd_WEP_KEY_INDEX_MASK));
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of key_material.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action 	the action: GET or SET
+ *  @param cmd_oid	OID: ENABLE or DISABLE
+ *  @param pdata_buf    A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_key_material(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd,
+                             u16 cmd_action,
+                             WLAN_OID cmd_oid, void *pdata_buf)
+{
+    HostCmd_DS_802_11_KEY_MATERIAL *pKeyMaterial = &cmd->params.keymaterial;
+    WLAN_802_11_KEY *pKey = (WLAN_802_11_KEY *) pdata_buf;
+    u16 KeyParamSet_len;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+    pKeyMaterial->Action = wlan_cpu_to_le16(cmd_action);
+
+    if (cmd_action == HostCmd_ACT_GEN_GET) {
+        cmd->Size = wlan_cpu_to_le16(2 + S_DS_GEN);
+        ret = WLAN_STATUS_SUCCESS;
+        goto done;
+    }
+
+    memset(&pKeyMaterial->KeyParamSet, 0, sizeof(MrvlIEtype_KeyParamSet_t));
+
+    if (pKey->KeyLength == WPA_AES_KEY_LEN) {
+        PRINTM(INFO, "WPA_AES\n");
+        pKeyMaterial->KeyParamSet.KeyTypeId =
+            wlan_cpu_to_le16(KEY_TYPE_ID_AES);
+
+        if (cmd_oid == (WLAN_OID) KEY_INFO_ENABLED)
+            pKeyMaterial->KeyParamSet.KeyInfo =
+                wlan_cpu_to_le16(KEY_INFO_AES_ENABLED);
+        else
+            pKeyMaterial->KeyParamSet.KeyInfo =
+                !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED));
+
+        if (pKey->KeyIndex & 0x40000000)        //AES pairwise key: unicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_AES_UNICAST);
+        else                    //AES group key: multicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_AES_MCAST);
+    } else if (pKey->KeyLength == WPA_TKIP_KEY_LEN) {
+        PRINTM(INFO, "WPA_TKIP\n");
+        pKeyMaterial->KeyParamSet.KeyTypeId =
+            wlan_cpu_to_le16(KEY_TYPE_ID_TKIP);
+        pKeyMaterial->KeyParamSet.KeyInfo =
+            wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED);
+
+        if (pKey->KeyIndex & 0x40000000)        //TKIP pairwise key: unicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST);
+        else                    //TKIP group key: multicast
+            pKeyMaterial->KeyParamSet.KeyInfo |=
+                wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST);
+    }
+
+    if (pKeyMaterial->KeyParamSet.KeyTypeId) {
+        pKeyMaterial->KeyParamSet.Type =
+            wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+        pKeyMaterial->KeyParamSet.KeyLen = wlan_cpu_to_le16(pKey->KeyLength);
+        memcpy(pKeyMaterial->KeyParamSet.Key,
+               pKey->KeyMaterial, pKey->KeyLength);
+        pKeyMaterial->KeyParamSet.Length =
+            wlan_cpu_to_le16(pKey->KeyLength + 6);
+
+#define TYPE_LEN_FIELDS_LEN 4
+        KeyParamSet_len = (pKey->KeyLength + 6) + TYPE_LEN_FIELDS_LEN;
+#define ACTION_FIELD_LEN 2
+        cmd->Size =
+            wlan_cpu_to_le16(KeyParamSet_len + ACTION_FIELD_LEN + S_DS_GEN);
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of get_log.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_get_log(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_GET_LOG) + S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of snmp_mib.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param cmd_oid   	the OID of SNMP MIB
+ *  @param pdata_buf	the pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+                         HostCmd_DS_COMMAND * cmd,
+                         int cmd_action, int cmd_oid, void *pdata_buf)
+{
+    HostCmd_DS_802_11_SNMP_MIB *pSNMPMIB = &cmd->params.smib;
+    wlan_adapter *Adapter = priv->adapter;
+    u8 ucTemp;
+
+    ENTER();
+
+    PRINTM(INFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_SNMP_MIB) + S_DS_GEN);
+
+    switch (cmd_oid) {
+    case DesiredBssType_i:
+        pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+        pSNMPMIB->OID = wlan_cpu_to_le16((u16) DesiredBssType_i);
+        pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u8));
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure)
+            ucTemp = SNMP_MIB_VALUE_INFRA;
+        else
+            ucTemp = SNMP_MIB_VALUE_ADHOC;
+
+        memmove(pSNMPMIB->Value, &ucTemp, sizeof(u8));
+
+        break;
+
+    case Dot11D_i:
+        {
+            u32 ulTemp;
+
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) Dot11D_i);
+
+            if (cmd_action == HostCmd_ACT_GEN_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *(u32 *) pdata_buf;
+                *((PUSHORT) (pSNMPMIB->Value)) =
+                    wlan_cpu_to_le16((u16) ulTemp);
+            }
+            break;
+        }
+
+    case Dot11H_i:
+        {
+            u32 ulTemp;
+
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) Dot11H_i);
+
+            if (cmd_action == HostCmd_ACT_GEN_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *(u32 *) pdata_buf;
+                *((PUSHORT) (pSNMPMIB->Value)) =
+                    wlan_cpu_to_le16((u16) ulTemp);
+            }
+            break;
+        }
+
+    case FragThresh_i:
+        {
+            WLAN_802_11_FRAGMENTATION_THRESHOLD ulTemp;
+
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) FragThresh_i);
+
+            if (cmd_action == HostCmd_ACT_GEN_GET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+            } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *((WLAN_802_11_FRAGMENTATION_THRESHOLD *)
+                           pdata_buf);
+                *((PUSHORT) (pSNMPMIB->Value)) =
+                    wlan_cpu_to_le16((u16) ulTemp);
+
+            }
+
+            break;
+        }
+
+    case RtsThresh_i:
+        {
+
+            WLAN_802_11_RTS_THRESHOLD ulTemp;
+            pSNMPMIB->OID = wlan_cpu_to_le16((u16) RtsThresh_i);
+
+            if (cmd_action == HostCmd_ACT_GEN_GET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+            } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+                pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+                pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+                ulTemp = *((WLAN_802_11_RTS_THRESHOLD *)
+                           pdata_buf);
+                *(PUSHORT) (pSNMPMIB->Value) = wlan_cpu_to_le16((u16) ulTemp);
+
+            }
+            break;
+        }
+    case ShortRetryLim_i:
+        pSNMPMIB->OID = wlan_cpu_to_le16((u16) ShortRetryLim_i);
+
+        if (cmd_action == HostCmd_ACT_GEN_GET) {
+            pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+        } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+            pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+            pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16));
+            *((PUSHORT) (pSNMPMIB->Value)) =
+                wlan_cpu_to_le16((u16) Adapter->TxRetryCount);
+        }
+
+        break;
+    default:
+        break;
+    }
+
+    PRINTM(INFO,
+           "SNMP_CMD: Command=0x%x, Size=0x%x, SeqNum=0x%x, Result=0x%x\n",
+           cmd->Command, cmd->Size, cmd->SeqNum, cmd->Result);
+
+    PRINTM(INFO,
+           "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n",
+           pSNMPMIB->QueryType, pSNMPMIB->OID, pSNMPMIB->BufSize,
+           *(u16 *) pSNMPMIB->Value);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of radio_control.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_radio_control(wlan_private * priv,
+                              HostCmd_DS_COMMAND * cmd, int cmd_action)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_RADIO_CONTROL *pRadioControl = &cmd->params.radio;
+
+    ENTER();
+
+    cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RADIO_CONTROL))
+                                 + S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL);
+
+    pRadioControl->Action = wlan_cpu_to_le16(cmd_action);
+    pRadioControl->Control = wlan_cpu_to_le16(Adapter->RadioOn);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of bca_timeshare.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param user_bca_ts	A pointer to HostCmd_DS_802_11_BCA_TIMESHARE structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_bca_timeshare(wlan_private * priv,
+                              HostCmd_DS_COMMAND * cmd,
+                              u16 cmd_action,
+                              HostCmd_DS_802_11_BCA_TIMESHARE * user_bca_ts)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &cmd->params.bca_timeshare;
+
+    ENTER();
+
+    cmd->Size = wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_BCA_TIMESHARE)) +
+                                 S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE);
+
+    if (cmd_action == HostCmd_ACT_GEN_GET) {
+        memset(&Adapter->bca_ts, 0, sizeof(bca_ts));
+        memset(bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
+        bca_ts->Action = wlan_cpu_to_le16(cmd_action);
+        bca_ts->TrafficType = wlan_cpu_to_le16(user_bca_ts->TrafficType);
+    } else if (cmd_action == HostCmd_ACT_GEN_SET) {
+        bca_ts->Action = wlan_cpu_to_le16(cmd_action);
+        bca_ts->TrafficType = wlan_cpu_to_le16(user_bca_ts->TrafficType);
+        bca_ts->TimeShareInterval =
+            wlan_cpu_to_le32(user_bca_ts->TimeShareInterval);
+        bca_ts->BTTime = wlan_cpu_to_le32(user_bca_ts->BTTime);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rf_tx_power.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+                            HostCmd_DS_COMMAND * cmd,
+                            u16 cmd_action, void *pdata_buf)
+{
+
+    HostCmd_DS_802_11_RF_TX_POWER *pRTP = &cmd->params.txp;
+
+    ENTER();
+
+    cmd->Size =
+        wlan_cpu_to_le16((sizeof(HostCmd_DS_802_11_RF_TX_POWER)) + S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER);
+    pRTP->Action = cmd_action;
+
+    PRINTM(INFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n", cmd->Size,
+           cmd->Command, pRTP->Action);
+
+    switch (cmd_action) {
+    case HostCmd_ACT_GEN_GET:
+        pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET);
+        pRTP->CurrentLevel = 0;
+        break;
+
+    case HostCmd_ACT_GEN_SET:
+        pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
+        pRTP->CurrentLevel = wlan_cpu_to_le16(*((u16 *) pdata_buf));
+        break;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rf_antenna.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+                           HostCmd_DS_COMMAND * cmd,
+                           u16 cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_RF_ANTENNA *rant = &cmd->params.rant;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_ANTENNA) + S_DS_GEN);
+
+    rant->Action = wlan_cpu_to_le16(cmd_action);
+    if ((cmd_action == HostCmd_ACT_SET_RX) ||
+        (cmd_action == HostCmd_ACT_SET_TX)) {
+        rant->AntennaMode =
+            wlan_cpu_to_le16((u16) (*(WLAN_802_11_ANTENNA *) pdata_buf));
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rate_adapt_rateset.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_802_11_RATE_ADAPT_RATESET * rateadapt = &cmd->params.rateset;
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RATE_ADAPT_RATESET) +
+                         S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RATE_ADAPT_RATESET);
+
+    ENTER();
+
+    rateadapt->Action = wlan_cpu_to_le16(cmd_action);
+    rateadapt->HWRateDropMode = wlan_cpu_to_le16(Adapter->HWRateDropMode);
+    rateadapt->Threshold = wlan_cpu_to_le16(Adapter->Threshold);
+    rateadapt->FinalRate = wlan_cpu_to_le16(Adapter->FinalRate);
+    rateadapt->Bitmap = wlan_cpu_to_le16(Adapter->RateBitmap);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of mac_multicast_adr.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_mac_multicast_adr(wlan_private * priv,
+                           HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    HostCmd_DS_MAC_MULTICAST_ADR *pMCastAdr = &cmd->params.madr;
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_MULTICAST_ADR) + S_DS_GEN);
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+    pMCastAdr->Action = wlan_cpu_to_le16(cmd_action);
+    pMCastAdr->NumOfAdrs =
+        wlan_cpu_to_le16((u16) Adapter->NumOfMulticastMACAddr);
+    memcpy(pMCastAdr->MACList, Adapter->MulticastList,
+           Adapter->NumOfMulticastMACAddr * ETH_ALEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rf_channel.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param option	the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rf_channel(wlan_private * priv,
+                           HostCmd_DS_COMMAND * cmd,
+                           int option, void *pdata_buf)
+{
+    HostCmd_DS_802_11_RF_CHANNEL *rfchan = &cmd->params.rfchannel;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RF_CHANNEL)
+                                 + S_DS_GEN);
+
+    if (option == HostCmd_OPT_802_11_RF_CHANNEL_SET) {
+        rfchan->CurrentChannel = wlan_cpu_to_le16(*((u16 *) pdata_buf));
+    }
+
+    rfchan->Action = wlan_cpu_to_le16(option);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of rssi.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_rssi(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RSSI);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_RSSI) + S_DS_GEN);
+    cmd->params.rssi.N = wlan_cpu_to_le16(Adapter->bcn_avg_factor);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of reg_access.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param CmdPtr  	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_reg_access(wlan_private * priv,
+                    HostCmd_DS_COMMAND * CmdPtr,
+                    u8 cmd_action, void *pdata_buf)
+{
+    wlan_offset_value *offval;
+
+    ENTER();
+
+    offval = (wlan_offset_value *) pdata_buf;
+
+    switch (CmdPtr->Command) {
+    case HostCmd_CMD_MAC_REG_ACCESS:
+        {
+            HostCmd_DS_MAC_REG_ACCESS *macreg;
+
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_REG_ACCESS) +
+                                 S_DS_GEN);
+            macreg = (HostCmd_DS_MAC_REG_ACCESS *) & CmdPtr->params.macreg;
+
+            macreg->Action = wlan_cpu_to_le16(cmd_action);
+            macreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
+            macreg->Value = wlan_cpu_to_le32(offval->value);
+
+            break;
+        }
+
+    case HostCmd_CMD_BBP_REG_ACCESS:
+        {
+            HostCmd_DS_BBP_REG_ACCESS *bbpreg;
+
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_BBP_REG_ACCESS) +
+                                 S_DS_GEN);
+            bbpreg = (HostCmd_DS_BBP_REG_ACCESS *) & CmdPtr->params.bbpreg;
+
+            bbpreg->Action = wlan_cpu_to_le16(cmd_action);
+            bbpreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
+            bbpreg->Value = (u8) offval->value;
+
+            break;
+        }
+
+    case HostCmd_CMD_RF_REG_ACCESS:
+        {
+            HostCmd_DS_RF_REG_ACCESS *rfreg;
+
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_RF_REG_ACCESS) + S_DS_GEN);
+            rfreg = (HostCmd_DS_RF_REG_ACCESS *) & CmdPtr->params.rfreg;
+
+            rfreg->Action = wlan_cpu_to_le16(cmd_action);
+            rfreg->Offset = wlan_cpu_to_le16((u16) offval->offset);
+            rfreg->Value = (u8) offval->value;
+
+            break;
+        }
+
+    default:
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of mac_address.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_mac_address(wlan_private * priv,
+                            HostCmd_DS_COMMAND * cmd, u16 cmd_action)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_MAC_ADDRESS) +
+                                 S_DS_GEN);
+    cmd->Result = 0;
+
+    cmd->params.macadd.Action = wlan_cpu_to_le16(cmd_action);
+
+    if (cmd_action == HostCmd_ACT_GEN_SET) {
+        memcpy(cmd->params.macadd.MacAdd, Adapter->CurrentAddr, ETH_ALEN);
+        HEXDUMP("SET_CMD: MAC ADDRESS-", Adapter->CurrentAddr, 6);
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of cal_data_ext.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_cal_data_ext(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_802_11_CAL_DATA_EXT *PCalDataext = pdata_buf;
+
+    HostCmd_DS_802_11_CAL_DATA_EXT *pCmdCalData =
+        (HostCmd_DS_802_11_CAL_DATA_EXT *) & cmd->params.caldataext;
+
+    ENTER();
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_CAL_DATA_EXT);
+
+    PRINTM(INFO, "CalDataLen = %d(d)\n", PCalDataext->CalDataLen);
+
+    if (PCalDataext->CalDataLen >
+        MAX_SETGET_CONF_CMD_LEN - CAL_DATA_HEADER_LEN) {
+        PRINTM(MSG, "CAL_DATA_EXT: Cal data lenght too large!\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memcpy(pCmdCalData, PCalDataext,
+           PCalDataext->CalDataLen + CAL_DATA_HEADER_LEN);
+
+    pCmdCalData->Action = wlan_cpu_to_le16(pCmdCalData->Action);
+    pCmdCalData->Revision = wlan_cpu_to_le16(pCmdCalData->Revision);
+    pCmdCalData->CalDataLen = wlan_cpu_to_le16(pCmdCalData->CalDataLen);
+
+    cmd->Size = wlan_cpu_to_le16(PCalDataext->CalDataLen +
+                                 CAL_DATA_HEADER_LEN + S_DS_GEN);
+
+    PRINTM(INFO, "CAL_DATA_EXT: cmd->Size = %d(d)\n", cmd->Size);
+
+    cmd->Result = 0;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function prepares command of eeprom_access.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd	   	A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+                              HostCmd_DS_COMMAND * cmd,
+                              int cmd_action, void *pdata_buf)
+{
+    wlan_ioctl_regrdwr *ea = pdata_buf;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_EEPROM_ACCESS);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_EEPROM_ACCESS) + S_DS_GEN);
+    cmd->Result = 0;
+
+    cmd->params.rdeeprom.Action = wlan_cpu_to_le16(ea->Action);
+    cmd->params.rdeeprom.Offset = wlan_cpu_to_le16(ea->Offset);
+    cmd->params.rdeeprom.ByteCount = wlan_cpu_to_le16(ea->NOB);
+    cmd->params.rdeeprom.Value = 0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+static int
+wlan_cmd_ibss_coalescing_status(wlan_private * priv,
+                                HostCmd_DS_COMMAND * cmd,
+                                int cmd_action, void *pdata_buf)
+{
+    HostCmd_DS_802_11_IBSS_Status *pIBSSReq = &(cmd->params.ibssCoalescing);
+    u16 *enable = pdata_buf;
+
+    PRINTM(INFO, "HostCmd_CMD_802_11_BSSID_QUERY request");
+
+    cmd->Command =
+        wlan_cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_IBSS_Status) + S_DS_GEN);
+    cmd->Result = 0;
+    pIBSSReq->Action = wlan_cpu_to_le16(cmd_action);
+
+    switch (cmd_action) {
+    case HostCmd_ACT_GEN_SET:
+        pIBSSReq->Enable = wlan_cpu_to_le16(*enable);
+        break;
+
+        /* In other case.. Noting to do */
+    case HostCmd_ACT_GEN_GET:
+    default:
+        break;
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function queues the command to cmd list.
+ *  
+ *  @param Adapter	A pointer to wlan_adapter structure
+ *  @param CmdNode   	A pointer to CmdCtrlNode structure
+ *  @param addtail	specify if the cmd needs to be queued in the header or tail
+ *  @return 	   	n/a
+ */
+void
+wlan_insert_cmd_to_pending_q(wlan_adapter * Adapter, CmdCtrlNode * CmdNode,
+                             BOOLEAN addtail)
+{
+    ulong flags;
+    HostCmd_DS_COMMAND *CmdPtr;
+    u16 command;
+
+    ENTER();
+
+    if (!CmdNode) {
+        PRINTM(WARN, "QUEUE_CMD: CmdNode is NULL\n");
+        goto done;
+    }
+
+    CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+    if (!CmdPtr) {
+        PRINTM(WARN, "QUEUE_CMD: CmdPtr is NULL\n");
+        goto done;
+    }
+
+    command = wlan_le16_to_cpu(CmdPtr->Command);
+
+    /* Exit_PS command needs to be queued in the header always. */
+    if (command == HostCmd_CMD_802_11_PS_MODE) {
+        HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode;
+        if (wlan_le16_to_cpu(psm->Action) == HostCmd_SubCmd_Exit_PS) {
+            if (Adapter->PSState != PS_STATE_FULL_POWER)
+                addtail = FALSE;
+        }
+    }
+
+    if ((command == HostCmd_CMD_802_11_WAKEUP_CONFIRM)
+        || (command == HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE)
+        || (command == HostCmd_CMD_802_11_HOST_SLEEP_CFG)
+        ) {
+        addtail = FALSE;
+    }
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+
+    if (addtail)
+        list_add_tail((struct list_head *) CmdNode, &Adapter->CmdPendingQ);
+    else
+        list_add((struct list_head *) CmdNode, &Adapter->CmdPendingQ);
+
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    PRINTM(INFO, "QUEUE_CMD: cmd=0x%x is queued\n", command);
+
+  done:
+    LEAVE();
+    return;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/** 
+ *  @brief This function sends general command to firmware.
+ *  
+ *  @param priv     	A pointer to wlan_private structure
+ *  @param cmd      	A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf	A pointer to data buffer
+ *  @return         	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_mfg_cmd(wlan_private * priv,
+                 HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_GEN *pCmdPtr;
+
+    ENTER();
+
+    pCmdPtr = (HostCmd_DS_GEN *) pdata_buf;
+
+    /* copy the MFG command to command buffer */
+    memcpy((void *) cmd, pdata_buf, pCmdPtr->Size);
+
+    PRINTM(INFO, "MFG command size = %d\n", pCmdPtr->Size);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MFG_COMMAND);
+    cmd->Size = wlan_cpu_to_le16(cmd->Size);
+    cmd->Result = 0;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+#endif
+
+/** 
+ *  @brief This function downloads the command to firmware.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param CmdNode   	A pointer to CmdCtrlNode structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_dnld_cmd_to_fw(wlan_private * priv, CmdCtrlNode * CmdNode)
+{
+    ulong flags;
+    HostCmd_DS_COMMAND *CmdPtr;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 CmdSize;
+    u16 Command;
+    unsigned long driver_flags;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    if (!Adapter || !CmdNode) {
+        PRINTM(ERROR, "DNLD_CMD: Adapter = %#x, CmdNode = %#x\n",
+               (int) Adapter, (int) CmdNode);
+        if (CmdNode)
+            wlan_insert_cmd_to_free_q(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+
+    if (!CmdPtr || !CmdPtr->Size) {
+        PRINTM(ERROR, "DNLD_CMD: CmdPtr is Null or Cmd Size is Zero, "
+               "Not sending\n");
+        wlan_insert_cmd_to_free_q(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Set command sequence number */
+    Adapter->SeqNum++;
+    CmdPtr->SeqNum = wlan_cpu_to_le16(Adapter->SeqNum);
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+    Adapter->CurCmd = CmdNode;
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    Command = wlan_le16_to_cpu(CmdPtr->Command);
+    CmdSize = wlan_le16_to_cpu(CmdPtr->Size);
+
+    CmdNode->CmdWaitQWoken = FALSE;
+
+    ret = sbi_host_to_card(priv, MV_TYPE_CMD, (u8 *) CmdPtr, CmdSize);
+
+    /* clear TxDone interrupt bit */
+    OS_INT_DISABLE(priv, driver_flags);
+    Adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
+    OS_INT_RESTORE(priv, driver_flags);
+
+    if (ret != 0) {
+        PRINTM(ERROR, "DNLD_CMD: Host to Card Failed\n");
+        /* set error code that will be transferred back to wlan_prepare_cmd() */
+        Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
+        wlan_insert_cmd_to_free_q(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+        Adapter->dbg.num_cmd_host_to_card_failure++;
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Save the last command id and action to debug log */
+    Adapter->dbg.LastCmdIndex = (Adapter->dbg.LastCmdIndex + 1) % DBG_CMD_NUM;
+    Adapter->dbg.LastCmdId[Adapter->dbg.LastCmdIndex] = Command;
+    Adapter->dbg.LastCmdAct[Adapter->dbg.LastCmdIndex] =
+        wlan_le16_to_cpu(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN));
+
+    PRINTM(CMND, "DNLD_CMD: 0x%x, act 0x%x, len %d, seqno %d @ %lu\n",
+           Command, wlan_le16_to_cpu(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN)),
+           CmdSize, wlan_le16_to_cpu(CmdPtr->SeqNum), os_time_get());
+    DBG_HEXDUMP(CMD_D, "DNLD_CMD", CmdNode->BufVirtualAddr, CmdSize);
+
+    /* Setup the timer after transmit command */
+    if (Command == HostCmd_CMD_802_11_SCAN
+        || Command == HostCmd_CMD_802_11_DEAUTHENTICATE
+        || Command == HostCmd_CMD_802_11_ASSOCIATE
+        || Command == HostCmd_CMD_WMM_ADDTS_REQ) {
+        wlan_mod_timer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_10S);
+    } else {
+        wlan_mod_timer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_5S);
+    }
+
+    Adapter->CommandTimerIsSet = TRUE;
+
+    if (Command == HostCmd_CMD_802_11_DEEP_SLEEP) {
+        if (Adapter->IntCounter || Adapter->CurrentTxSkb)
+            PRINTM(INFO, "DNLD_CMD: DS- IntCnt=%d CurTxSkb=%s\n",
+                   Adapter->IntCounter, (Adapter->CurrentTxSkb) ? "Y" : "N");
+
+        if (Adapter->IntCounter) {
+            OS_INT_DISABLE(priv, driver_flags);
+            Adapter->IntCounterSaved = Adapter->IntCounter;
+            Adapter->IntCounter = 0;
+            OS_INT_RESTORE(priv, driver_flags);
+        }
+        if (Adapter->CurrentTxSkb) {
+            kfree_skb(Adapter->CurrentTxSkb);
+            OS_INT_DISABLE(priv, driver_flags);
+            Adapter->CurrentTxSkb = NULL;
+            OS_INT_RESTORE(priv, driver_flags);
+            priv->stats.tx_dropped++;
+        }
+        /* 1. change the PS state to DEEP_SLEEP
+         * 2. since there is no response for this command, so 
+         *    delete the command timer and free the Node. */
+
+        Adapter->IsDeepSleep = TRUE;
+
+        wlan_insert_cmd_to_free_q(priv, CmdNode);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+        if (Adapter->CommandTimerIsSet) {
+            wlan_cancel_timer(&Adapter->MrvDrvCommandTimer);
+            Adapter->CommandTimerIsSet = FALSE;
+        }
+
+        if (Adapter->IsAutoDeepSleepEnabled) {
+            Adapter->bWakeupDevRequired = TRUE;
+            /* For auto deep sleep mode, after entering deep sleep state, 
+             * dnld_sent flag should be cleared so that the commands in 
+             * pending queue can be handled by main thread. */
+            priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+        }
+
+        if (Adapter->bHostSleepConfigured) {
+            Adapter->bWakeupDevRequired = TRUE;
+            wlan_host_sleep_activated_event(priv);
+        }
+
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function prepares command of mac_control.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd		A pointer to HostCmd_DS_COMMAND structure
+ *  @param InfoBuf	A pointer to the command string
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_cmd_mac_control(wlan_private * priv,
+                     HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    HostCmd_DS_MAC_CONTROL *mac = &cmd->params.macctrl;
+    u16 Action = *((u16 *) InfoBuf);
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_MAC_CONTROL) + S_DS_GEN);
+    mac->Action = wlan_cpu_to_le16(Action);
+
+    PRINTM(INFO, "wlan_cmd_mac_control(): Action=0x%X Size=%d\n",
+           mac->Action, cmd->Size);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function inserts command node to CmdFreeQ
+ *  after cleans it.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param pTempCmd	A pointer to CmdCtrlNode structure
+ *  @return 		n/a
+ */
+void
+wlan_insert_cmd_to_free_q(wlan_private * priv, CmdCtrlNode * pTempCmd)
+{
+    ulong flags;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!pTempCmd)
+        goto done;
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+    wlan_clean_cmd_node(pTempCmd);
+    list_add_tail((struct list_head *) pTempCmd, &Adapter->CmdFreeQ);
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+  done:
+    LEAVE();
+}
+
+/** 
+ *  @brief This function prepare the command before send to firmware.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd_no	command number
+ *  @param cmd_action	command action: GET or SET
+ *  @param wait_option	wait option: wait response or not
+ *  @param cmd_oid	cmd oid: treated as sub command
+ *  @param pdata_buf	A pointer to informaion buffer
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_prepare_cmd(wlan_private * priv,
+                 u16 cmd_no,
+                 u16 cmd_action,
+                 u16 wait_option, WLAN_OID cmd_oid, void *pdata_buf)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    CmdCtrlNode *CmdNode;
+    HostCmd_DS_COMMAND *CmdPtr;
+
+    ENTER();
+
+    if (!Adapter) {
+        PRINTM(ERROR, "PREP_CMD: Adapter is Null\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (Adapter->SurpriseRemoved) {
+        PRINTM(ERROR, "PREP_CMD: Card is Removed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    CmdNode = wlan_get_cmd_node(priv);
+
+    if (CmdNode == NULL) {
+        PRINTM(MSG, "PREP_CMD: No free CmdNode\n");
+
+        /* Wake up main thread to execute next command */
+        wake_up_interruptible(&priv->MainThread.waitQ);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    wlan_init_cmd_node(priv, CmdNode, cmd_oid, wait_option, pdata_buf);
+
+    CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+
+    if (!CmdPtr) {
+        PRINTM(MSG, "PREP_CMD: BufVirtualAddr of CmdNode is NULL\n");
+        wlan_insert_cmd_to_free_q(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    CmdPtr->Command = cmd_no;
+    CmdPtr->Result = 0;
+
+    TX_EVENT_FLAGS_SET(&CmdNode->cmdwait_q, 0, TX_AND);
+    switch (cmd_no) {
+    case HostCmd_CMD_GET_HW_SPEC:
+        ret = wlan_cmd_hw_spec(priv, CmdPtr);
+        break;
+    case HostCmd_CMD_802_11_PS_MODE:
+        ret = wlan_cmd_802_11_ps_mode(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_SCAN:
+        ret = wlan_cmd_802_11_scan(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_MAC_CONTROL:
+        ret = wlan_cmd_mac_control(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_ASSOCIATE:
+        ret = wlan_cmd_802_11_associate(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_DEAUTHENTICATE:
+        ret = wlan_cmd_802_11_deauthenticate(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_SET_WEP:
+        ret = wlan_cmd_802_11_set_wep(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_AD_HOC_START:
+        ret = wlan_cmd_802_11_ad_hoc_start(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_RESET:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
+        break;
+
+    case HostCmd_CMD_802_11_GET_LOG:
+        ret = wlan_cmd_802_11_get_log(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_SNMP_MIB:
+        ret = wlan_cmd_802_11_snmp_mib(priv, CmdPtr,
+                                       cmd_action, cmd_oid, pdata_buf);
+        break;
+
+    case HostCmd_CMD_MAC_REG_ACCESS:
+    case HostCmd_CMD_BBP_REG_ACCESS:
+    case HostCmd_CMD_RF_REG_ACCESS:
+        ret = wlan_cmd_reg_access(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RF_CHANNEL:
+        ret = wlan_cmd_802_11_rf_channel(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RF_TX_POWER:
+        ret = wlan_cmd_802_11_rf_tx_power(priv, CmdPtr,
+                                          cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RADIO_CONTROL:
+        ret = wlan_cmd_802_11_radio_control(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_RF_ANTENNA:
+        ret = wlan_cmd_802_11_rf_antenna(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RATE_ADAPT_RATESET:
+        ret = wlan_cmd_802_11_rate_adapt_rateset(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_MAC_MULTICAST_ADR:
+        ret = wlan_cmd_mac_multicast_adr(priv, CmdPtr, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_AD_HOC_JOIN:
+        ret = wlan_cmd_802_11_ad_hoc_join(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_RSSI:
+        ret = wlan_cmd_802_11_rssi(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_AD_HOC_STOP:
+        ret = wlan_cmd_802_11_ad_hoc_stop(priv, CmdPtr);
+        break;
+    case HostCmd_CMD_802_11_KEY_MATERIAL:
+        ret = wlan_cmd_802_11_key_material(priv, CmdPtr,
+                                           cmd_action, cmd_oid, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_MAC_ADDRESS:
+        ret = wlan_cmd_802_11_mac_address(priv, CmdPtr, cmd_action);
+        break;
+    case HostCmd_CMD_802_11_CAL_DATA_EXT:
+        ret = wlan_cmd_802_11_cal_data_ext(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_DEEP_SLEEP:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size = wlan_cpu_to_le16((u16)
+                                        (sizeof
+                                         (HostCmd_DS_802_11_DEEP_SLEEP)));
+        break;
+
+    case HostCmd_CMD_802_11_HOST_SLEEP_CFG:
+        ret = wlan_cmd_802_11_host_sleep_cfg(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_WAKEUP_CONFIRM:
+    case HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
+        break;
+    case HostCmd_CMD_802_11_EEPROM_ACCESS:
+        ret = wlan_cmd_802_11_eeprom_access(priv, CmdPtr,
+                                            cmd_action, pdata_buf);
+        break;
+
+#ifdef MFG_CMD_SUPPORT
+    case HostCmd_CMD_MFG_COMMAND:
+        ret = wlan_cmd_mfg_cmd(priv, CmdPtr, pdata_buf);
+        break;
+#endif
+
+    case HostCmd_CMD_802_11D_DOMAIN_INFO:
+        ret = wlan_cmd_802_11d_domain_info(priv, CmdPtr, cmd_no, cmd_action);
+        break;
+
+    case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+    case HostCmd_CMD_802_11_TPC_INFO:
+    case HostCmd_CMD_802_11_CHAN_SW_ANN:
+        ret = wlan_11h_cmd_process(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_MEASUREMENT_REQUEST:
+    case HostCmd_CMD_MEASUREMENT_REPORT:
+        ret = wlan_meas_cmd_process(priv, CmdPtr, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_SLEEP_PARAMS:
+        ret = wlan_cmd_802_11_sleep_params(priv, CmdPtr, cmd_action);
+        break;
+    case HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE:
+        ret = wlan_cmd_802_11_bca_timeshare(priv, CmdPtr,
+                                            cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_INACTIVITY_TIMEOUT:
+        ret = wlan_cmd_802_11_inactivity_timeout(priv, CmdPtr,
+                                                 cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+        ret = wlan_cmd_802_11_bg_scan_config(priv, CmdPtr,
+                                             cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+        ret = wlan_cmd_802_11_bg_scan_query(priv, CmdPtr);
+        break;
+
+    case HostCmd_CMD_802_11_FW_WAKE_METHOD:
+        ret = wlan_cmd_802_11_fw_wakeup_method(priv, CmdPtr,
+                                               cmd_action, pdata_buf);
+        break;
+
+    case HostCmd_CMD_WMM_GET_STATUS:
+        ret = wlan_cmd_wmm_get_status(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_ADDTS_REQ:
+        ret = wlan_cmd_wmm_addts_req(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_DELTS_REQ:
+        ret = wlan_cmd_wmm_delts_req(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_QUEUE_CONFIG:
+        ret = wlan_cmd_wmm_queue_config(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_QUEUE_STATS:
+        ret = wlan_cmd_wmm_queue_stats(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_WMM_TS_STATUS:
+        ret = wlan_cmd_wmm_ts_status(priv, CmdPtr, pdata_buf);
+        break;
+    case HostCmd_CMD_TX_PKT_STATS:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_TX_PKT_STATS);
+        CmdPtr->Size = wlan_cpu_to_le16(S_DS_GEN);
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_TPC_CFG:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TPC_CFG);
+        CmdPtr->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_TPC_CFG) + S_DS_GEN);
+
+        memmove(&CmdPtr->params.tpccfg,
+                pdata_buf, sizeof(HostCmd_DS_802_11_TPC_CFG));
+        CmdPtr->params.tpccfg.Action =
+            wlan_cpu_to_le16(CmdPtr->params.tpccfg.Action);
+
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_LED_CONTROL:
+        {
+            HostCmd_DS_802_11_LED_CTRL *pLedCtrl = &CmdPtr->params.ledgpio;
+            MrvlIEtypes_LedGpio_t *gpio = &pLedCtrl->LedGpio;
+            MrvlIEtypes_LedBehavior_t *pLedBehavior = pLedCtrl->LedBehavior;
+
+            memmove(&CmdPtr->params.ledgpio,
+                    pdata_buf, sizeof(HostCmd_DS_802_11_LED_CTRL));
+
+            CmdPtr->Command =
+                wlan_cpu_to_le16(HostCmd_CMD_802_11_LED_CONTROL);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+            CmdPtr->Size = wlan_cpu_to_le16(gpio->Header.Len + S_DS_GEN
+                                            +
+                                            ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+
+            pLedCtrl->Action = wlan_cpu_to_le16(pLedCtrl->Action);
+            pLedCtrl->LedNums = wlan_cpu_to_le16(pLedCtrl->LedNums);
+
+            gpio->Header.Type = wlan_cpu_to_le16(gpio->Header.Type);
+            gpio->Header.Len = wlan_cpu_to_le16(gpio->Header.Len);
+
+            pLedBehavior->Header.Type =
+                wlan_cpu_to_le16(pLedBehavior->Header.Type);
+            pLedBehavior->Header.Len =
+                wlan_cpu_to_le16(pLedBehavior->Header.Len);
+
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        }
+    case HostCmd_CMD_802_11_SLEEP_PERIOD:
+        ret = wlan_cmd_802_11_sleep_period(priv, CmdPtr,
+                                           cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_802_11_CRYPTO:
+        ret = wlan_cmd_802_11_crypto(priv, CmdPtr, cmd_action, pdata_buf);
+        break;
+    case HostCmd_CMD_GET_TSF:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_TSF);
+        CmdPtr->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_TSF)
+                                        + S_DS_GEN);
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_TX_RATE_QUERY:
+        CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+        CmdPtr->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_TX_RATE_QUERY) + S_DS_GEN);
+        Adapter->TxRate = 0;
+        ret = WLAN_STATUS_SUCCESS;
+        break;
+    case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+        ret =
+            wlan_cmd_ibss_coalescing_status(priv, CmdPtr, cmd_action,
+                                            pdata_buf);
+        break;
+
+    case HostCmd_CMD_SDIO_PULL_CTRL:
+        {
+            HostCmd_DS_SDIO_PULL_CTRL *pSdiopullctl =
+                &CmdPtr->params.sdiopullctl;
+
+            CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_SDIO_PULL_CTRL);
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_SDIO_PULL_CTRL) +
+                                 S_DS_GEN);
+
+            memcpy(pSdiopullctl, pdata_buf,
+                   sizeof(HostCmd_DS_SDIO_PULL_CTRL));
+            pSdiopullctl->Action = wlan_cpu_to_le16(pSdiopullctl->Action);
+            pSdiopullctl->PullUp = wlan_cpu_to_le16(pSdiopullctl->PullUp);
+            pSdiopullctl->PullDown = wlan_cpu_to_le16(pSdiopullctl->PullDown);
+
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        }
+
+    case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+        {
+            HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *pSysclockcfg =
+                &CmdPtr->params.sysclockcfg;
+
+            CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG) +
+                                 S_DS_GEN);
+
+            memcpy(pSysclockcfg, pdata_buf,
+                   sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG));
+            pSysclockcfg->Action = wlan_cpu_to_le16(pSysclockcfg->Action);
+            pSysclockcfg->SystemClock =
+                wlan_cpu_to_le16(pSysclockcfg->SystemClock);
+            break;
+        }
+
+    case HostCmd_CMD_MODULE_TYPE_CONFIG:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        CmdPtr->Size =
+            wlan_cpu_to_le16(sizeof(HostCmd_DS_MODULE_TYPE_CONFIG) +
+                             S_DS_GEN);
+        memcpy(&CmdPtr->params.moduletypecfg, pdata_buf,
+               sizeof(HostCmd_DS_MODULE_TYPE_CONFIG));
+        CmdPtr->params.moduletypecfg.Action =
+            wlan_cpu_to_le16(CmdPtr->params.moduletypecfg.Action);
+        CmdPtr->params.moduletypecfg.Module =
+            wlan_cpu_to_le16(CmdPtr->params.moduletypecfg.Module);
+        break;
+
+    case HostCmd_CMD_VERSION_EXT:
+        CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+        memcpy(&CmdPtr->params, pdata_buf, sizeof(HostCmd_DS_VERSION_EXT));
+        CmdPtr->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_VERSION_EXT)
+                                        + S_DS_GEN);
+        break;
+    case HostCmd_CMD_MEF_CFG:
+        {
+            MEF_CFG_DATA *pMefData = (MEF_CFG_DATA *) pdata_buf;
+            CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+            memcpy(&CmdPtr->params, (u8 *) & pMefData->data, pMefData->size);
+            CmdPtr->Size = wlan_cpu_to_le16(pMefData->size + S_DS_GEN);
+            CmdPtr->params.mefcfg.Criteria =
+                wlan_cpu_to_le32(CmdPtr->params.mefcfg.Criteria);
+            CmdPtr->params.mefcfg.NumEntries =
+                wlan_cpu_to_le16(CmdPtr->params.mefcfg.NumEntries);
+        }
+        break;
+    case HostCmd_CMD_DBGS_CFG:
+        {
+            DBGS_CFG_DATA *pDbgCfg = (DBGS_CFG_DATA *) pdata_buf;
+            CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+            memcpy(&CmdPtr->params, (u8 *) & pDbgCfg->data, pDbgCfg->size);
+            CmdPtr->Size = wlan_cpu_to_le16(pDbgCfg->size + S_DS_GEN);
+        }
+        break;
+    case HostCmd_CMD_GET_MEM:
+        {
+            FW_MEM_DATA *pFwData = (FW_MEM_DATA *) pdata_buf;
+            CmdPtr->Command = wlan_cpu_to_le16(cmd_no);
+            memcpy(&CmdPtr->params, (u8 *) & pFwData->data,
+                   sizeof(HostCmd_DS_GET_MEM));
+            CmdPtr->Size =
+                wlan_cpu_to_le16(sizeof(HostCmd_DS_GET_MEM) + S_DS_GEN);
+        }
+        break;
+
+    default:
+        PRINTM(INFO, "PREP_CMD: unknown command- %#x\n", cmd_no);
+        ret = WLAN_STATUS_FAILURE;
+        break;
+    }
+
+    /* return error, since the command preparation failed */
+    if (ret != WLAN_STATUS_SUCCESS) {
+        PRINTM(ERROR, "PREP_CMD: Command 0x%x preparation failed\n", cmd_no);
+        wlan_insert_cmd_to_free_q(priv, CmdNode);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    PRINTM(CMND, "PREP_CMD: 0x%x\n", cmd_no);
+
+    CmdNode->CmdWaitQWoken = FALSE;
+    wlan_insert_cmd_to_pending_q(Adapter, CmdNode, TRUE);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+    if (wait_option & HostCmd_OPTION_WAITFORRSP) {
+        PRINTM(INFO, "PREP_CMD: Wait for CMD response...\n");
+        if (wait_option & HostCmd_OPTION_TIMEOUT) {
+            if (!os_wait_interruptible_timeout
+                (CmdNode->cmdwait_q, CmdNode->CmdWaitQWoken,
+                 MRVDRV_TIMER_10S)) {
+                PRINTM(INFO, "PREP_CMD:Timeout ...\n");
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+        } else
+            wait_event_interruptible(CmdNode->cmdwait_q,
+                                     CmdNode->CmdWaitQWoken);
+
+        if (Adapter->CurCmdRetCode) {
+            PRINTM(INFO, "PREP_CMD: Command failed with return code=%d\n",
+                   Adapter->CurCmdRetCode);
+            Adapter->CurCmdRetCode = 0;
+            ret = WLAN_STATUS_FAILURE;
+        }
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function allocates the command buffer and link
+ *  it to command free queue.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_alloc_cmd_buffer(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u32 ulBufSize;
+    u32 i;
+    CmdCtrlNode *TempCmdArray;
+    u8 *pTempVirtualAddr;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* Allocate and initialize CmdCtrlNode */
+    ulBufSize = sizeof(CmdCtrlNode) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+    if (!(TempCmdArray = kmalloc(ulBufSize, GFP_KERNEL))) {
+        PRINTM(INFO, "ALLOC_CMD_BUF: Failed to allocate TempCmdArray\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    Adapter->CmdArray = TempCmdArray;
+    memset(Adapter->CmdArray, 0, ulBufSize);
+
+    /* Allocate and initialize command buffers */
+    ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER;
+    for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+        if (!(pTempVirtualAddr = kmalloc(ulBufSize, GFP_KERNEL))) {
+            PRINTM(INFO, "ALLOC_CMD_BUF: pTempVirtualAddr: out of memory\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        memset(pTempVirtualAddr, 0, ulBufSize);
+
+        /* Update command buffer virtual */
+        TempCmdArray[i].BufVirtualAddr = pTempVirtualAddr;
+    }
+
+    for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+        init_waitqueue_head(&TempCmdArray[i].cmdwait_q);
+        wlan_insert_cmd_to_free_q(priv, &TempCmdArray[i]);
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function frees the command buffer.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_free_cmd_buffer(wlan_private * priv)
+{
+    u32 ulBufSize;
+    UINT i;
+    CmdCtrlNode *TempCmdArray;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* need to check if cmd array is allocated or not */
+    if (Adapter->CmdArray == NULL) {
+        PRINTM(INFO, "FREE_CMD_BUF: CmdArray is Null\n");
+        goto done;
+    }
+
+    TempCmdArray = Adapter->CmdArray;
+
+    /* Release shared memory buffers */
+    ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER;
+    for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+        if (TempCmdArray[i].BufVirtualAddr) {
+            PRINTM(INFO, "Free all the array\n");
+            kfree(TempCmdArray[i].BufVirtualAddr);
+            TempCmdArray[i].BufVirtualAddr = NULL;
+        }
+    }
+
+    /* Release CmdCtrlNode */
+    if (Adapter->CmdArray) {
+        PRINTM(INFO, "Free CmdArray\n");
+        kfree(Adapter->CmdArray);
+        Adapter->CmdArray = NULL;
+    }
+
+  done:
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function gets a free command node if available in
+ *  command free queue.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @return CmdCtrlNode A pointer to CmdCtrlNode structure or NULL
+ */
+CmdCtrlNode *
+wlan_get_cmd_node(wlan_private * priv)
+{
+    CmdCtrlNode *TempNode;
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+
+    ENTER();
+
+    if (!Adapter)
+        return NULL;
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+
+    if (!list_empty(&Adapter->CmdFreeQ)) {
+        TempNode = (CmdCtrlNode *) Adapter->CmdFreeQ.next;
+        list_del((struct list_head *) TempNode);
+    } else {
+        PRINTM(WARN, "GET_CMD_NODE: CmdCtrlNode is not available\n");
+        TempNode = NULL;
+    }
+
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    LEAVE();
+    return TempNode;
+}
+
+/** 
+ *  @brief This function cleans command node.
+ *  
+ *  @param pTempNode	A pointer to CmdCtrlNode structure
+ *  @return 		n/a
+ */
+void
+wlan_clean_cmd_node(CmdCtrlNode * pTempNode)
+{
+    ENTER();
+
+    if (!pTempNode)
+        return;
+    pTempNode->CmdWaitQWoken = TRUE;
+    if (pTempNode->wait_option & HostCmd_OPTION_WAITFORRSP) {
+        wake_up_interruptible(&pTempNode->cmdwait_q);
+    }
+    pTempNode->Status = 0;
+    pTempNode->cmd_oid = (WLAN_OID) 0;
+    pTempNode->wait_option = 0;
+    pTempNode->CmdFlags = 0;
+    pTempNode->pdata_buf = NULL;
+
+    if (pTempNode->BufVirtualAddr != NULL)
+        memset(pTempNode->BufVirtualAddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function initializes the command node.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param pTempNode	A pointer to CmdCtrlNode structure
+ *  @param cmd_oid	cmd oid: treated as sub command
+ *  @param wait_option	wait option: wait response or not
+ *  @param pdata_buf	A pointer to informaion buffer
+ *  @return 		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+void
+wlan_init_cmd_node(wlan_private * priv,
+                   CmdCtrlNode * pTempNode,
+                   WLAN_OID cmd_oid, u16 wait_option, void *pdata_buf)
+{
+    ENTER();
+
+    if (!pTempNode)
+        return;
+
+    pTempNode->cmd_oid = cmd_oid;
+    pTempNode->wait_option = wait_option;
+    pTempNode->pdata_buf = pdata_buf;
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function executes next command in command
+ *  pending queue. It will put fimware back to PS mode
+ *  if applicable.
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_exec_next_cmd(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    CmdCtrlNode *CmdNode = NULL;
+    HostCmd_DS_COMMAND *CmdPtr;
+    ulong flags;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!Adapter) {
+        PRINTM(MSG, "EXEC_NEXT_CMD: Adapter is NULL\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+
+    if (Adapter->CurCmd) {
+        PRINTM(MSG, "EXEC_NEXT_CMD: there is command in processing!\n");
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (!list_empty(&Adapter->CmdPendingQ)) {
+        CmdNode = (CmdCtrlNode *)
+            Adapter->CmdPendingQ.next;
+    }
+
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+    if (CmdNode) {
+        CmdPtr = (HostCmd_DS_COMMAND *) CmdNode->BufVirtualAddr;
+
+        if (wlan_is_cmd_allowed_in_ps(CmdPtr->Command)) {
+            if ((Adapter->PSState == PS_STATE_SLEEP)
+                || (Adapter->PSState == PS_STATE_PRE_SLEEP)
+                ) {
+                PRINTM(INFO,
+                       "EXEC_NEXT_CMD: Cannot send cmd 0x%x in PSState %d\n",
+                       CmdPtr->Command, Adapter->PSState);
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            PRINTM(INFO, "EXEC_NEXT_CMD: OK to send command "
+                   "0x%x in PSState %d\n", CmdPtr->Command, Adapter->PSState);
+        } else if (Adapter->PSState != PS_STATE_FULL_POWER) {
+            /*
+             * 1. Non-PS command: 
+             * Queue it. set NeedToWakeup to TRUE if current state 
+             * is SLEEP, otherwise call wlan_exit_ps to send Exit_PS.
+             * 2. PS command but not Exit_PS: 
+             * Ignore it.
+             * 3. PS command Exit_PS:
+             * Set NeedToWakeup to TRUE if current state is SLEEP, 
+             * otherwise send this command down to firmware
+             * immediately.
+             */
+            if (CmdPtr->Command !=
+                wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE)) {
+                /*  Prepare to send Exit PS,
+                 *  this non PS command will be sent later */
+                if ((Adapter->PSState == PS_STATE_SLEEP)
+                    || (Adapter->PSState == PS_STATE_PRE_SLEEP)
+                    ) {
+                    /* w/ new scheme, it will not reach here.
+                       since it is blocked in main_thread. */
+                    Adapter->NeedToWakeup = TRUE;
+                } else
+                    wlan_exit_ps(priv, 0);
+
+                ret = WLAN_STATUS_SUCCESS;
+                goto done;
+            } else {
+                /*
+                 * PS command. Ignore it if it is not Exit_PS. 
+                 * otherwise send it down immediately.
+                 */
+                HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode;
+
+                PRINTM(INFO, "EXEC_NEXT_CMD: PS cmd- Action=0x%x\n",
+                       psm->Action);
+                if (psm->Action != wlan_cpu_to_le16(HostCmd_SubCmd_Exit_PS)) {
+                    PRINTM(INFO, "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+                    list_del((struct list_head *) CmdNode);
+                    wlan_insert_cmd_to_free_q(priv, CmdNode);
+
+                    ret = WLAN_STATUS_SUCCESS;
+                    goto done;
+                }
+
+                if ((Adapter->PSState == PS_STATE_SLEEP)
+                    || (Adapter->PSState == PS_STATE_PRE_SLEEP)
+                    ) {
+                    PRINTM(INFO,
+                           "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+                    list_del((struct list_head *) CmdNode);
+                    wlan_insert_cmd_to_free_q(priv, CmdNode);
+                    Adapter->NeedToWakeup = TRUE;
+
+                    ret = WLAN_STATUS_SUCCESS;
+                    goto done;
+                }
+
+                PRINTM(INFO, "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+            }
+        }
+        list_del((struct list_head *) CmdNode);
+        wlan_dnld_cmd_to_fw(priv, CmdNode);
+    } else {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            /*
+             * check if in power save mode, if yes, put the device back
+             * to PS mode
+             */
+            if ((Adapter->PSMode != Wlan802_11PowerModeCAM) &&
+                (Adapter->PSState == PS_STATE_FULL_POWER)) {
+                if (Adapter->SecInfo.WPAEnabled
+                    || Adapter->SecInfo.WPA2Enabled) {
+                    if (Adapter->IsGTK_SET) {
+                        PRINTM(INFO, "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+                               " go back to PS_SLEEP");
+                        wlan_enter_ps(priv, 0);
+                    }
+                } else {
+                    if ((Adapter->InfrastructureMode != Wlan802_11IBSS)
+                        || Adapter->CurBssParams.BSSDescriptor.ATIMWindow) {
+                        PRINTM(INFO, "EXEC_NEXT_CMD: Command PendQ is empty,"
+                               " go back to PS_SLEEP");
+                        wlan_enter_ps(priv, 0);
+                    }
+                }
+            }
+        } else {
+            /*
+             * check if in auto deep sleep mode, if yes, put the device back
+             * to DS mode
+             */
+            if (Adapter->IsAutoDeepSleepEnabled && !Adapter->IntCounter) {
+                PRINTM(INFO, "Entering Auto Deep Sleep mode...\n");
+                ret = wlan_prepare_cmd(priv,
+                                       HostCmd_CMD_802_11_DEEP_SLEEP, 0,
+                                       0, 0, NULL);
+            }
+        }
+        /* The hs_activate command is sent when Host Sleep is configured
+           and de-activated in full power mode. */
+        if (Adapter->bHostSleepConfigured && !Adapter->HS_Activated
+            && ((Adapter->MediaConnectStatus == WlanMediaStateConnected)
+                || (!Adapter->IsAutoDeepSleepEnabled))
+            && (((Adapter->PSMode == Wlan802_11PowerModeCAM)
+                 && (Adapter->PSState == PS_STATE_FULL_POWER))
+                || ((Adapter->InfrastructureMode == Wlan802_11IBSS)
+                    && !Adapter->CurBssParams.BSSDescriptor.ATIMWindow)
+            )) {
+            ret = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE,
+                                   0, 0, 0, NULL);
+        }
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ *  
+ *  @param FunctionContext    A pointer to FunctionContext
+ *  @return 	   n/a
+ */
+void
+wlan_cmd_timeout_func(void *FunctionContext)
+{
+    wlan_private *priv = (wlan_private *) FunctionContext;
+    wlan_adapter *Adapter = priv->adapter;
+    CmdCtrlNode *pTempNode;
+    HostCmd_DS_COMMAND *CmdPtr;
+
+    ENTER();
+
+    PRINTM(CMND, "Command timeout.\n");
+
+    Adapter->CommandTimerIsSet = FALSE;
+
+    if (!Adapter->num_cmd_timeout)
+        Adapter->dbg.num_cmd_timeout++;
+
+    pTempNode = Adapter->CurCmd;
+
+    if (pTempNode == NULL) {
+        PRINTM(INFO, "CurCmd Empty\n");
+        goto exit;
+    }
+
+    CmdPtr = (HostCmd_DS_COMMAND *) pTempNode->BufVirtualAddr;
+    if (CmdPtr == NULL) {
+        goto exit;
+    }
+
+    if (CmdPtr->Size) {
+        Adapter->dbg.TimeoutCmdId = wlan_cpu_to_le16(CmdPtr->Command);
+        Adapter->dbg.TimeoutCmdAct =
+            wlan_cpu_to_le16(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN));
+        PRINTM(CMND, "Timeout cmd = 0x%x, act = 0x%x\n",
+               Adapter->dbg.TimeoutCmdId, Adapter->dbg.TimeoutCmdAct);
+    }
+#define MAX_CMD_TIMEOUT_COUNT	5
+    Adapter->num_cmd_timeout++;
+    if (Adapter->num_cmd_timeout > MAX_CMD_TIMEOUT_COUNT) {
+        PRINTM(FATAL, "num_cmd_timeout=%d\n", Adapter->num_cmd_timeout);
+        goto exit;
+    }
+
+    /* Restart the timer to trace command response again */
+    wlan_mod_timer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_1S);
+    Adapter->CommandTimerIsSet = TRUE;
+
+    /* Wake up main thread to read int status register */
+    Adapter->IntCounter++;
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+  exit:
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function sends sleep confirm command to firmware.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param CmdPtr  A pointer to the command
+ *  @param size	   the size of command
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_dnld_sleep_confirm_cmd(wlan_private * priv, u8 * CmdPtr, u16 size)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    static u32 i = 0;
+
+    ENTER();
+
+    HEXDUMP("SLEEP_CFM", CmdPtr, size);
+
+    ret = sbi_host_to_card(priv, MV_TYPE_CMD, CmdPtr, size);
+    if (!priv->enhance_flag) {
+        priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+    }
+
+    if (ret) {
+        PRINTM(MSG, "SLEEP_CFM: sbi_host_to_card() failed\n");
+        Adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+    } else {
+        Adapter->PSState = PS_STATE_SLEEP;
+        if (Adapter->IsEnhancedPSEnabled && !Adapter->sleep_period.period       /* PPS / UAPSD not enabled */
+            )
+            Adapter->bWakeupDevRequired = TRUE;
+        if (Adapter->bHostSleepConfigured &&
+            (Adapter->sleep_period.period == 0)) {
+            Adapter->bWakeupDevRequired = TRUE;
+#define SDIO_CLK_300KHZ 300
+            //sd_set_busclock((psd_device) priv->wlan_dev.card, SDIO_CLK_300KHZ); /* set the clock to the lowest frequency */
+            wlan_host_sleep_activated_event(priv);
+        }
+#define NUM_SC_PER_LINE		16
+        if (++i % NUM_SC_PER_LINE == 0) {
+            PRINTM(EVENT, "+\n");
+        } else {
+            PRINTM(EVENT, "+");
+        }
+
+        /* check if interrupt is received after sleep confirm */
+        if (Adapter->IntCounter) {
+            PRINTM(INFO, "SLEEP_CFM: After sent, IntCnt=%d\n",
+                   Adapter->IntCounter);
+            Adapter->PSState = PS_STATE_AWAKE;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function sends Enter_PS command to firmware.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param wait_option	wait response or not
+ *  @return 	   	n/a 
+ */
+void
+wlan_enter_ps(wlan_private * priv, int wait_option)
+{
+
+    ENTER();
+
+    wlan_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE,
+                     HostCmd_SubCmd_Enter_PS, wait_option, 0, NULL);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function sends Eixt_PS command to firmware.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param wait_option	wait response or not
+ *  @return 	   	n/a 
+ */
+void
+wlan_exit_ps(wlan_private * priv, int wait_option)
+{
+    WLAN_802_11_POWER_MODE LocalPSMode;
+
+    ENTER();
+
+    LocalPSMode = Wlan802_11PowerModeCAM;
+
+    wlan_prepare_cmd(priv, HostCmd_CMD_802_11_PS_MODE,
+                     HostCmd_SubCmd_Exit_PS, wait_option, 0, &LocalPSMode);
+
+    LEAVE();
+    return;
+}
+
+/** 
+ *  @brief This function checks condition and prepares to
+ *  send sleep confirm command to firmware if ok.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param PSMode  	Power Saving mode
+ *  @return 	   	n/a 
+ */
+void
+wlan_ps_cond_check(wlan_private * priv, u16 PSMode)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd && !Adapter->IntCounter) {
+        wlan_dnld_sleep_confirm_cmd(priv, (u8 *) & Adapter->PSConfirmSleep,
+                                    sizeof(PS_CMD_ConfirmSleep));
+
+        os_start_queue(priv);
+    } else {
+        PRINTM(INFO, "Delay Sleep Confirm (%s%s%s)\n",
+               (priv->wlan_dev.dnld_sent) ? "D" : "",
+               (Adapter->CurCmd) ? "C" : "",
+               (Adapter->IntCounter) ? "I" : "");
+    }
+
+    LEAVE();
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_cmdresp.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_cmdresp.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_cmdresp.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_cmdresp.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1730 @@
+/** @file wlan_cmdresp.c
+  * @brief This file contains the handling of command
+  * responses as well as events generated by firmware.
+  *
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  *  
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/10/05: Add Doxygen format comments
+	11/11/05: Add support for WMM Status change event
+	12/13/05: Add Proprietary periodic sleep support
+	12/23/05: Fix bug in adhoc start where the current index was
+	          not properly being assigned before it was used.
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join structures.
+	          Update assoc response handling; entire IEEE response returned
+	04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+	04/10/06: Add hostcmd generic API
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	05/04/06: Add IBSS coalescing related new hostcmd response handling
+	05/08/06: Remove PermanentAddr from Adapter
+	06/08/06: Remove function HandleMICFailureEvent()
+	08/29/06: Add ledgpio private command
+********************************************************/
+
+#include	"wlan_headers.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function handles disconnect event. it
+ *  reports disconnect to upper layer, clean tx/rx packets,
+ *  reset link state etc.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void
+wlan_reset_connect_state(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    union iwreq_data wrqu;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus != WlanMediaStateConnected)
+        return;
+
+    PRINTM(INFO, "Handles disconnect event.\n");
+
+    /* Free Tx and Rx packets, report disconnect to upper layer */
+    wlan_clean_txrx(priv);
+
+    memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    /* reset SNR/NF/RSSI values */
+    memset(Adapter->SNR, 0x00, sizeof(Adapter->SNR));
+    memset(Adapter->NF, 0x00, sizeof(Adapter->NF));
+    memset(Adapter->RSSI, 0x00, sizeof(Adapter->RSSI));
+    memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
+    memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
+    Adapter->nextSNRNF = 0;
+    Adapter->numSNRNF = 0;
+    Adapter->RxPDRate = 0;
+    PRINTM(INFO, "Current SSID=%s, Ssid Length=%u\n",
+           Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid,
+           Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength);
+    PRINTM(INFO, "Previous SSID=%s, Ssid Length=%u\n",
+           Adapter->PreviousSSID.Ssid, Adapter->PreviousSSID.SsidLength);
+
+    Adapter->SecInfo.WPAEnabled = FALSE;
+    Adapter->SecInfo.WPA2Enabled = FALSE;
+    Adapter->Wpa_ie_len = 0;
+    Adapter->SecInfo.EncryptionMode = CIPHER_NONE;
+
+    Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
+    Adapter->AdhocState = ADHOC_IDLE;
+    Adapter->AdhocLinkSensed = FALSE;
+
+    /* 
+     * memorize the previous SSID and BSSID
+     * it could be used for re-assoc
+     */
+    memcpy(&Adapter->PreviousSSID,
+           &Adapter->CurBssParams.BSSDescriptor.Ssid,
+           sizeof(WLAN_802_11_SSID));
+    memcpy(Adapter->PreviousBSSID,
+           Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+
+    /* need to erase the current SSID and BSSID info */
+    memset(&Adapter->CurBssParams, 0x00, sizeof(Adapter->CurBssParams));
+
+    if (Adapter->PSState != PS_STATE_FULL_POWER) {
+        /* make firmware to exit PS mode */
+        PRINTM(INFO, "Disconnected, so exit PS mode.\n");
+        wlan_exit_ps(priv, 0);
+    }
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function handles link lost, deauth and
+ *  disassoc events.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+static void
+wlan_handle_disconnect_event(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        wlan_reset_connect_state(priv);
+#ifdef REASSOCIATION
+        if (Adapter->Reassoc_on == TRUE) {
+            PRINTM(INFO, "RE-ASSOC: trigger the timer\n");
+            Adapter->ReassocTimerIsSet = TRUE;
+            wlan_mod_timer(&Adapter->MrvDrvTimer, 0);
+        }
+#endif /* REASSOCIATION */
+    }
+}
+
+/** 
+ *  @brief This function handles the command response of reg_access
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param type	   the type of reg access (MAC, BBP or RF)
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_reg_access(wlan_private * priv, u16 type, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_offset_value *pOffsetValue =
+        (wlan_offset_value *) Adapter->CurCmd->pdata_buf;
+
+    ENTER();
+
+    switch (type) {
+    case HostCmd_CMD_MAC_REG_ACCESS:
+        {
+            HostCmd_DS_MAC_REG_ACCESS *reg;
+
+            reg = (HostCmd_DS_MAC_REG_ACCESS *) & resp->params.macreg;
+
+            pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
+            pOffsetValue->value = wlan_le32_to_cpu(reg->Value);
+            break;
+        }
+
+    case HostCmd_CMD_BBP_REG_ACCESS:
+        {
+            HostCmd_DS_BBP_REG_ACCESS *reg;
+            reg = (HostCmd_DS_BBP_REG_ACCESS *) & resp->params.bbpreg;
+
+            pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
+            pOffsetValue->value = (u8) reg->Value;
+            break;
+        }
+
+    case HostCmd_CMD_RF_REG_ACCESS:
+        {
+            HostCmd_DS_RF_REG_ACCESS *reg;
+            reg = (HostCmd_DS_RF_REG_ACCESS *) & resp->params.rfreg;
+
+            pOffsetValue->offset = wlan_le16_to_cpu(reg->Offset);
+            pOffsetValue->value = (u8) reg->Value;
+            break;
+        }
+
+    default:
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of get_hw_spec
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_get_hw_spec(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    u32 i;
+    HostCmd_DS_GET_HW_SPEC *hwspec = &resp->params.hwspec;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    Adapter->fwCapInfo = wlan_le32_to_cpu(hwspec->fwCapInfo);
+
+    if (IS_SUPPORT_MULTI_BANDS(Adapter)) {
+        Adapter->fw_bands = GET_FW_DEFAULT_BANDS(Adapter);
+        Adapter->is_multiband = 1;
+    } else {
+        Adapter->adhoc_start_band = BAND_B;
+        Adapter->fw_bands = BAND_B;
+        Adapter->is_multiband = 0;
+    }
+
+    Adapter->config_bands = Adapter->fw_bands;
+
+    if (Adapter->fw_bands & BAND_A) {
+        Adapter->adhoc_start_band = BAND_A;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL_A;
+    } else if (Adapter->fw_bands & BAND_B) {
+        Adapter->adhoc_start_band = BAND_B;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+    } else if (Adapter->fw_bands & BAND_G) {
+        Adapter->adhoc_start_band = BAND_G;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+    }
+
+    Adapter->FWReleaseNumber = wlan_le32_to_cpu(hwspec->FWReleaseNumber);
+
+    PRINTM(INFO, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+           Adapter->FWReleaseNumber);
+    PRINTM(INFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+           hwspec->PermanentAddr[0], hwspec->PermanentAddr[1],
+           hwspec->PermanentAddr[2], hwspec->PermanentAddr[3],
+           hwspec->PermanentAddr[4], hwspec->PermanentAddr[5]);
+    PRINTM(INFO, "GET_HW_SPEC: HWIfVersion=0x%X  Version=0x%X\n",
+           wlan_le16_to_cpu(hwspec->HWIfVersion),
+           wlan_le16_to_cpu(hwspec->Version));
+
+    Adapter->RegionCode = wlan_le16_to_cpu(hwspec->RegionCode);
+
+    for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+        /* use the region code to search for the index */
+        if (Adapter->RegionCode == RegionCodeToIndex[i]) {
+            break;
+        }
+    }
+
+    /* if it's unidentified region code, use the default (USA) */
+    if (i >= MRVDRV_MAX_REGION_CODE) {
+        Adapter->RegionCode = 0x10;
+        PRINTM(WARN, "unidentified region code, use the default (USA)\n");
+    }
+
+    if (Adapter->CurrentAddr[0] == 0xff) {
+        memmove(Adapter->CurrentAddr, hwspec->PermanentAddr, ETH_ALEN);
+    }
+    memcpy(priv->wlan_dev.netdev->dev_addr, Adapter->CurrentAddr, ETH_ALEN);
+
+    if (wlan_set_regiontable(priv, Adapter->RegionCode, Adapter->fw_bands)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (wlan_set_universaltable(priv, Adapter->fw_bands)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the command response of host_sleep_cfg
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_host_sleep_cfg(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_HOST_SLEEP_CFG *hscfg = &resp->params.hostsleepcfg;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (hscfg->conditions != HOST_SLEEP_CFG_CANCEL) {
+        Adapter->bHostSleepConfigured = TRUE;
+    } else {
+        Adapter->bHostSleepConfigured = FALSE;
+        if (Adapter->PSState == PS_STATE_FULL_POWER && Adapter->HS_Activated) {
+            wlan_host_sleep_deactivated_event(priv);
+        }
+        os_start_queue(priv);
+        os_carrier_on(priv);
+        wmm_start_queue(priv);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the command response of fw_wakeup_method
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_fw_wakeup_method(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_FW_WAKEUP_METHOD *fwwm = &resp->params.fwwakeupmethod;
+    u16 action;
+
+    ENTER();
+
+    action = wlan_le16_to_cpu(fwwm->Action);
+
+    switch (action) {
+    case HostCmd_ACT_GEN_GET:
+    case HostCmd_ACT_GEN_SET:
+        Adapter->fwWakeupMethod = wlan_le16_to_cpu(fwwm->Method);
+        break;
+    default:
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of sleep_params
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_sleep_params(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_SLEEP_PARAMS *sp = &resp->params.sleep_params;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
+           " extsleepclk=%x\n", sp->Error, sp->Offset,
+           sp->StableTime, sp->CalControl, sp->ExternalSleepClk);
+    Adapter->sp.sp_error = wlan_le16_to_cpu(sp->Error);
+    Adapter->sp.sp_offset = wlan_le16_to_cpu(sp->Offset);
+    Adapter->sp.sp_stabletime = wlan_le16_to_cpu(sp->StableTime);
+    Adapter->sp.sp_calcontrol = wlan_le16_to_cpu(sp->CalControl);
+    Adapter->sp.sp_extsleepclk = wlan_le16_to_cpu(sp->ExternalSleepClk);
+    Adapter->sp.sp_reserved = wlan_le16_to_cpu(sp->Reserved);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of sleep_params
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_sleep_period(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_SLEEP_PERIOD *sp_period = &resp->params.ps_sleeppd;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    Adapter->sleep_period.period = wlan_le16_to_cpu(sp_period->Period);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of bca_timeshare
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_bca_timeshare(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_BCA_TIMESHARE *bca_ts = &resp->params.bca_timeshare;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(MSG, "TrafficType=%x TimeShareInterva=%x BTTime=%x\n",
+           bca_ts->TrafficType, bca_ts->TimeShareInterval, bca_ts->BTTime);
+
+    Adapter->bca_ts.TrafficType = wlan_le16_to_cpu(bca_ts->TrafficType);
+    Adapter->bca_ts.TimeShareInterval =
+        wlan_le32_to_cpu(bca_ts->TimeShareInterval);
+    Adapter->bca_ts.BTTime = wlan_le32_to_cpu(bca_ts->BTTime);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of mac_control
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_mac_control(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of set_wep
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_set_wep(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of reset
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_reset(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+    PRINTM(INFO, "HWAC - Reset command successful\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of snmp_mib
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_snmp_mib(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_SNMP_MIB *smib = &resp->params.smib;
+    u16 OID = wlan_le16_to_cpu(smib->OID);
+    u16 QueryType = wlan_le16_to_cpu(smib->QueryType);
+
+    ENTER();
+
+    PRINTM(INFO, "SNMP_RESP: value of the OID = %x, QueryType=%x\n", OID,
+           QueryType);
+    PRINTM(INFO, "SNMP_RESP: Buf size  = %x\n",
+           wlan_le16_to_cpu(smib->BufSize));
+
+    if (QueryType == HostCmd_ACT_GEN_GET) {
+        switch (OID) {
+        case FragThresh_i:
+            priv->adapter->FragThsd =
+                wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
+            PRINTM(INFO, "SNMP_RESP: FragThsd =%u\n",
+                   priv->adapter->FragThsd);
+            break;
+        case RtsThresh_i:
+            priv->adapter->RTSThsd =
+                wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
+            PRINTM(INFO, "SNMP_RESP: RTSThsd =%u\n", priv->adapter->RTSThsd);
+            break;
+        case ShortRetryLim_i:
+            priv->adapter->TxRetryCount =
+                wlan_le16_to_cpu(*((PUSHORT) (smib->Value)));
+            PRINTM(INFO, "SNMP_RESP: TxRetryCount =%u\n",
+                   priv->adapter->RTSThsd);
+            break;
+        default:
+            break;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of radio_control
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_radio_control(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of key_material
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_key_material(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_KEY_MATERIAL *pKey = &resp->params.keymaterial;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wlan_le16_to_cpu(pKey->Action) == HostCmd_ACT_GEN_SET) {
+        if ((wlan_le16_to_cpu(pKey->KeyParamSet.KeyInfo) &
+             KEY_INFO_TKIP_MCAST)
+            || (wlan_le16_to_cpu(pKey->KeyParamSet.KeyInfo) &
+                KEY_INFO_AES_MCAST)) {
+            PRINTM(INFO, "Key: GTK is set\n");
+            Adapter->IsGTK_SET = TRUE;
+        }
+    }
+
+    memcpy(Adapter->aeskey.KeyParamSet.Key, pKey->KeyParamSet.Key,
+           sizeof(pKey->KeyParamSet.Key));
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of mac_address
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_mac_address(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_MAC_ADDRESS *MacAdd = &resp->params.macadd;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    memcpy(Adapter->CurrentAddr, MacAdd->MacAdd, ETH_ALEN);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rf_tx_power
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rf_tx_power(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 Action = wlan_le16_to_cpu(rtp->Action);
+
+    ENTER();
+
+    Adapter->TxPowerLevel = wlan_le16_to_cpu(rtp->CurrentLevel);
+
+    if (Action == HostCmd_ACT_GEN_GET) {
+        Adapter->MaxTxPowerLevel = rtp->MaxPower;
+        Adapter->MinTxPowerLevel = rtp->MinPower;
+    }
+
+    PRINTM(INFO, "Current TxPower Level = %d,Max Power=%d, Min Power=%d\n",
+           Adapter->TxPowerLevel, Adapter->MaxTxPowerLevel,
+           Adapter->MinTxPowerLevel);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rf_antenna
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rf_antenna(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RF_ANTENNA *pAntenna = &resp->params.rant;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 Action = wlan_le16_to_cpu(pAntenna->Action);
+
+    if (Action == HostCmd_ACT_GET_RX)
+        Adapter->RxAntennaMode = wlan_le16_to_cpu(pAntenna->AntennaMode);
+
+    if (Action == HostCmd_ACT_GET_TX)
+        Adapter->TxAntennaMode = wlan_le16_to_cpu(pAntenna->AntennaMode);
+
+    PRINTM(INFO, "RF_ANT_RESP: Action = 0x%x, Mode = 0x%04x\n",
+           Action, wlan_le16_to_cpu(pAntenna->AntennaMode));
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of multicast_address
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_mac_multicast_adr(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rate_adapt_rateset
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RATE_ADAPT_RATESET *rates = &resp->params.rateset;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wlan_le16_to_cpu(rates->Action) == HostCmd_ACT_GEN_GET) {
+        Adapter->HWRateDropMode = wlan_le16_to_cpu(rates->HWRateDropMode);
+        Adapter->Threshold = wlan_le16_to_cpu(rates->Threshold);
+        Adapter->FinalRate = wlan_le16_to_cpu(rates->FinalRate);
+        Adapter->RateBitmap = wlan_le16_to_cpu(rates->Bitmap);
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rf_channel
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rf_channel(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RF_CHANNEL *rfchannel = &resp->params.rfchannel;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 Action = wlan_le16_to_cpu(rfchannel->Action);
+    u16 newChannel = wlan_le16_to_cpu(rfchannel->CurrentChannel);
+
+    ENTER();
+
+    if (Action == HostCmd_OPT_802_11_RF_CHANNEL_GET
+        && Adapter->CurBssParams.BSSDescriptor.Channel != newChannel) {
+        PRINTM(INFO, "Channel Switch: %d to %d\n",
+               Adapter->CurBssParams.BSSDescriptor.Channel, newChannel);
+
+        /* Update the channel again */
+        Adapter->CurBssParams.BSSDescriptor.Channel = newChannel;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of rssi
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_rssi(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_RSSI_RSP *rssirsp = &resp->params.rssirsp;
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* store the non average value */
+    Adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = wlan_le16_to_cpu(rssirsp->SNR);
+    Adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+        wlan_le16_to_cpu(rssirsp->NoiseFloor);
+
+    Adapter->SNR[TYPE_BEACON][TYPE_AVG] = wlan_le16_to_cpu(rssirsp->AvgSNR);
+    Adapter->NF[TYPE_BEACON][TYPE_AVG] =
+        wlan_le16_to_cpu(rssirsp->AvgNoiseFloor);
+
+    Adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                 Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+    Adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+                 Adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+    PRINTM(INFO, "Beacon RSSI value = 0x%x\n",
+           Adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/** 
+ *  @brief This function handles the command response of mfg_cmd
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_mfg_cmd(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "MFG command response size = %d\n", resp->Size);
+
+    resp->Size = MIN(resp->Size, MRVDRV_SIZE_OF_CMD_BUFFER);
+    memcpy(Adapter->CurCmd->pdata_buf, (void *) resp, resp->Size);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+#endif /* MFG_CMD_SUPPORT */
+
+/** 
+ *  @brief This function handles the command response of cal_data_ext.
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param resp		A pointer to HostCmd_DS_COMMAND
+ *  @return    		WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_802_11_cal_data_ext(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_CAL_DATA_EXT *pCalDataExt = &resp->params.caldataext;
+
+    ENTER();
+
+    if (wlan_le16_to_cpu(pCalDataExt->Action) == HostCmd_ACT_GEN_GET) {
+        pCalDataExt->Action = wlan_le16_to_cpu(pCalDataExt->Action);
+        pCalDataExt->Revision = wlan_le16_to_cpu(pCalDataExt->Revision);
+        pCalDataExt->CalDataLen = wlan_le16_to_cpu(pCalDataExt->CalDataLen);
+
+        memmove(Adapter->CurCmd->pdata_buf,
+                pCalDataExt, pCalDataExt->CalDataLen + CAL_DATA_HEADER_LEN);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of eeprom_access
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_eeprom_access(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_regrdwr *pBuf =
+        (wlan_ioctl_regrdwr *) Adapter->CurCmd->pdata_buf;
+
+    PRINTM(INFO, "eeprom read len=%x\n",
+           wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount));
+    if (pBuf->NOB < wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)) {
+        pBuf->NOB = 0;
+        PRINTM(INFO, "eeprom read return length is too big\n");
+        return WLAN_STATUS_FAILURE;
+    }
+    pBuf->NOB = wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount);
+    if (pBuf->NOB > 0) {
+        memcpy(&pBuf->Value, (u8 *) & resp->params.rdeeprom.Value, pBuf->NOB);
+        HEXDUMP("EEPROM", (char *) &pBuf->Value, pBuf->NOB);
+    }
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of get_log
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_get_log(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_GET_LOG *LogMessage =
+        (HostCmd_DS_802_11_GET_LOG *) & resp->params.glog;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    memcpy(&Adapter->LogMsg, LogMessage, sizeof(HostCmd_DS_802_11_GET_LOG));
+    endian_convert_GET_LOG(Adapter->LogMsg);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the command response of crypto
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp	   A pointer to HostCmd_DS_COMMAND
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_ret_cmd_802_11_crypto(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_CRYPTO *crypto = &resp->params.crypto;
+    MrvlIEtypes_Data_t *data =
+        (MrvlIEtypes_Data_t *) ((u8 *) crypto +
+                                sizeof(HostCmd_DS_802_11_CRYPTO));
+
+    data->Header.Type = wlan_le16_to_cpu(data->Header.Type);
+    data->Header.Len = wlan_le16_to_cpu(data->Header.Len);
+
+    crypto->EncDec = wlan_le16_to_cpu(crypto->EncDec);
+    crypto->Algorithm = wlan_le16_to_cpu(crypto->Algorithm);
+    crypto->KeyIVLength = wlan_le16_to_cpu(crypto->KeyIVLength);
+    crypto->KeyLength = wlan_le16_to_cpu(crypto->KeyLength);
+
+    memmove(Adapter->CurCmd->pdata_buf, crypto,
+            sizeof(HostCmd_DS_802_11_CRYPTO) + data->Header.Len +
+            sizeof(MrvlIEtypesHeader_t));
+
+    return WLAN_STATUS_SUCCESS;
+
+}
+
+static void
+wlan_ret_ibss_coalescing_status(wlan_private * priv,
+                                HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_802_11_IBSS_Status *IBSSStatusRsp;
+    wlan_adapter *Adapter;
+    union iwreq_data wrqu;
+    u8 nullMac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+    Adapter = priv->adapter;
+    IBSSStatusRsp = &(resp->params.ibssCoalescing);
+
+    if (Adapter->CurCmd->pdata_buf)
+        *(int *) Adapter->CurCmd->pdata_buf = IBSSStatusRsp->Enable;
+
+    if (wlan_le16_to_cpu(IBSSStatusRsp->Action) == HostCmd_ACT_GEN_SET) {
+        return;
+    }
+
+    PRINTM(INFO, "New BSSID %x:%x:%x:%x:%x:%x\n",
+           IBSSStatusRsp->BSSID[0],
+           IBSSStatusRsp->BSSID[1],
+           IBSSStatusRsp->BSSID[2],
+           IBSSStatusRsp->BSSID[3],
+           IBSSStatusRsp->BSSID[4], IBSSStatusRsp->BSSID[5]);
+
+    /* if rsp has NULL BSSID, Just return.. No Action */
+    if (!memcmp(IBSSStatusRsp->BSSID, nullMac, ETH_ALEN)) {
+        PRINTM(MSG, "New BSSID is NULL\n");
+        return;
+    }
+
+    /* if BSSID is diff, Send evnet to Linux */
+    if (memcmp(Adapter->CurBssParams.BSSDescriptor.MacAddress,
+               IBSSStatusRsp->BSSID, ETH_ALEN)) {
+        memcpy((void *) Adapter->CurBssParams.BSSDescriptor.MacAddress,
+               (void *) IBSSStatusRsp->BSSID, ETH_ALEN);
+
+        /* Beacon Interval and ATIM window */
+        Adapter->CurBssParams.BSSDescriptor.BeaconPeriod
+            = IBSSStatusRsp->BeaconInterval;
+        Adapter->CurBssParams.BSSDescriptor.ATIMWindow
+            = IBSSStatusRsp->ATIMWindow;
+        //ERP Information
+        Adapter->CurBssParams.BSSDescriptor.ERPFlags =
+            (u8) IBSSStatusRsp->UseGRateProtection;
+
+        memset(&wrqu, 0, sizeof(wrqu));
+        memcpy(wrqu.ap_addr.sa_data,
+               Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+        Adapter->AdhocState = ADHOC_COALESCED;
+        wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+    }
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function stop tx/rx queue and free skb
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+void
+wlan_clean_txrx(wlan_private * priv)
+{
+    ENTER();
+    os_stop_queue(priv);
+    os_carrier_off(priv);
+
+    wmm_stop_queue(priv);
+    wmm_cleanup_queues(priv);
+
+    /* Free Tx and Rx packets */
+    os_free_tx_packet(priv);
+    LEAVE();
+}
+
+/** 
+ *  @brief This function handles the command response
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_process_cmdresp(wlan_private * priv)
+{
+    u16 RespCmdOrig;
+    u16 RespCmd;
+    HostCmd_DS_COMMAND *resp;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    ulong flags;
+    u16 Result;
+
+    ENTER();
+
+    /* Now we got response from FW, cancel the command timer */
+    if (Adapter->CommandTimerIsSet) {
+        wlan_cancel_timer(&Adapter->MrvDrvCommandTimer);
+        Adapter->CommandTimerIsSet = FALSE;
+    }
+
+    if (!Adapter->CurCmd) {
+        resp = (HostCmd_DS_COMMAND *) priv->wlan_dev.upld_buf;
+        resp->Command = wlan_le16_to_cpu(resp->Command);
+        PRINTM(ERROR, "CMD_RESP: NULL CurCmd, 0x%x\n", resp->Command);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    Adapter->num_cmd_timeout = 0;
+
+    DBG_HEXDUMP(CMD_D, "CMD_RESP", Adapter->CurCmd->BufVirtualAddr,
+                priv->wlan_dev.upld_len);
+
+    resp = (HostCmd_DS_COMMAND *) (Adapter->CurCmd->BufVirtualAddr);
+
+    resp->Command = wlan_le16_to_cpu(resp->Command);
+    resp->Size = wlan_le16_to_cpu(resp->Size);
+    resp->SeqNum = wlan_le16_to_cpu(resp->SeqNum);
+    resp->Result = wlan_le16_to_cpu(resp->Result);
+
+    RespCmdOrig = resp->Command;
+    Result = resp->Result;
+
+    /* Save the last command response to debug log */
+    Adapter->dbg.LastCmdRespIndex =
+        (Adapter->dbg.LastCmdRespIndex + 1) % DBG_CMD_NUM;
+    Adapter->dbg.LastCmdRespId[Adapter->dbg.LastCmdRespIndex] = RespCmdOrig;
+
+    PRINTM(CMND, "CMD_RESP: 0x%x, result %d, len %d, seqno %d @ %lu\n",
+           RespCmdOrig, Result, resp->Size, resp->SeqNum, os_time_get());
+
+    if (!(RespCmdOrig & HostCmd_RET_BIT)) {
+        PRINTM(ERROR, "CMD_RESP: Invalid response to command!");
+        Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
+        wlan_insert_cmd_to_free_q(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Clear the HostCmd_RET_BIT */
+    resp->Command &= ~HostCmd_RET_BIT;
+    RespCmd = resp->Command;
+
+    /* Store the response code to CurCmdRetCode. */
+    Adapter->CurCmdRetCode = resp->Result;
+
+    if (RespCmd == HostCmd_CMD_802_11_PS_MODE) {
+        HostCmd_DS_802_11_PS_MODE *psmode;
+
+        psmode = &resp->params.psmode;
+        PRINTM(INFO, "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+               resp->Result, psmode->Action);
+        psmode->Action = wlan_cpu_to_le16(psmode->Action);
+
+        if (Result) {
+            PRINTM(ERROR, "CMD_RESP: PS command failed- %#x \n",
+                   resp->Result);
+            if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+                /* 
+                 * We should not re-try enter-ps command in 
+                 * ad-hoc mode. It takes place in 
+                 * wlan_exec_next_cmd().
+                 */
+                if (psmode->Action == HostCmd_SubCmd_Enter_PS)
+                    Adapter->PSMode = Wlan802_11PowerModeCAM;
+            }
+        } else if (psmode->Action == HostCmd_SubCmd_Enter_PS) {
+            Adapter->NeedToWakeup = FALSE;
+            Adapter->PSState = PS_STATE_AWAKE;
+            if (Adapter->MediaConnectStatus != WlanMediaStateConnected) {
+                /*
+                 * When Deauth Event received before Enter_PS command
+                 * response, We need to wake up the firmware.
+                 */
+                PRINTM(INFO,
+                       "CMD_RESP: Disconnected, Going to invoke wlan_exit_ps\n");
+                wlan_exit_ps(priv, 0);
+            }
+        } else if (psmode->Action == HostCmd_SubCmd_Exit_PS) {
+            Adapter->NeedToWakeup = FALSE;
+            Adapter->PSState = PS_STATE_FULL_POWER;
+        } else {
+            PRINTM(INFO, "CMD_RESP: PS- Action=0x%X\n", psmode->Action);
+        }
+
+        wlan_insert_cmd_to_free_q(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+        ret = WLAN_STATUS_SUCCESS;
+        goto done;
+    }
+
+    if (Adapter->CurCmd->CmdFlags & CMD_F_HOSTCMD) {
+        /* Copy the response back to response buffer */
+        memcpy(Adapter->CurCmd->pdata_buf, resp, resp->Size);
+
+        Adapter->CurCmd->CmdFlags &= ~CMD_F_HOSTCMD;
+
+        if ((Result == HostCmd_RESULT_OK)
+            && (RespCmd == HostCmd_CMD_802_11_HOST_SLEEP_CFG)) {
+            ret = wlan_ret_host_sleep_cfg(priv, resp);
+        }
+    } else {
+        /* If the command is not successful, cleanup and return failure */
+        if (Result != HostCmd_RESULT_OK) {
+            PRINTM(ERROR, "CMD_RESP: cmd %#x error, result=%#x\n",
+                   resp->Command, resp->Result);
+            /*
+             * Handling errors here
+             */
+            switch (RespCmd) {
+            case HostCmd_CMD_GET_HW_SPEC:
+                PRINTM(INFO, "CMD_RESP: HW spec command Failed\n");
+                break;
+
+            }
+
+            wlan_insert_cmd_to_free_q(priv, Adapter->CurCmd);
+            spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+            Adapter->CurCmd = NULL;
+            spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+            return WLAN_STATUS_FAILURE;
+        }
+
+        switch (RespCmd) {
+        case HostCmd_CMD_MAC_REG_ACCESS:
+        case HostCmd_CMD_BBP_REG_ACCESS:
+        case HostCmd_CMD_RF_REG_ACCESS:
+            ret = wlan_ret_reg_access(priv, RespCmd, resp);
+            break;
+
+        case HostCmd_CMD_GET_HW_SPEC:
+            ret = wlan_ret_get_hw_spec(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+            {
+                union iwreq_data wrqu;
+
+                ret = wlan_ret_802_11_scan(priv, resp);
+                memset(&wrqu, 0, sizeof(union iwreq_data));
+                wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                    NULL);
+                PRINTM(INFO, "CMD_RESP: BG_SCAN result is ready!\n");
+                break;
+            }
+        case HostCmd_CMD_802_11_SCAN:
+            ret = wlan_ret_802_11_scan(priv, resp);
+            break;
+
+        case HostCmd_CMD_MAC_CONTROL:
+            ret = wlan_ret_mac_control(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_GET_LOG:
+            ret = wlan_ret_get_log(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_ASSOCIATE:
+            ret = wlan_ret_802_11_associate(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_DEAUTHENTICATE:
+            ret = wlan_ret_802_11_deauthenticate(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_SET_WEP:
+            ret = wlan_ret_802_11_set_wep(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_AD_HOC_START:
+        case HostCmd_CMD_802_11_AD_HOC_JOIN:
+            ret = wlan_ret_802_11_ad_hoc(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_RESET:
+            ret = wlan_ret_802_11_reset(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_SNMP_MIB:
+            ret = wlan_ret_802_11_snmp_mib(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_RF_TX_POWER:
+            ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_RADIO_CONTROL:
+            ret = wlan_ret_802_11_radio_control(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_HOST_SLEEP_CFG:
+            ret = wlan_ret_host_sleep_cfg(priv, resp);
+            break;
+        case HostCmd_CMD_802_11_WAKEUP_CONFIRM:
+            wlan_host_sleep_deactivated_event(priv);
+            break;
+        case HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE:
+            if (Adapter->bHostSleepConfigured
+                && Adapter->HSCfg.gap == HOST_SLEEP_CFG_GAP_FF)
+                Adapter->bWakeupDevRequired = TRUE;
+            wlan_host_sleep_activated_event(priv);
+            break;
+
+        case HostCmd_CMD_802_11_RF_ANTENNA:
+            ret = wlan_ret_802_11_rf_antenna(priv, resp);
+            break;
+
+        case HostCmd_CMD_MAC_MULTICAST_ADR:
+            ret = wlan_ret_mac_multicast_adr(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_RATE_ADAPT_RATESET:
+            ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+            break;
+        case HostCmd_CMD_802_11_RF_CHANNEL:
+            ret = wlan_ret_802_11_rf_channel(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_RSSI:
+            ret = wlan_ret_802_11_rssi(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_MAC_ADDRESS:
+            ret = wlan_ret_802_11_mac_address(priv, resp);
+            break;
+
+#ifdef MFG_CMD_SUPPORT
+        case HostCmd_CMD_MFG_COMMAND:
+            ret = wlan_ret_mfg_cmd(priv, resp);
+            break;
+#endif
+        case HostCmd_CMD_802_11_AD_HOC_STOP:
+            ret = wlan_ret_802_11_ad_hoc_stop(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_CAL_DATA_EXT:
+            ret = wlan_ret_802_11_cal_data_ext(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_KEY_MATERIAL:
+            ret = wlan_ret_802_11_key_material(priv, resp);
+            break;
+        case HostCmd_CMD_802_11_EEPROM_ACCESS:
+            ret = wlan_ret_802_11_eeprom_access(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11D_DOMAIN_INFO:
+            ret = wlan_ret_802_11d_domain_info(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
+        case HostCmd_CMD_802_11_TPC_INFO:
+        case HostCmd_CMD_802_11_CHAN_SW_ANN:
+            ret = wlan_11h_cmdresp_process(priv, resp);
+            break;
+        case HostCmd_CMD_MEASUREMENT_REQUEST:
+        case HostCmd_CMD_MEASUREMENT_REPORT:
+            ret = wlan_meas_cmdresp_process(priv, resp);
+            break;
+        case HostCmd_CMD_802_11_SLEEP_PARAMS:
+            ret = wlan_ret_802_11_sleep_params(priv, resp);
+            break;
+        case HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE:
+            ret = wlan_ret_802_11_bca_timeshare(priv, resp);
+            break;
+        case HostCmd_CMD_802_11_INACTIVITY_TIMEOUT:
+            *((u16 *) Adapter->CurCmd->pdata_buf) =
+                wlan_le16_to_cpu(resp->params.inactivity_timeout.Timeout);
+            break;
+        case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+            break;
+
+        case HostCmd_CMD_802_11_FW_WAKE_METHOD:
+            ret = wlan_ret_fw_wakeup_method(priv, resp);
+            break;
+
+        case HostCmd_CMD_802_11_SLEEP_PERIOD:
+            ret = wlan_ret_802_11_sleep_period(priv, resp);
+            break;
+        case HostCmd_CMD_WMM_GET_STATUS:
+            ret = wlan_cmdresp_wmm_get_status(priv, resp);
+            break;
+        case HostCmd_CMD_WMM_ADDTS_REQ:
+            ret = wlan_cmdresp_wmm_addts_req(priv, resp);
+            break;
+        case HostCmd_CMD_WMM_DELTS_REQ:
+            ret = wlan_cmdresp_wmm_delts_req(priv, resp);
+            break;
+        case HostCmd_CMD_WMM_QUEUE_CONFIG:
+            ret = wlan_cmdresp_wmm_queue_config(priv, resp);
+            break;
+        case HostCmd_CMD_WMM_QUEUE_STATS:
+            ret = wlan_cmdresp_wmm_queue_stats(priv, resp);
+            break;
+        case HostCmd_CMD_WMM_TS_STATUS:
+            ret = wlan_cmdresp_wmm_ts_status(priv, resp);
+            break;
+        case HostCmd_CMD_TX_PKT_STATS:
+            memcpy(Adapter->CurCmd->pdata_buf,
+                   &resp->params.txPktStats, sizeof(HostCmd_DS_TX_PKT_STATS));
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        case HostCmd_CMD_802_11_TPC_CFG:
+            memmove(Adapter->CurCmd->pdata_buf,
+                    &resp->params.tpccfg, sizeof(HostCmd_DS_802_11_TPC_CFG));
+            break;
+        case HostCmd_CMD_802_11_LED_CONTROL:
+            {
+                HostCmd_DS_802_11_LED_CTRL *pLedCtrl = &resp->params.ledgpio;
+                MrvlIEtypes_LedGpio_t *pGpio = &pLedCtrl->LedGpio;
+                MrvlIEtypes_LedBehavior_t *pBehavior = pLedCtrl->LedBehavior;
+
+                pLedCtrl->Action = wlan_le16_to_cpu(pLedCtrl->Action);
+                pLedCtrl->LedNums = wlan_le16_to_cpu(pLedCtrl->LedNums);
+                pGpio->Header.Type = wlan_le16_to_cpu(pGpio->Header.Type);
+                pGpio->Header.Len = wlan_le16_to_cpu(pGpio->Header.Len);
+                pBehavior->Header.Type =
+                    wlan_le16_to_cpu(pBehavior->Header.Type);
+                pBehavior->Header.Len =
+                    wlan_le16_to_cpu(pBehavior->Header.Len);
+                memmove(Adapter->CurCmd->pdata_buf, &resp->params.ledgpio,
+                        sizeof(HostCmd_DS_802_11_LED_CTRL));
+                break;
+            }
+        case HostCmd_CMD_802_11_CRYPTO:
+            ret = wlan_ret_cmd_802_11_crypto(priv, resp);
+            break;
+
+        case HostCmd_CMD_GET_TSF:
+            resp->params.gettsf.TsfValue =
+                wlan_le64_to_cpu(resp->params.gettsf.TsfValue);
+            memcpy(priv->adapter->CurCmd->pdata_buf,
+                   &resp->params.gettsf.TsfValue, sizeof(u64));
+            break;
+        case HostCmd_CMD_802_11_TX_RATE_QUERY:
+            priv->adapter->TxRate =
+                wlan_le16_to_cpu(resp->params.txrate.TxRate);
+            break;
+        case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+            wlan_ret_ibss_coalescing_status(priv, resp);
+            break;
+
+        case HostCmd_CMD_SDIO_PULL_CTRL:
+            memmove(Adapter->CurCmd->pdata_buf,
+                    &resp->params.sdiopullctl,
+                    sizeof(HostCmd_DS_SDIO_PULL_CTRL));
+            break;
+        case HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG:
+            {
+                int i;
+                HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG *pSysclockcfg =
+                    &resp->params.sysclockcfg;
+
+                pSysclockcfg->Action = wlan_le16_to_cpu(pSysclockcfg->Action);
+                pSysclockcfg->SystemClock =
+                    wlan_le16_to_cpu(pSysclockcfg->SystemClock);
+                pSysclockcfg->SupportedSysClockLen =
+                    wlan_le16_to_cpu(pSysclockcfg->SupportedSysClockLen);
+                for (i = 0;
+                     i <
+                     (sizeof(pSysclockcfg->SupportedSysClock) / sizeof(u16));
+                     i++)
+                    pSysclockcfg->SupportedSysClock[i] =
+                        wlan_le16_to_cpu(pSysclockcfg->SupportedSysClock[i]);
+                memmove(Adapter->CurCmd->pdata_buf, &resp->params.sysclockcfg,
+                        sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG));
+                break;
+            }
+
+        case HostCmd_CMD_MODULE_TYPE_CONFIG:
+            resp->params.moduletypecfg.Action =
+                wlan_le16_to_cpu(resp->params.moduletypecfg.Action);
+            resp->params.moduletypecfg.Module =
+                wlan_le16_to_cpu(resp->params.moduletypecfg.Module);
+            memmove(Adapter->CurCmd->pdata_buf, &resp->params.moduletypecfg,
+                    sizeof(HostCmd_DS_MODULE_TYPE_CONFIG));
+            break;
+
+        case HostCmd_CMD_VERSION_EXT:
+            memcpy(Adapter->CurCmd->pdata_buf,
+                   &resp->params.verext, sizeof(HostCmd_DS_VERSION_EXT));
+            break;
+        case HostCmd_CMD_MEF_CFG:
+            break;
+        case HostCmd_CMD_DBGS_CFG:
+            break;
+        case HostCmd_CMD_GET_MEM:
+            {
+                FW_MEM_DATA *pFwData =
+                    (FW_MEM_DATA *) Adapter->CurCmd->pdata_buf;
+                pFwData->size = resp->Size - S_DS_GEN;
+                memcpy((u8 *) & pFwData->data, &resp->params.getmem,
+                       pFwData->size);
+            }
+            break;
+        default:
+            PRINTM(INFO, "CMD_RESP: Unknown command response %#x\n",
+                   resp->Command);
+            break;
+        }
+    }
+
+    if (Adapter->CurCmd) {
+        /* Clean up and Put current command back to CmdFreeQ */
+        wlan_insert_cmd_to_free_q(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+#if WIRELESS_EXT >= 18
+/** 
+ *  @brief This function sends mic error event to application.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @para event    MIC ERROR EVENT. 
+ *  @return 	   n/a
+ */
+void
+send_mic_error_event(wlan_private * priv, u32 event)
+{
+    union iwreq_data iwrq;
+    struct iw_michaelmicfailure mic;
+
+    ENTER();
+
+    memset(&iwrq, 0, sizeof(iwrq));
+    memset(&mic, 0, sizeof(mic));
+    if (event == EVENT_MIC_ERR_UNICAST) {
+        mic.flags = IW_MICFAILURE_PAIRWISE;
+    } else {
+        mic.flags = IW_MICFAILURE_GROUP;
+    }
+
+    iwrq.data.pointer = &mic;
+    iwrq.data.length = sizeof(mic);
+
+    wireless_send_event(priv->wlan_dev.netdev, IWEVMICHAELMICFAILURE, &iwrq,
+                        (u8 *) & mic);
+
+    LEAVE();
+    return;
+}
+#endif
+
+/** 
+ *  @brief This function handles events generated by firmware
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_process_event(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    u32 eventcause = Adapter->EventCause;
+
+    ENTER();
+
+    /* Save the last event to debug log */
+    Adapter->dbg.LastEventIndex =
+        (Adapter->dbg.LastEventIndex + 1) % DBG_CMD_NUM;
+    Adapter->dbg.LastEvent[Adapter->dbg.LastEventIndex] = eventcause;
+
+    if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE)
+        PRINTM(EVENT, "EVENT: 0x%x @ %lu\n", eventcause, os_time_get());
+
+    switch (eventcause) {
+    case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+        PRINTM(INFO, "EVENT: DUMMY_HOST_WAKEUP_SIGNAL\n");
+        if (!priv->adapter->HS_Activated) {
+            PRINTM(WARN, "DUMMY_HOST_WAKEUP_SIGNAL (HS_Deactivated)\n");
+        } else {
+            wlan_host_sleep_wakeup_event(priv);
+        }
+        break;
+    case EVENT_LINK_SENSED:
+        PRINTM(INFO, "EVENT: LINK_SENSED\n");
+        Adapter->AdhocLinkSensed = TRUE;
+        os_carrier_on(priv);
+        os_start_queue(priv);
+        wmm_start_queue(priv);
+        send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED);
+        break;
+
+    case EVENT_DEAUTHENTICATED:
+        PRINTM(INFO, "EVENT: Deauthenticated\n");
+        Adapter->dbg.num_event_deauth++;
+        wlan_handle_disconnect_event(priv);
+        break;
+
+    case EVENT_DISASSOCIATED:
+        PRINTM(INFO, "EVENT: Disassociated\n");
+        Adapter->dbg.num_event_disassoc++;
+        wlan_handle_disconnect_event(priv);
+        break;
+
+    case EVENT_LINK_LOST:
+        PRINTM(INFO, "EVENT: Link lost\n");
+        Adapter->dbg.num_event_link_lost++;
+        wlan_handle_disconnect_event(priv);
+        break;
+
+    case EVENT_PS_SLEEP:
+        PRINTM(INFO, "EVENT: SLEEP\n");
+        PRINTM(EVENT, "_");
+
+        /* handle unexpected PS SLEEP event */
+        if (Adapter->PSState == PS_STATE_FULL_POWER) {
+            PRINTM(INFO, "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+            break;
+        }
+        Adapter->PSState = PS_STATE_PRE_SLEEP;
+
+        wlan_ps_cond_check(priv, (u16) Adapter->PSMode);
+        break;
+
+    case EVENT_PS_AWAKE:
+        PRINTM(INFO, "EVENT: AWAKE \n");
+        PRINTM(EVENT, "|");
+        Adapter->bWakeupDevRequired = FALSE;
+        Adapter->WakeupTries = 0;
+        sbi_reset_deepsleep_wakeup(priv);
+
+        /* handle unexpected PS AWAKE event */
+        if (Adapter->PSState == PS_STATE_FULL_POWER) {
+            PRINTM(INFO, "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+            break;
+        }
+
+        Adapter->TxLockFlag = FALSE;
+        if (TRUE == wlan_check_last_packet_indication(priv)) {
+            if (!priv->wlan_dev.dnld_sent && Adapter->gen_null_pkg) {
+                wlan_send_null_packet(priv,
+                                      MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
+                                      MRVDRV_TxPD_POWER_MGMT_LAST_PACKET);
+                Adapter->TxLockFlag = TRUE;
+            }
+        }
+
+        Adapter->PSState = PS_STATE_AWAKE;
+
+        if (Adapter->NeedToWakeup == TRUE) {
+            /*
+             * wait for the command processing to finish
+             * before resuming sending 
+             * Adapter->NeedToWakeup will be set to FALSE 
+             * in PSWakup()
+             */
+            PRINTM(INFO, "Waking up...\n");
+            wlan_exit_ps(priv, 0);
+        }
+        break;
+
+    case EVENT_DEEP_SLEEP_AWAKE:
+        sbi_reset_deepsleep_wakeup(priv);
+        PRINTM(INFO, "EVENT: DS_AWAKE\n");
+        if (priv->adapter->IsDeepSleep == TRUE) {
+            Adapter->IsDeepSleep = FALSE;
+            Adapter->bWakeupDevRequired = FALSE;
+            Adapter->WakeupTries = 0;
+            /* 
+             * For auto DS + BGS case, some delay is needed to 
+             * avoid going back to DS before getting BGS result
+             */
+            if (Adapter->IsAutoDeepSleepEnabled &&
+                Adapter->bgScanConfig->Enable)
+                os_sched_timeout(10);
+            if (!priv->enhance_flag) {
+                priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+                priv->adapter->HisRegCpy |= HIS_TxDnLdRdy;
+            }
+        }
+        send_iwevcustom_event(priv, CUS_EVT_DEEP_SLEEP_AWAKE);
+        wake_up_interruptible(&Adapter->ds_awake_q);
+        break;
+
+    case EVENT_HOST_SLEEP_AWAKE:
+        PRINTM(INFO, "EVENT: HS_AWAKE\n");
+        Adapter->bWakeupDevRequired = FALSE;
+        Adapter->WakeupTries = 0;
+        sbi_reset_deepsleep_wakeup(priv);
+        /*
+         * in BG SCAN mode w/ deep sleep, WAKE UP event
+         * will be sent first, Deep Sleep Awake will
+         * be sent later. 
+         */
+        if (priv->adapter->IsDeepSleep == TRUE) {
+            priv->adapter->IsDeepSleep = FALSE;
+            if (!priv->enhance_flag) {
+                priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+                priv->adapter->HisRegCpy |= HIS_TxDnLdRdy;
+            }
+        }
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_WAKEUP_CONFIRM,
+                               0, 0, 0, NULL);
+        break;
+
+    case EVENT_MIC_ERR_UNICAST:
+        PRINTM(INFO, "EVENT: UNICAST MIC ERROR\n");
+#if WIRELESS_EXT >= 18
+        send_mic_error_event(priv, EVENT_MIC_ERR_UNICAST);
+#else
+        send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI);
+#endif
+        break;
+
+    case EVENT_MIC_ERR_MULTICAST:
+        PRINTM(INFO, "EVENT: MULTICAST MIC ERROR\n");
+#if WIRELESS_EXT >= 18
+        send_mic_error_event(priv, EVENT_MIC_ERR_MULTICAST);
+#else
+        send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_MUL);
+#endif
+        break;
+    case EVENT_MIB_CHANGED:
+    case EVENT_INIT_DONE:
+        break;
+
+    case EVENT_ADHOC_BCN_LOST:
+        PRINTM(INFO, "EVENT: ADHOC_BCN_LOST\n");
+        Adapter->AdhocLinkSensed = FALSE;
+        wlan_clean_txrx(priv);
+        send_iwevcustom_event(priv, CUS_EVT_ADHOC_BCN_LOST);
+        break;
+
+    case EVENT_BG_SCAN_REPORT:
+        PRINTM(INFO, "EVENT: BGS_REPORT\n");
+        Adapter->bgScanConfig->Enable = FALSE;
+        ret = wlan_cmd_bgs_query(priv);
+        break;
+    case EVENT_STOP_TX:
+        PRINTM(INFO, "EVENT: Stop Tx (%#x)\n", eventcause);
+        wlan_11h_tx_disable(priv);
+        break;
+    case EVENT_START_TX:
+        PRINTM(INFO, "EVENT: Start Tx (%#x)\n", eventcause);
+        wlan_11h_tx_enable(priv);
+        break;
+    case EVENT_CHANNEL_SWITCH:
+        PRINTM(INFO, "EVENT: Channel Switch (%#x)\n", eventcause);
+
+        wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+                         HostCmd_OPT_802_11_RF_CHANNEL_GET, 0, 0, NULL);
+        break;
+    case EVENT_MEAS_REPORT_RDY:
+        PRINTM(INFO, "EVENT: Measurement Report Ready (%#x)\n", eventcause);
+        wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT,
+                         HostCmd_ACT_GEN_SET, 0, 0, NULL);
+        break;
+    case EVENT_WMM_STATUS_CHANGE:
+        PRINTM(INFO, "EVENT: WMM status changed\n");
+        ret = wlan_cmd_wmm_status_change(priv);
+        break;
+
+    case EVENT_RSSI_LOW:
+        PRINTM(INFO, "EVENT: Beacon RSSI_LOW\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW);
+        break;
+    case EVENT_SNR_LOW:
+        PRINTM(INFO, "EVENT: Beacon SNR_LOW\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW);
+        break;
+    case EVENT_MAX_FAIL:
+        PRINTM(INFO, "EVENT: MAX_FAIL\n");
+        send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL);
+        break;
+    case EVENT_RSSI_HIGH:
+        PRINTM(INFO, "EVENT: Beacon RSSI_HIGH\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH);
+        break;
+    case EVENT_SNR_HIGH:
+        PRINTM(INFO, "EVENT: Beacon SNR_HIGH\n");
+        send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH);
+        break;
+    case EVENT_DATA_RSSI_LOW:
+        PRINTM(INFO, "EVENT: Data RSSI_LOW\n");
+        send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW);
+        break;
+    case EVENT_DATA_SNR_LOW:
+        PRINTM(INFO, "EVENT: Data SNR_LOW\n");
+        send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW);
+        break;
+    case EVENT_DATA_RSSI_HIGH:
+        PRINTM(INFO, "EVENT: Data RSSI_HIGH\n");
+        send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH);
+        break;
+    case EVENT_DATA_SNR_HIGH:
+        PRINTM(INFO, "EVENT: Data SNR_HIGH\n");
+        send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH);
+        break;
+    case EVENT_IBSS_COALESCED:
+        PRINTM(INFO, "EVENT: IBSS_COALESCED\n");
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                               HostCmd_ACT_GEN_GET, 0, 0, NULL);
+
+        break;
+    default:
+        PRINTM(INFO, "EVENT: unknown event id: %#x\n", eventcause);
+        break;
+    }
+
+    Adapter->EventCause = 0;
+    LEAVE();
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_debug.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_debug.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_debug.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_debug.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,297 @@
+/** @file wlan_debug.c
+  * @brief This file contains functions for debug proc file.
+  *   
+  * (c) Copyright © 2003-2007, Marvell International Ltd.  
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	
+********************************************************/
+
+#include  "wlan_headers.h"
+
+#ifdef CONFIG_PROC_FS
+/********************************************************
+		Local Variables
+********************************************************/
+
+#define item_size(n) (sizeof ((wlan_adapter *)0)->n)
+#define item_addr(n) ((u32) &((wlan_adapter *)0)->n)
+
+#define item_dbg_size(n) (sizeof (((wlan_adapter *)0)->dbg.n))
+#define item_dbg_addr(n) ((u32) &(((wlan_adapter *)0)->dbg.n))
+
+#define item1_size(n) (sizeof ((wlan_dev_t *)0)->n)
+#define item1_addr(n) ((u32) &((wlan_dev_t *)0)->n)
+
+struct debug_data
+{
+    char name[32];
+    u32 size;
+    u32 addr;
+    u32 offset;
+};
+
+/* To debug any member of wlan_adapter or wlan_dev_t, simply add one line here.
+ */
+#define ITEMS_FROM_WLAN_DEV		1
+
+static struct debug_data items[] = {
+    {"IntCounter", item_size(IntCounter), 0, item_addr(IntCounter)},
+    {"ConnectStatus", item_size(MediaConnectStatus), 0,
+     item_addr(MediaConnectStatus)},
+    {"wmmQStp", item_size(wmm.queueStopped), 0, item_addr(wmm.queueStopped)},
+    {"wmmPkts", item_size(wmm.packetsQueued), 0,
+     item_addr(wmm.packetsQueued)},
+    {"wmmAcVo", item_size(wmm.packetsOut[WMM_AC_VO]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_VO])},
+    {"wmmAcVi", item_size(wmm.packetsOut[WMM_AC_VI]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_VI])},
+    {"wmmAcBE", item_size(wmm.packetsOut[WMM_AC_BE]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_BE])},
+    {"wmmAcBK", item_size(wmm.packetsOut[WMM_AC_BK]), 0,
+     item_addr(wmm.packetsOut[WMM_AC_BK])},
+    {"PSMode", item_size(PSMode), 0, item_addr(PSMode)},
+    {"PSState", item_size(PSState), 0, item_addr(PSState)},
+    {"IsDeepSleep", item_size(IsDeepSleep), 0, item_addr(IsDeepSleep)},
+    {"IsAutoDeepSleepEnabled", item_size(IsAutoDeepSleepEnabled), 0,
+     item_addr(IsAutoDeepSleepEnabled)},
+    {"WakeupDevReq", item_size(bWakeupDevRequired), 0,
+     item_addr(bWakeupDevRequired)},
+    {"WakeupTries", item_size(WakeupTries), 0, item_addr(WakeupTries)},
+    {"HS_Configured", item_size(bHostSleepConfigured), 0,
+     item_addr(bHostSleepConfigured)},
+    {"HS_Activated", item_size(HS_Activated), 0, item_addr(HS_Activated)},
+    {"num_tx_timeout", item_dbg_size(num_tx_timeout), 0,
+     item_dbg_addr(num_tx_timeout)},
+    {"num_cmd_timeout", item_dbg_size(num_cmd_timeout), 0,
+     item_dbg_addr(num_cmd_timeout)},
+    {"TimeoutCmdId", item_dbg_size(TimeoutCmdId), 0,
+     item_dbg_addr(TimeoutCmdId)},
+    {"TimeoutCmdAct", item_dbg_size(TimeoutCmdAct), 0,
+     item_dbg_addr(TimeoutCmdAct)},
+    {"LastCmdId", item_dbg_size(LastCmdId), 0, item_dbg_addr(LastCmdId)},
+    {"LastCmdAct", item_dbg_size(LastCmdAct), 0, item_dbg_addr(LastCmdAct)},
+    {"LastCmdIndex", item_dbg_size(LastCmdIndex), 0,
+     item_dbg_addr(LastCmdIndex)},
+    {"LastCmdRespId", item_dbg_size(LastCmdRespId), 0,
+     item_dbg_addr(LastCmdRespId)},
+    {"LastCmdRespIndex", item_dbg_size(LastCmdRespIndex), 0,
+     item_dbg_addr(LastCmdRespIndex)},
+    {"LastEvent", item_dbg_size(LastEvent), 0, item_dbg_addr(LastEvent)},
+    {"LastEventIndex", item_dbg_size(LastEventIndex), 0,
+     item_dbg_addr(LastEventIndex)},
+    {"num_cmd_h2c_fail", item_dbg_size(num_cmd_host_to_card_failure), 0,
+     item_dbg_addr(num_cmd_host_to_card_failure)},
+    {"num_cmd_sleep_cfm_fail",
+     item_dbg_size(num_cmd_sleep_cfm_host_to_card_failure), 0,
+     item_dbg_addr(num_cmd_sleep_cfm_host_to_card_failure)},
+    {"num_tx_h2c_fail", item_dbg_size(num_tx_host_to_card_failure), 0,
+     item_dbg_addr(num_tx_host_to_card_failure)},
+    {"num_evt_deauth", item_dbg_size(num_event_deauth), 0,
+     item_dbg_addr(num_event_deauth)},
+    {"num_evt_disassoc", item_dbg_size(num_event_disassoc), 0,
+     item_dbg_addr(num_event_disassoc)},
+    {"num_evt_link_lost", item_dbg_size(num_event_link_lost), 0,
+     item_dbg_addr(num_event_link_lost)},
+    {"num_cmd_deauth", item_dbg_size(num_cmd_deauth), 0,
+     item_dbg_addr(num_cmd_deauth)},
+    {"num_cmd_assoc_ok", item_dbg_size(num_cmd_assoc_success), 0,
+     item_dbg_addr(num_cmd_assoc_success)},
+    {"num_cmd_assoc_fail", item_dbg_size(num_cmd_assoc_failure), 0,
+     item_dbg_addr(num_cmd_assoc_failure)},
+
+    {"dnld_sent", item1_size(dnld_sent), 0, item1_addr(dnld_sent)},
+};
+
+static int num_of_items = sizeof(items) / sizeof(items[0]);
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+/** 
+ *  @brief proc read function
+ *
+ *  @param page	   pointer to buffer
+ *  @param s       read data starting position
+ *  @param off     offset
+ *  @param cnt     counter 
+ *  @param eof     end of file flag
+ *  @param data    data to output
+ *  @return 	   number of output data
+ */
+static int
+wlan_debug_read(char *page, char **s, off_t off, int cnt, int *eof,
+                void *data)
+{
+    int val = 0;
+    char *p = page;
+    int i;
+
+    struct debug_data *d = (struct debug_data *) data;
+
+    if (MODULE_GET == 0)
+        return WLAN_STATUS_FAILURE;
+
+    for (i = 0; i < num_of_items; i++) {
+        if (d[i].size == 1)
+            val = *((u8 *) d[i].addr);
+        else if (d[i].size == 2)
+            val = *((u16 *) d[i].addr);
+        else if (d[i].size == 4)
+            val = *((u32 *) d[i].addr);
+        else {
+            int j;
+            p += sprintf(p, "%s=", d[i].name);
+            for (j = 0; j < d[i].size; j += 2) {
+                val = *(u16 *) (d[i].addr + j);
+                p += sprintf(p, "0x%x ", val);
+            }
+            p += sprintf(p, "\n");
+            continue;
+        }
+
+        if (strstr(d[i].name, "Id"))
+            p += sprintf(p, "%s=0x%x\n", d[i].name, val);
+        else
+            p += sprintf(p, "%s=%d\n", d[i].name, val);
+    }
+    MODULE_PUT;
+    return p - page;
+}
+
+/** 
+ *  @brief proc write function
+ *
+ *  @param f	   file pointer
+ *  @param buf     pointer to data buffer
+ *  @param cnt     data number to write
+ *  @param data    data to write
+ *  @return 	   number of data
+ */
+static int
+wlan_debug_write(struct file *f, const char *buf, unsigned long cnt,
+                 void *data)
+{
+    int r, i;
+    char *pdata;
+    char *p;
+    char *p0;
+    char *p1;
+    char *p2;
+    struct debug_data *d = (struct debug_data *) data;
+
+    if (MODULE_GET == 0)
+        return WLAN_STATUS_FAILURE;
+
+    pdata = (char *) kmalloc(cnt, GFP_KERNEL);
+    if (pdata == NULL) {
+        MODULE_PUT;
+        return 0;
+    }
+
+    if (copy_from_user(pdata, buf, cnt)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(pdata);
+        MODULE_PUT;
+        return 0;
+    }
+
+    p0 = pdata;
+    for (i = 0; i < num_of_items; i++) {
+        do {
+            p = strstr(p0, d[i].name);
+            if (p == NULL)
+                break;
+            p1 = strchr(p, '\n');
+            if (p1 == NULL)
+                break;
+            p0 = p1++;
+            p2 = strchr(p, '=');
+            if (!p2)
+                break;
+            p2++;
+            r = string_to_number(p2);
+            if (d[i].size == 1)
+                *((u8 *) d[i].addr) = (u8) r;
+            else if (d[i].size == 2)
+                *((u16 *) d[i].addr) = (u16) r;
+            else if (d[i].size == 4)
+                *((u32 *) d[i].addr) = (u32) r;
+            break;
+        } while (TRUE);
+    }
+    kfree(pdata);
+    MODULE_PUT;
+    return cnt;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+/** 
+ *  @brief create debug proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @param dev     pointer net_device
+ *  @return 	   N/A
+ */
+void
+wlan_debug_entry(wlan_private * priv, struct net_device *dev)
+{
+    int i;
+    struct proc_dir_entry *r;
+
+    if (priv->proc_entry == NULL)
+        return;
+
+    for (i = 0; i < (num_of_items - ITEMS_FROM_WLAN_DEV); i++) {
+        items[i].addr = items[i].offset + (u32) priv->adapter;
+    }
+    for (i = num_of_items - ITEMS_FROM_WLAN_DEV; i < num_of_items; i++) {
+        items[i].addr = items[i].offset + (u32) & priv->wlan_dev;
+    }
+    r = create_proc_entry("debug", 0644, priv->proc_entry);
+    if (r == NULL)
+        return;
+
+    r->data = &items[0];
+    r->read_proc = wlan_debug_read;
+    r->write_proc = wlan_debug_write;
+    r->owner = THIS_MODULE;
+
+}
+
+/** 
+ *  @brief remove proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @return 	   N/A
+ */
+void
+wlan_debug_remove(wlan_private * priv)
+{
+    remove_proc_entry("debug", priv->proc_entry);
+}
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_decl.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_decl.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_decl.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_decl.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,212 @@
+/** @file wlan_decl.h
+ *  @brief This file contains declaration referring to
+ *  functions defined in other source files
+ *     
+ *  (c) Copyright © 2003-2007, Marvell International Ltd.  
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/******************************************************
+Change log:
+	09/29/05: add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join structures.
+	          Move wlan_wext statics to their source file.
+******************************************************/
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+/** Function Prototype Declaration */
+int wlan_init_fw(wlan_private * priv);
+int wlan_init_sw(wlan_private * priv);
+int wlan_tx_packet(wlan_private * priv, struct sk_buff *skb);
+void wlan_free_adapter(wlan_private * priv);
+
+int wlan_send_null_packet(wlan_private * priv, u8 flags);
+BOOLEAN wlan_check_last_packet_indication(wlan_private * priv);
+
+void Wep_encrypt(wlan_private * priv, u8 * Buf, u32 Len);
+int wlan_free_cmd_buffer(wlan_private * priv);
+void wlan_clean_cmd_node(CmdCtrlNode * pTempNode);
+CmdCtrlNode *wlan_get_cmd_node(wlan_private * priv);
+
+void wlan_init_cmd_node(wlan_private * priv,
+                        CmdCtrlNode * pTempNode,
+                        WLAN_OID cmd_oid, u16 wait_option, void *pdata_buf);
+
+BOOLEAN wlan_is_cmd_allowed(wlan_private * priv);
+
+int wlan_prepare_cmd(wlan_private * priv,
+                     u16 cmd_no,
+                     u16 cmd_action,
+                     u16 wait_option, WLAN_OID cmd_oid, void *pdata_buf);
+
+void wlan_insert_cmd_to_pending_q(wlan_adapter * Adapter,
+                                  CmdCtrlNode * CmdNode, BOOLEAN addtail);
+
+int wlan_set_deep_sleep(wlan_private * priv, BOOLEAN bDeepSleep);
+int wlan_alloc_cmd_buffer(wlan_private * priv);
+int wlan_exec_next_cmd(wlan_private * priv);
+int wlan_process_event(wlan_private * priv);
+void wlan_interrupt(wlan_private *);
+u32 index_to_data_rate(u8 index);
+u8 data_rate_to_index(u32 rate);
+void get_version(wlan_adapter * adapter, char *version, int maxlen);
+void wlan_read_write_rfreg(wlan_private * priv);
+
+#ifdef CONFIG_PROC_FS
+/** The proc fs interface */
+void wlan_proc_entry(wlan_private * priv, struct net_device *dev);
+void wlan_proc_remove(wlan_private * priv);
+int string_to_number(char *s);
+#ifdef PROC_DEBUG
+void wlan_debug_entry(wlan_private * priv, struct net_device *dev);
+void wlan_debug_remove(wlan_private * priv);
+#endif /* PROC_DEBUG */
+#endif /* CONFIG_PROC_FS */
+int wlan_process_cmdresp(wlan_private * priv);
+void wlan_process_tx(wlan_private * priv);
+void wlan_insert_cmd_to_free_q(wlan_private * priv, CmdCtrlNode * pTempCmd);
+void wlan_cmd_timeout_func(void *FunctionContext);
+
+#ifdef REASSOCIATION
+void wlan_reassoc_timer_func(void *FunctionContext);
+#endif /* REASSOCIATION */
+
+int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+                   struct iw_point *dwrq, char *extra);
+int wlan_set_regiontable(wlan_private * priv, u8 region, u8 band);
+
+void wlan_clean_txrx(wlan_private * priv);
+
+int wlan_host_sleep_activated_event(wlan_private * priv);
+int wlan_host_sleep_deactivated_event(wlan_private * priv);
+int wlan_host_sleep_wakeup_event(wlan_private * priv);
+int wlan_deep_sleep_ioctl(wlan_private * priv, struct ifreq *rq);
+
+int wlan_process_rx_packet(wlan_private * priv, struct sk_buff *);
+
+void wlan_enter_ps(wlan_private * priv, int wait_option);
+void wlan_ps_cond_check(wlan_private * priv, u16 PSMode);
+void wlan_exit_ps(wlan_private * priv, int wait_option);
+
+extern CHANNEL_FREQ_POWER *find_cfp_by_band_and_channel(wlan_adapter *
+                                                        adapter, u8 band,
+                                                        u16 channel);
+extern CHANNEL_FREQ_POWER *get_cfp_by_band_and_channel(u8 band, u16 channel,
+                                                       REGION_CHANNEL *
+                                                       region_channnel);
+
+CHANNEL_FREQ_POWER *wlan_get_region_cfp_table(u8 region, u8 band,
+                                              int *cfp_no);
+
+extern void wlan_reset_connect_state(wlan_private * priv);
+
+#if WIRELESS_EXT > 14
+void send_iwevcustom_event(wlan_private * priv, s8 * str);
+#endif
+
+/* Macros and Functions in interface module */
+/** INT Status Bit Definition : Rx upload ready */
+#define HIS_RxUpLdRdy			BIT(0)
+/** INT Status Bit Definition : Tx download ready */
+#define HIS_TxDnLdRdy			BIT(1)
+/** INT Status Bit Definition : Command download ready */
+#define HIS_CmdDnLdRdy			BIT(2)
+/** INT Status Bit Definition : Card event */
+#define HIS_CardEvent			BIT(3)
+/** INT Status Bit Definition : Command upload ready */
+#define HIS_CmdUpLdRdy			BIT(4)
+
+/** Disable Host interrupt mask */
+#define	HIM_DISABLE			0xff
+/** Enable Host interrupt mask */
+#define HIM_ENABLE			0x03
+
+/** Firmware ready */
+#define FIRMWARE_READY			0xfedc
+/** Length of device name */
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN			32
+#endif
+/** Maximum length of key */
+#define MAXKEYLEN			13
+
+/** The number of times to try when polling for status bits */
+#define MAX_POLL_TRIES			100
+
+/** The number of times to try when waiting for downloaded firmware to 
+     become active. (polling the scratch register). */
+
+#define MAX_FIRMWARE_POLL_TRIES		100
+
+/** Number of firmware blocks to transfer */
+#define FIRMWARE_TRANSFER_NBLOCK	2
+
+/** Packet type: data, command & event */
+typedef enum _mv_type
+{
+    MV_TYPE_DAT = 0,
+    MV_TYPE_CMD = 1,
+    MV_TYPE_EVENT = 3
+} mv_type;
+
+/** Function Prototype Declaration : Function add */
+typedef wlan_private *(*wlan_notifier_fn_add) (void *dev_id);
+/** Function Prototype Declaration : Function remove */
+typedef int (*wlan_notifier_fn_remove) (void *dev_id);
+
+/** Function Prototype Declaration : ISR notifier */
+typedef IRQ_RET_TYPE(*isr_notifier_fn_t) (s32 irq, void *dev_id,
+                                          struct pt_regs * reg);
+/** Function Prototype Declaration : IRQ handler */
+typedef IRQ_RET_TYPE(*handler_fn_t) (s32 irq, void *dev_id, struct pt_regs *);
+
+/* Probe and Check if the card is present*/
+int sbi_probe_card(void *card);
+/** Register SBI functions */
+int *sbi_register(wlan_notifier_fn_add, wlan_notifier_fn_remove, void *);
+/** Unregister SBI function */
+void sbi_unregister(void);
+/** Register SBI device */
+int sbi_register_dev(wlan_private * priv);
+/** Unregister SBI device */
+int sbi_unregister_dev(wlan_private *);
+int sbi_disable_host_int(wlan_private * priv);
+/** Get interrupt status */
+int sbi_get_int_status(wlan_private * priv, u8 *);
+int sbi_prog_firmware(wlan_private *);
+/** Check firmware status */
+int sbi_check_fw_status(wlan_private *, int);
+
+int sbi_prog_helper(wlan_private *);
+int sbi_prog_fw_w_helper(wlan_private *);
+
+/** Send data from host to card */
+int sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+int sbi_enable_host_int(wlan_private *);
+
+int sbi_exit_deep_sleep(wlan_private *);
+int sbi_reset_deepsleep_wakeup(wlan_private *);
+
+int sbi_read_ioreg(wlan_private * priv, u32 reg, u8 * dat);
+int sbi_write_ioreg(wlan_private * priv, u32 reg, u8 dat);
+int sbi_set_bus_clock(wlan_private * priv, u8 option);
+
+/** Get CIS information */
+int sbi_get_cis_info(wlan_private * priv, void *cisinfo, int *cislen);
+
+#endif /* _WLAN_DECL_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_drv.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_drv.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_drv.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_drv.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,753 @@
+/** @file wlan_drv.h
+  * @brief This file contains wlan driver specific defines etc.
+  * 
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	05/30/07: Initial creation
+	
+********************************************************/
+
+#ifndef _WLAN_DRV_H
+#define _WLAN_DRV_H
+
+/** Driver release version */
+#define DRIVER_RELEASE_VERSION		"26530"
+
+/** Maximum number of BSSID per channel */
+#define	MAX_BSSID_PER_CHANNEL		16
+
+/** For the extended Scan */
+#define MAX_EXTENDED_SCAN_BSSID_LIST    (MAX_BSSID_PER_CHANNEL * \
+						MRVDRV_MAX_CHANNEL_SIZE + 1)
+enum
+{
+    ADHOC_IDLE,
+    ADHOC_STARTED,
+    ADHOC_JOINED,
+    ADHOC_COALESCED
+};
+
+typedef struct _PER_CHANNEL_BSSID_LIST_DATA
+{
+    /** BSSID list data start */
+    u8 ucStart;
+    /** BSSID list data count */
+    u8 ucNumEntry;
+} PER_CHANNEL_BSSID_LIST_DATA, *PPER_CHANNEL_BSSID_LIST_DATA;
+
+typedef struct _MRV_BSSID_IE_LIST
+{
+    /** Fixed IEs */
+    WLAN_802_11_FIXED_IEs FixedIE;
+    /** Variable IEs */
+    u8 VariableIE[MRVDRV_SCAN_LIST_VAR_IE_SPACE];
+} MRV_BSSID_IE_LIST, *PMRV_BSSID_IE_LIST;
+
+/** Maximum number of region channel */
+#define	MAX_REGION_CHANNEL_NUM	2
+
+/** Chan-Freq-TxPower mapping table*/
+typedef struct _CHANNEL_FREQ_POWER
+{
+        /** Channel Number		*/
+    u16 Channel;
+        /** Frequency of this Channel	*/
+    u32 Freq;
+        /** Max allowed Tx power level	*/
+    u16 MaxTxPower;
+        /** TRUE:channel unsupported;  FLASE:supported*/
+    BOOLEAN Unsupported;
+} CHANNEL_FREQ_POWER;
+
+/** region-band mapping table*/
+typedef struct _REGION_CHANNEL
+{
+        /** TRUE if this entry is valid		     */
+    BOOLEAN Valid;
+        /** Region code for US, Japan ...	     */
+    u8 Region;
+        /** Band B/G/A, used for BAND_CONFIG cmd	     */
+    u8 Band;
+        /** Actual No. of elements in the array below */
+    u8 NrCFP;
+        /** chan-freq-txpower mapping table*/
+    CHANNEL_FREQ_POWER *CFP;
+} REGION_CHANNEL;
+
+typedef struct _wlan_802_11_security_t
+{
+    /** WPA enabled flag */
+    BOOLEAN WPAEnabled;
+    /** WPA2 enabled flag */
+    BOOLEAN WPA2Enabled;
+    /** WEP status */
+    WLAN_802_11_WEP_STATUS WEPStatus;
+    /** Authentication mode */
+    WLAN_802_11_AUTHENTICATION_MODE AuthenticationMode;
+    /** Encryption mode */
+    WLAN_802_11_ENCRYPTION_MODE EncryptionMode;
+} wlan_802_11_security_t;
+
+/** Current Basic Service Set State Structure */
+typedef struct
+{
+    /** BSS descriptor */
+    BSSDescriptor_t BSSDescriptor;
+
+        /** band */
+    u8 band;
+
+        /** number of rates supported */
+    int NumOfRates;
+
+        /** supported rates*/
+    u8 DataRates[WLAN_SUPPORTED_RATES];
+
+        /** wmm enable? */
+    u8 wmm_enabled;
+
+        /** uapsd enable?*/
+    u8 wmm_uapsd_enabled;
+} CurrentBSSParams_t;
+
+/** sleep_params */
+typedef struct SleepParams
+{
+    /** Sleep parameter error */
+    u16 sp_error;
+    /** Sleep parameter offset */
+    u16 sp_offset;
+    /** Sleep parameter stable time */
+    u16 sp_stabletime;
+    /** Sleep parameter calibration control */
+    u8 sp_calcontrol;
+    /** Sleep parameter external sleep clock */
+    u8 sp_extsleepclk;
+    /** Sleep parameter reserved */
+    u16 sp_reserved;
+} SleepParams;
+
+/** sleep_period */
+typedef struct SleepPeriod
+{
+    /** Sleep period */
+    u16 period;
+    /** Reserved */
+    u16 reserved;
+} SleepPeriod;
+
+/** Debug command number */
+#define DBG_CMD_NUM	5
+
+/** info for debug purpose */
+typedef struct _wlan_dbg
+{
+    /** Number of host to card command failures */
+    u32 num_cmd_host_to_card_failure;
+    /** Number of host to card sleep confirm failures */
+    u32 num_cmd_sleep_cfm_host_to_card_failure;
+    /** Number of host to card Tx failures */
+    u32 num_tx_host_to_card_failure;
+    /** Number of deauthentication events */
+    u32 num_event_deauth;
+    /** Number of disassosiation events */
+    u32 num_event_disassoc;
+    /** Number of link lost events */
+    u32 num_event_link_lost;
+    /** Number of deauthentication commands */
+    u32 num_cmd_deauth;
+    /** Number of association comamnd successes */
+    u32 num_cmd_assoc_success;
+    /** Number of association command failures */
+    u32 num_cmd_assoc_failure;
+    /** Number of Tx timeouts */
+    u32 num_tx_timeout;
+    /** Number of command timeouts */
+    u32 num_cmd_timeout;
+    /** Timeout command ID */
+    u16 TimeoutCmdId;
+    /** Timeout command action */
+    u16 TimeoutCmdAct;
+    /** List of last command IDs */
+    u16 LastCmdId[DBG_CMD_NUM];
+    /** List of last command actions */
+    u16 LastCmdAct[DBG_CMD_NUM];
+    /** Last command index */
+    u16 LastCmdIndex;
+    /** List of last command response IDs */
+    u16 LastCmdRespId[DBG_CMD_NUM];
+    /** Last command response index */
+    u16 LastCmdRespIndex;
+    /** List of last events */
+    u16 LastEvent[DBG_CMD_NUM];
+    /** Last event index */
+    u16 LastEventIndex;
+} wlan_dbg;
+
+/** Data structure for the Marvell WLAN device */
+typedef struct _wlan_dev
+{
+        /** device name */
+    char name[DEV_NAME_LEN];
+        /** card pointer */
+    void *card;
+        /** IO port */
+    u32 ioport;
+        /** Upload received */
+    u32 upld_rcv;
+        /** Upload type */
+    u32 upld_typ;
+        /** Upload length */
+    u32 upld_len;
+        /** netdev pointer */
+    struct net_device *netdev;
+        /** Upload buffer*/
+    u8 upld_buf[WLAN_UPLD_SIZE];
+        /** Download sent: 
+	 	bit0 1/0=data_sent/data_tx_done, 
+		bit1 1/0=cmd_sent/cmd_tx_done, 
+		all other bits reserved 0 */
+    u8 dnld_sent;
+} wlan_dev_t, *pwlan_dev_t;
+
+/** Data structure for WPS information */
+typedef struct
+{
+    /** Session enable flag */
+    BOOLEAN SessionEnable;
+} wps_t;
+
+/** Private structure for the MV device */
+struct _wlan_private
+{
+    /** Device open */
+    int open;
+
+    /** Device adapter structure */
+    wlan_adapter *adapter;
+    /** Device structure */
+    wlan_dev_t wlan_dev;
+
+    /** Net device statistics structure */
+    struct net_device_stats stats;
+
+    /** IW statistics */
+    struct iw_statistics wstats;
+#ifdef CONFIG_PROC_FS
+    struct proc_dir_entry *proc_mwlan;
+    struct proc_dir_entry *proc_entry;
+#endif                          /* CONFIG_PROC_FS */
+    /** Firmware helper */
+    const struct firmware *fw_helper;
+    /** Firmware */
+    const struct firmware *firmware;
+    /** Hotplug device */
+    struct device *hotplug_device;
+
+        /** thread to service interrupts */
+    wlan_thread MainThread;
+
+#ifdef REASSOCIATION
+        /** thread to service mac events */
+    wlan_thread ReassocThread;
+#endif                          /* REASSOCIATION */
+
+        /** Enhancement flag - for V10 and UP */
+    int enhance_flag;
+};
+
+/** Wlan Adapter data structure*/
+struct _wlan_adapter
+{
+        /** STATUS variables */
+    WLAN_HARDWARE_STATUS HardwareStatus;
+    /** Firmware release number */
+    u32 FWReleaseNumber;
+    /** Firmware capability information */
+    u32 fwCapInfo;
+    /** Chip revision number */
+    u8 chip_rev;
+
+        /** Command-related variables */
+    /** Command sequence number */
+    u16 SeqNum;
+    /** Command controller nodes */
+    CmdCtrlNode *CmdArray;
+        /** Current Command */
+    CmdCtrlNode *CurCmd;
+    /** Current command return code */
+    int CurCmdRetCode;
+
+        /** Command Queues */
+        /** Free command buffers */
+    struct list_head CmdFreeQ;
+        /** Pending command buffers */
+    struct list_head CmdPendingQ;
+
+        /** Variables brought in from private structure */
+    int irq;
+
+        /** Async and Sync Event variables */
+    u32 IntCounter;
+    /** save int for DS/PS */
+    u32 IntCounterSaved;
+    /** Event cause */
+    u32 EventCause;
+        /** nickname */
+    u8 nodeName[16];
+
+        /** spin locks */
+    spinlock_t QueueSpinLock __ATTRIB_ALIGN__;
+
+        /** Timers */
+    WLAN_DRV_TIMER MrvDrvCommandTimer __ATTRIB_ALIGN__;
+    /** Command timer set flag */
+    BOOLEAN CommandTimerIsSet;
+
+#ifdef REASSOCIATION
+        /**Reassociation timer*/
+    BOOLEAN ReassocTimerIsSet;
+    WLAN_DRV_TIMER MrvDrvTimer __ATTRIB_ALIGN__;
+#endif                          /* REASSOCIATION */
+
+        /** Event Queues */
+    wait_queue_head_t ds_awake_q __ATTRIB_ALIGN__;
+
+    /** His registry copy */
+    u8 HisRegCpy;
+
+    /** bg scan related variable */
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *bgScanConfig;
+    /** BG scan configuration size */
+    u32 bgScanConfigSize;
+
+    /** WMM related variable*/
+    WMM_DESC wmm;
+
+        /** current ssid/bssid related parameters*/
+    CurrentBSSParams_t CurBssParams;
+
+    /** Infrastructure mode */
+    WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+
+    /** Attempted BSS descriptor */
+    BSSDescriptor_t *pAttemptedBSSDesc;
+
+    /** Attempted SSID before scan */
+    WLAN_802_11_SSID AttemptedSSIDBeforeScan;
+    /** Prevous SSID */
+    WLAN_802_11_SSID PreviousSSID;
+    /** Previous BSSID */
+    u8 PreviousBSSID[ETH_ALEN];
+
+    /** Scan table */
+    BSSDescriptor_t *ScanTable;
+    /** Number of records in the scan table */
+    u32 NumInScanTable;
+
+    /** Scan type */
+    u8 ScanType;
+    /** Scan mode */
+    u32 ScanMode;
+    /** Specific scan time */
+    u16 SpecificScanTime;
+    /** Active scan time */
+    u16 ActiveScanTime;
+    /** Passive scan time */
+    u16 PassiveScanTime;
+
+    /** Beacon period */
+    u16 BeaconPeriod;
+    /** AdHoc G rate */
+    u8 AdhocState;
+    /** AdHoc link sensed flag */
+    BOOLEAN AdhocLinkSensed;
+
+#ifdef REASSOCIATION
+        /** Reassociation on and off */
+    BOOLEAN Reassoc_on;
+    SEMAPHORE ReassocSem;
+#endif                          /* REASSOCIATION */
+
+    /** ATIM enabled flag */
+    BOOLEAN ATIMEnabled;
+
+        /** MAC address information */
+    u8 CurrentAddr[ETH_ALEN];
+    /** Multicast address list */
+    u8 MulticastList[MRVDRV_MAX_MULTICAST_LIST_SIZE]
+        [ETH_ALEN];
+    /** Number of multicast addresses in the list */
+    u32 NumOfMulticastMACAddr;
+
+    /** Hardware rate drop mode */
+    u16 HWRateDropMode;
+    /** Rate bitmap */
+    u16 RateBitmap;
+    /** Threshold */
+    u16 Threshold;
+    /** Final rate */
+    u16 FinalRate;
+        /** control G Rates */
+    BOOLEAN adhoc_grate_enabled;
+
+    /** Tx antenna */
+    WLAN_802_11_ANTENNA TxAntenna;
+    /** Rx antenna */
+    WLAN_802_11_ANTENNA RxAntenna;
+
+    /** AdHoc channel */
+    u8 AdhocChannel;
+    /** AdHoc autoselect */
+    u8 AdhocAutoSel;
+    /** Fragmentation threshold */
+    WLAN_802_11_FRAGMENTATION_THRESHOLD FragThsd;
+    /** RTS threshold */
+    WLAN_802_11_RTS_THRESHOLD RTSThsd;
+
+    /** Data rate */
+    u32 DataRate;
+    /** Automatic data rate flag */
+    BOOLEAN Is_DataRate_Auto;
+
+        /** number of association attempts for the current SSID cmd */
+    /** Listen interval */
+    u16 ListenInterval;
+    /** Tx retry count */
+    u8 TxRetryCount;
+
+        /** Tx-related variables (for single packet tx) */
+    /** Current Tx packet */
+    struct sk_buff *CurrentTxSkb;
+    /** Tx lock flag */
+    BOOLEAN TxLockFlag;
+    /** Gen NULL pkg */
+    u16 gen_null_pkg;
+    /** Current Tx lock */
+    spinlock_t CurrentTxLock __ATTRIB_ALIGN__;
+
+        /** NIC Operation characteristics */
+    /** Current packet filter */
+    u16 CurrentPacketFilter;
+    /** Media connection status */
+    u32 MediaConnectStatus;
+    /** Region code */
+    u16 RegionCode;
+    /** Tx power level */
+    u16 TxPowerLevel;
+    /** Maximum Tx power level */
+    u8 MaxTxPowerLevel;
+    /** Minimum Tx power level */
+    u8 MinTxPowerLevel;
+
+        /** POWER MANAGEMENT AND PnP SUPPORT */
+    BOOLEAN SurpriseRemoved;
+    /** ATIM window */
+    u16 AtimWindow;
+
+    /** Power Save mode */
+    u16 PSMode;                 /* Wlan802_11PowerModeCAM=disable
+                                   Wlan802_11PowerModeMAX_PSP=enable */
+    /** Multiple DTIM */
+    u16 MultipleDtim;
+    /** Beacon miss timeout */
+    u16 BCNMissTimeOut;
+    /** Power Save state */
+    u32 PSState;
+    /** Need to wakeup flag */
+    BOOLEAN NeedToWakeup;
+
+    /** Power save confirm sleep command */
+    PS_CMD_ConfirmSleep PSConfirmSleep;
+    /** Local listen interval */
+    u16 LocalListenInterval;
+    /** Null packet interval */
+    u16 NullPktInterval;
+    /** AdHoc awake period */
+    u16 AdhocAwakePeriod;
+    /** Firmware wakeup method */
+    u16 fwWakeupMethod;
+    /** Deep Sleep flag */
+    BOOLEAN IsDeepSleep;
+    /** Auto Deep Sleep enabled flag */
+    BOOLEAN IsAutoDeepSleepEnabled;
+    /** Enhanced Power Save enabled flag */
+    BOOLEAN IsEnhancedPSEnabled;
+    /** Device wakeup required flag */
+    BOOLEAN bWakeupDevRequired;
+    /** Number of wakeup tries */
+    u32 WakeupTries;
+    /** Host Sleep configured flag */
+    BOOLEAN bHostSleepConfigured;
+    /** Host Sleep configuration */
+    HostCmd_DS_802_11_HOST_SLEEP_CFG HSCfg;
+        /** ARP filter related variable */
+    u8 ArpFilter[ARP_FILTER_MAX_BUF_SIZE];
+    /** ARP filter size */
+    u32 ArpFilterSize;
+    /** Host Sleep activated flag */
+    BOOLEAN HS_Activated;
+
+        /** Encryption parameter */
+    wlan_802_11_security_t SecInfo;
+
+    /** WEP keys */
+    MRVL_WEP_KEY WepKey[MRVL_NUM_WEP_KEY];
+    /** Current WEP key index */
+    u16 CurrentWepKeyIndex;
+
+    /** Buffer for TLVs passed from the application to be inserted into the
+     *    association request to firmware 
+     */
+    u8 mrvlAssocTlvBuffer[MRVDRV_ASSOC_TLV_BUF_SIZE];
+
+    /** Length of the data stored in mrvlAssocTlvBuffer*/
+    u8 mrvlAssocTlvBufferLen;
+
+    /** Buffer to store the association response for application retrieval */
+    u8 assocRspBuffer[MRVDRV_ASSOC_RSP_BUF_SIZE];
+
+    /** Length of the data stored in assocRspBuffer */
+    int assocRspSize;
+
+    /** Generice IEEE IEs passed from the application to be inserted into the
+     *    association request to firmware 
+     */
+    u8 genIeBuffer[MRVDRV_GENIE_BUF_SIZE];
+
+    /** Length of the data stored in genIeBuffer */
+    u8 genIeBufferLen;
+
+    /** GTK set flag */
+    BOOLEAN IsGTK_SET;
+
+        /** Encryption Key*/
+    u8 Wpa_ie[256];
+    /** WPA IE length */
+    u8 Wpa_ie_len;
+
+    /** AES key material */
+    HostCmd_DS_802_11_KEY_MATERIAL aeskey;
+
+        /** Advanced Encryption Standard */
+    BOOLEAN AdhocAESEnabled;
+    /** Encryption key command queue */
+    wait_queue_head_t cmd_EncKey __ATTRIB_ALIGN__;
+
+    /** Rx antenna mode */
+    u16 RxAntennaMode;
+    /** TX antenna mode */
+    u16 TxAntennaMode;
+
+        /** Requested Signal Strength*/
+    /** Factor for calculating beacon average */
+    u16 bcn_avg_factor;
+    /** Factor for calculating data average */
+    u16 data_avg_factor;
+    /** Signal to Noise ratio */
+    u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+    /** Noise Floor */
+    u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+    /** RSSI */
+    u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+    /** Raw SNR */
+    u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
+    /** Raw NF */
+    u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+    /** Next SNR/NF */
+    u16 nextSNRNF;
+    /** Number of SNR/NF */
+    u16 numSNRNF;
+    /** Rx PD age */
+    u32 RxPDAge;
+    /** Rx PD rate */
+    u16 RxPDRate;
+
+    /** Radio on flag */
+    BOOLEAN RadioOn;
+
+        /** F/W supports multiband? */
+    u16 is_multiband;
+        /** F/W supported bands */
+    u16 fw_bands;
+        /** User selected bands (a/b/bg/abg) */
+    u16 config_bands;
+        /** User selected bands (a/b/g) to start adhoc network */
+    u16 adhoc_start_band;
+
+    /** Pointer to channel list last sent to the firmware for scanning */
+    ChanScanParamSet_t *pScanChannels;
+
+        /** Blue Tooth Co-existence Arbitration */
+    HostCmd_DS_802_11_BCA_TIMESHARE bca_ts;
+
+        /** sleep_params */
+    SleepParams sp;
+
+        /** sleep_period (Enhanced Power Save) */
+    SleepPeriod sleep_period;
+
+/** Maximum number of region channel */
+#define	MAX_REGION_CHANNEL_NUM	2
+        /** Region Channel data */
+    REGION_CHANNEL region_channel[MAX_REGION_CHANNEL_NUM];
+
+    /** Universal Channel data */
+    REGION_CHANNEL universal_channel[MAX_REGION_CHANNEL_NUM];
+
+        /** 11D and Domain Regulatory Data */
+    wlan_802_11d_domain_reg_t DomainReg;
+    /** Parsed region channel */
+    parsed_region_chan_11d_t parsed_region_chan;
+
+        /** FSM variable for 11d support */
+    wlan_802_11d_state_t State11D;
+    /** FSM variable for 11h support */
+    wlan_11h_state_t state11h;
+    /** FSM variable for MEAS support */
+    wlan_meas_state_t stateMeas;
+    /** Beaco buffer */
+    u8 beaconBuffer[MAX_SCAN_BEACON_BUFFER];
+    /** Pointer to valid beacon buffer end */
+    u8 *pBeaconBufEnd;
+
+    /** Log message  */
+    HostCmd_DS_802_11_GET_LOG LogMsg;
+    /** Scan probes */
+    u16 ScanProbes;
+
+    /** Tx packet control */
+    u32 PktTxCtrl;
+
+    /** Tx rate */
+    u16 TxRate;
+
+    /** WPS */
+    wps_t wps;
+
+    /** Debug */
+    wlan_dbg dbg;
+    /** Number of command timeouts */
+    u32 num_cmd_timeout;
+    /** Number of loops that main thread runs w/o sleep */
+    u32 main_thread_loops;
+
+    /** Driver spin lock */
+    spinlock_t driver_lock;
+};
+
+static inline int
+wlan_copy_mcast_addr(wlan_adapter * Adapter, struct net_device *dev)
+{
+    int i = 0;
+    struct dev_mc_list *mcptr = dev->mc_list;
+
+    for (i = 0; i < dev->mc_count; i++) {
+        memcpy(&Adapter->MulticastList[i], mcptr->dmi_addr, ETH_ALEN);
+        mcptr = mcptr->next;
+    }
+
+    return i;
+}
+
+static inline int
+os_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+
+    skb->dev = priv->wlan_dev.netdev;
+    skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
+    skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+    netif_rx(skb);
+
+    return 0;
+}
+
+static inline void
+os_free_tx_packet(wlan_private * priv)
+{
+    ulong flags;
+
+    if (priv->adapter->CurrentTxSkb) {
+        kfree_skb(priv->adapter->CurrentTxSkb);
+        spin_lock_irqsave(&priv->adapter->CurrentTxLock, flags);
+        priv->adapter->CurrentTxSkb = NULL;
+        spin_unlock_irqrestore(&priv->adapter->CurrentTxLock, flags);
+    }
+}
+
+/*
+ *  netif carrier_on/off and start(wake)/stop_queue handling
+ *
+ *           carrier_on      carrier_off     start_queue     stop_queue
+ * open           x(connect)      x(disconnect)   x
+ * close                          x                               x
+ * assoc          x                               x
+ * deauth                         x                               x
+ * adhoc-start
+ * adhoc-join
+ * adhoc-link     x                               x
+ * adhoc-bcnlost                  x                               x
+ * scan-begin                     x                               x
+ * scan-end       x                               x
+ * ds-enter                       x                               x
+ * ds-exit        x                               x
+ * xmit                                                           x
+ * xmit-done                                      x
+ * tx-timeout
+ */
+static inline void
+os_carrier_on(wlan_private * priv)
+{
+    if (!netif_carrier_ok(priv->wlan_dev.netdev) &&
+        (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) &&
+        ((priv->adapter->InfrastructureMode != Wlan802_11IBSS) ||
+         (priv->adapter->AdhocLinkSensed))) {
+        netif_carrier_on(priv->wlan_dev.netdev);
+    }
+}
+
+static inline void
+os_carrier_off(wlan_private * priv)
+{
+    if (netif_carrier_ok(priv->wlan_dev.netdev)) {
+        netif_carrier_off(priv->wlan_dev.netdev);
+    }
+}
+
+static inline void
+os_start_queue(wlan_private * priv)
+{
+    if (netif_queue_stopped(priv->wlan_dev.netdev) &&
+        (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) &&
+        ((priv->adapter->InfrastructureMode != Wlan802_11IBSS) ||
+         (priv->adapter->AdhocLinkSensed))) {
+        netif_wake_queue(priv->wlan_dev.netdev);
+    }
+}
+
+static inline void
+os_stop_queue(wlan_private * priv)
+{
+    if (!netif_queue_stopped(priv->wlan_dev.netdev)) {
+        netif_stop_queue(priv->wlan_dev.netdev);
+    }
+}
+
+#endif /* _WLAN_DRV_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_fw.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_fw.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_fw.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_fw.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,3921 @@
+/** @file wlan_fw.h
+ * 
+ * @brief This file contains firmware specific defines. 
+ *  
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	05/30/07: Initial creation
+********************************************************/
+
+#ifndef _WLAN_FW_H
+#define _WLAN_FW_H
+
+/** Macros for Data Alignment : size */
+#define ALIGN_SZ(p, a)	\
+	(((p) + ((a) - 1)) & ~((a) - 1))
+
+/** Macros for Data Alignment : address */
+#define ALIGN_ADDR(p, a)	\
+	((((u32)(p)) + (((u32)(a)) - 1)) & ~(((u32)(a)) - 1))
+
+/** The first valid channel for use */
+#define FIRST_VALID_CHANNEL	0xff
+/** PUBLIC DEFINITIONS */
+/** Default Ad-Hoc channel */
+#define DEFAULT_AD_HOC_CHANNEL       6
+/** Default Ad-Hoc channel A */
+#define DEFAULT_AD_HOC_CHANNEL_A    36
+
+/** Length of SNAP header */
+#define MRVDRV_SNAP_HEADER_LEN          8
+
+/** This is for firmware specific length */
+#define EXTRA_LEN	36
+
+/** Buffer size for ethenet Tx packets */
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+	(ETH_FRAME_LEN + sizeof(TxPD) + EXTRA_LEN)
+
+/** Buffer size for ethernet Rx packets */
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+	(ETH_FRAME_LEN + sizeof(RxPD) \
+	 + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+/** Host Command option for wait for RSP */
+#define HostCmd_OPTION_WAITFORRSP             0x0002
+/** Host Command option for wait for RSP Timeout */
+#define HostCmd_OPTION_TIMEOUT	              0x0004
+
+/** Host Command ID : Get hardware specifications */
+#define HostCmd_CMD_GET_HW_SPEC               0x0003
+/** Host Command ID : 802.11 reset */
+#define HostCmd_CMD_802_11_RESET              0x0005
+/** Host Command ID : 802.11 scan */
+#define HostCmd_CMD_802_11_SCAN               0x0006
+/** Host Command ID : 802.11 get log */
+#define HostCmd_CMD_802_11_GET_LOG            0x000b
+/** Host Command ID : MAC multicast address */
+#define HostCmd_CMD_MAC_MULTICAST_ADR         0x0010
+/** Host Command ID : 802.11 EEPROM access */
+#define HostCmd_CMD_802_11_EEPROM_ACCESS      0x0059
+/** Host Command ID : 802.11 associate */
+#define HostCmd_CMD_802_11_ASSOCIATE          0x0012
+/** Host Command ID : 802.11 set WEP */
+#define HostCmd_CMD_802_11_SET_WEP            0x0013
+/** Host Command ID : 802.11 SNMP MIB */
+#define HostCmd_CMD_802_11_SNMP_MIB           0x0016
+/** Host Command ID : MAC register access */
+#define HostCmd_CMD_MAC_REG_ACCESS            0x0019
+/** Host Command ID : BBP register access */
+#define HostCmd_CMD_BBP_REG_ACCESS            0x001a
+/** Host Command ID : RF register access */
+#define HostCmd_CMD_RF_REG_ACCESS             0x001b
+/** Host Command ID : 802.11 radio control */
+#define HostCmd_CMD_802_11_RADIO_CONTROL      0x001c
+/** Host Command ID : 802.11 RF channel */
+#define HostCmd_CMD_802_11_RF_CHANNEL         0x001d
+/** Host Command ID : 802.11 RF Tx power */
+#define HostCmd_CMD_802_11_RF_TX_POWER        0x001e
+/** Host Command ID : 802.11 RSSI */
+#define HostCmd_CMD_802_11_RSSI               0x001f
+/** Host Command ID : 802.11 RF antenna */
+#define HostCmd_CMD_802_11_RF_ANTENNA         0x0020
+
+/** Host Command ID : 802.11 Power Save mode */
+#define HostCmd_CMD_802_11_PS_MODE	      0x0021
+
+/** Host Command ID : 802.11 deauthenticate */
+#define HostCmd_CMD_802_11_DEAUTHENTICATE     0x0024
+/** Host Command ID : MAC control */
+#define HostCmd_CMD_MAC_CONTROL               0x0028
+/** Host Command ID : 802.11 Ad-Hoc start */
+#define HostCmd_CMD_802_11_AD_HOC_START       0x002b
+/** Host Command ID : 802.11 Ad-Hoc join */
+#define HostCmd_CMD_802_11_AD_HOC_JOIN        0x002c
+
+/** Host Command ID : 802.11 key material */
+#define HostCmd_CMD_802_11_KEY_MATERIAL       0x005e
+
+/** Host Command ID : 802.11 Deep Sleep */
+#define HostCmd_CMD_802_11_DEEP_SLEEP         0x003e
+
+/** Host Command ID : 802.11 Ad-Hoc stop */
+#define HostCmd_CMD_802_11_AD_HOC_STOP        0x0040
+
+/** Host Command ID : 802.11 Host Sleep configuration */
+#define HostCmd_CMD_802_11_HOST_SLEEP_CFG     0x0043
+/** Host Command ID : 802.11 Wakeup confirm */
+#define HostCmd_CMD_802_11_WAKEUP_CONFIRM     0x0044
+/** Host Command ID : 802.11 Host Sleep activated */
+#define HostCmd_CMD_802_11_HOST_SLEEP_ACTIVATE	0x0045
+
+/** Host Command ID : 802.22 MAC address */
+#define HostCmd_CMD_802_11_MAC_ADDRESS        0x004D
+/** Host Command ID : 802.11 EEPROM access */
+#define HostCmd_CMD_802_11_EEPROM_ACCESS      0x0059
+
+/** Host Command ID : 802.11 D domain information */
+#define HostCmd_CMD_802_11D_DOMAIN_INFO       0x005b
+
+/** Host Command ID : WMM Traffic Stream Status */
+#define HostCmd_CMD_WMM_TS_STATUS             0x005d
+
+/** Host Command ID : 802.11 TPC information */
+#define HostCmd_CMD_802_11_TPC_INFO           0x005f
+/** Host Command ID : 802.11 TPC adapt req */
+#define HostCmd_CMD_802_11_TPC_ADAPT_REQ      0x0060
+/** Host Command ID : 802.11 channel SW ann */
+#define HostCmd_CMD_802_11_CHAN_SW_ANN        0x0061
+/** Host Command ID : Measurement request */
+#define HostCmd_CMD_MEASUREMENT_REQUEST       0x0062
+/** Host Command ID : Measurement report */
+#define HostCmd_CMD_MEASUREMENT_REPORT        0x0063
+
+/** Host Command ID : 802.11 sleep parameters */
+#define HostCmd_CMD_802_11_SLEEP_PARAMS          0x0066
+
+/** Host Command ID : 802.11 inactivity timeout */
+#define HostCmd_CMD_802_11_INACTIVITY_TIMEOUT    0x0067
+
+/** Host Command ID : 802.11 sleep period */
+#define HostCmd_CMD_802_11_SLEEP_PERIOD          0x0068
+/** Host Command ID : 802.11 BCA configuration timeshare */
+#define HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE  0x0069
+
+/** Host Command ID : 802.11 BG scan configuration */
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG        0x006b
+/** Host Command ID : 802.11 BG scan query */
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY         0x006c
+
+/** Host Command ID : 802.11 calibration data ext */
+#define HostCmd_CMD_802_11_CAL_DATA_EXT          0x006d
+
+/** Host Command ID : WMM ADDTS req  */
+#define HostCmd_CMD_WMM_ADDTS_REQ                0x006E
+/** Host Command ID : WMM DELTS req */
+#define HostCmd_CMD_WMM_DELTS_REQ                0x006F
+/** Host Command ID : WMM queue configuration */
+#define HostCmd_CMD_WMM_QUEUE_CONFIG             0x0070
+/** Host Command ID : 802.11 get status */
+#define HostCmd_CMD_WMM_GET_STATUS               0x0071
+
+/** Host Command ID : 802.11 TPC configuration */
+#define HostCmd_CMD_802_11_TPC_CFG               0x0072
+
+/** Host Command ID : 802.11 firmware wakeup method */
+#define HostCmd_CMD_802_11_FW_WAKE_METHOD        0x0074
+
+/** Host Command ID : 802.11 LED control */
+#define HostCmd_CMD_802_11_LED_CONTROL           0x004e
+
+/** Host Command ID : 802.11 subscribe event */
+#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT       0x0075
+
+/** Host Command ID : 802.11 rate adapt rateset */
+#define HostCmd_CMD_802_11_RATE_ADAPT_RATESET    0x0076
+
+/** Host Command ID : 802.11 crypto */
+#define HostCmd_CMD_802_11_CRYPTO                0x0078
+
+/** Host Command ID : 802.11 Tx rate query */
+#define HostCmd_CMD_802_11_TX_RATE_QUERY	0x007f
+
+/** Host Command ID : 802.11 power adapt configuration ext */
+#define HostCmd_CMD_802_11_POWER_ADAPT_CFG_EXT	0x007e
+
+/** Host Command ID : Get TSF */
+#define HostCmd_CMD_GET_TSF                      0x0080
+
+/** Host Command ID : WMM queue stats */
+#define HostCmd_CMD_WMM_QUEUE_STATS              0x0081
+
+/** Host Command ID : 802.11 auto Tx */
+#define HostCmd_CMD_802_11_AUTO_TX		0x0082
+/** Host Command ID : 802.11 IBSS coalescing status */
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+
+/** Host Command ID : Memory access */
+#define HostCmd_CMD_MEM_ACCESS			0x0086
+
+#ifdef MFG_CMD_SUPPORT
+/** Host Command ID : Mfg command */
+#define HostCmd_CMD_MFG_COMMAND               0x0089
+#endif
+
+/** Host Command ID : DBGS configuration */
+#define HostCmd_CMD_DBGS_CFG		      0x008b
+/** Host Command ID : Get memory */
+#define HostCmd_CMD_GET_MEM		      0x008c
+
+/** Host Command ID : Tx packets stats */
+#define HostCmd_CMD_TX_PKT_STATS              0x008d
+
+/** Host Command ID : Configuration data */
+#define HostCmd_CMD_CFG_DATA                  0x008f
+
+/** Host Command ID : SDIO pull control */
+#define HostCmd_CMD_SDIO_PULL_CTRL		      0x0093
+
+/** Host Command ID : ECL system clock configuration */
+#define HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG   0x0094
+
+/** Host Command ID : Extended version */
+#define HostCmd_CMD_VERSION_EXT               0x0097
+
+/** Host Command ID : Module type configuration */
+#define HostCmd_CMD_MODULE_TYPE_CONFIG        0x0099
+
+/** Host Command ID : MEF configuration */
+#define HostCmd_CMD_MEF_CFG		      0x009a
+
+/* For the IEEE Power Save */
+/** Host Subcommand ID : Enter power save */
+#define HostCmd_SubCmd_Enter_PS               0x0030
+/** Host Subcommand ID : Exit power save */
+#define HostCmd_SubCmd_Exit_PS                0x0031
+/** Host Subcommand ID : Sleep confirmed */
+#define HostCmd_SubCmd_Sleep_Confirmed        0x0034
+/** Host Subcommand ID : Full power down */
+#define HostCmd_SubCmd_Full_PowerDown         0x0035
+/** Host Subcommand ID : Full power up */
+#define HostCmd_SubCmd_Full_PowerUp           0x0036
+
+/** Command RET code, MSB is set to 1 */
+#define HostCmd_RET_BIT                       0x8000
+
+/** General Result Code*/
+/** General result code OK */
+#define HostCmd_RESULT_OK                    0x0000
+/** Genenral error */
+#define HostCmd_RESULT_ERROR                 0x0001
+/** Command is not valid */
+#define HostCmd_RESULT_NOT_SUPPORT           0x0002
+/** Command is pending */
+#define HostCmd_RESULT_PENDING               0x0003
+/** System is busy (command ignored) */
+#define HostCmd_RESULT_BUSY                  0x0004
+/** Data buffer is not big enough */
+#define HostCmd_RESULT_PARTIAL_DATA          0x0005
+
+/* Definition of action or option for each command */
+
+/* Define general purpose action */
+/** General purpose action : Read */
+#define HostCmd_ACT_GEN_READ                    0x0000
+/** General purpose action : Write */
+#define HostCmd_ACT_GEN_WRITE                   0x0001
+/** General purpose action : Get */
+#define HostCmd_ACT_GEN_GET                     0x0000
+/** General purpose action : Set */
+#define HostCmd_ACT_GEN_SET                     0x0001
+/** General purpose action : Remove */
+#define HostCmd_ACT_GEN_REMOVE                  0x0002
+/** General purpose action : Off */
+#define HostCmd_ACT_GEN_OFF                     0x0000
+/** General purpose action : On */
+#define HostCmd_ACT_GEN_ON                      0x0001
+
+/* Define action or option for HostCmd_CMD_802_11_SET_WEP */
+/** WEP action : Add */
+#define HostCmd_ACT_ADD                         0x0002
+/** WEP action : Remove */
+#define HostCmd_ACT_REMOVE                      0x0004
+
+/** WEP type : 40 bit */
+#define HostCmd_TYPE_WEP_40_BIT                 0x0001
+/** WEP type : 104 bit */
+#define HostCmd_TYPE_WEP_104_BIT                0x0002
+
+/** WEP Key index mask */
+#define HostCmd_WEP_KEY_INDEX_MASK              0x3fff
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : BSS */
+#define HostCmd_BSS_TYPE_BSS                    0x0001
+/** Scan type : IBSS */
+#define HostCmd_BSS_TYPE_IBSS                   0x0002
+/** Scan type : Any */
+#define HostCmd_BSS_TYPE_ANY                    0x0003
+
+/* Define action or option for HostCmd_CMD_802_11_SCAN */
+/** Scan type : Active */
+#define HostCmd_SCAN_TYPE_ACTIVE                0x0000
+/** Scan type : Passive */
+#define HostCmd_SCAN_TYPE_PASSIVE               0x0001
+
+/* Radio type definitions for the channel TLV */
+/** Radio type BG */
+#define HostCmd_SCAN_RADIO_TYPE_BG		0
+/** Radio type A */
+#define HostCmd_SCAN_RADIO_TYPE_A		1
+
+/* Define action or option for HostCmd_CMD_MAC_CONTROL */
+/** MAC action : Rx on */
+#define HostCmd_ACT_MAC_RX_ON                   0x0001
+/** MAC action : Tx on */
+#define HostCmd_ACT_MAC_TX_ON                   0x0002
+/** MAC action : Loopback on */
+#define HostCmd_ACT_MAC_LOOPBACK_ON             0x0004
+/** MAC action : WEP enable */
+#define HostCmd_ACT_MAC_WEP_ENABLE              0x0008
+/** MAC action : EthernetII enable */
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE       0x0010
+/** MAC action : Promiscous mode enable */
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE      0x0080
+/** MAC action : All multicast enable */
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE    0x0100
+/** MAC action : Strict protection enable */
+#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE  0x0400
+/** MAC action : Ad-Hoc G protection on */
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON	  0x2000
+
+/* Define action or option or constant for HostCmd_CMD_MAC_MULTICAST_ADR */
+/** MAC address size */
+#define HostCmd_SIZE_MAC_ADR                    6
+/** Maximum number of MAC addresses */
+#define HostCmd_MAX_MCAST_ADRS                  32
+
+/** Radio on */
+#define RADIO_ON                                0x01
+/** Radio off */
+#define RADIO_OFF                               0x00
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+/** Get RF channel */
+#define HostCmd_OPT_802_11_RF_CHANNEL_GET       0x00
+/** Set RF channel */
+#define HostCmd_OPT_802_11_RF_CHANNEL_SET       0x01
+
+/** Host command action : Set Rx */
+#define HostCmd_ACT_SET_RX                      0x0001
+/** Host command action : Set Tx */
+#define HostCmd_ACT_SET_TX                      0x0002
+/** Host command action : Set both Rx and Tx */
+#define HostCmd_ACT_SET_BOTH                    0x0003
+/** Host command action : Get Rx */
+#define HostCmd_ACT_GET_RX                      0x0004
+/** Host command action : Get Tx */
+#define HostCmd_ACT_GET_TX                      0x0008
+/** Host command action : Get both Rx and Tx */
+#define HostCmd_ACT_GET_BOTH                    0x000c
+
+/** Card Event definition : Dummy host wakeup signal */
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL  0x00000001
+/** Card Event definition : Link lost with scan */
+#define EVENT_LINK_LOST_WITH_SCAN       0x00000002
+/** Card Event definition : Link lost */
+#define EVENT_LINK_LOST                 0x00000003
+/** Card Event definition : Link sensed */
+#define EVENT_LINK_SENSED               0x00000004
+/** Card Event definition : MIB changed */
+#define EVENT_MIB_CHANGED               0x00000006
+/** Card Event definition : Init done */
+#define EVENT_INIT_DONE                 0x00000007
+/** Card Event definition : Deauthenticated */
+#define EVENT_DEAUTHENTICATED           0x00000008
+/** Card Event definition : Disassociated */
+#define EVENT_DISASSOCIATED             0x00000009
+/** Card Event definition : Power save awake */
+#define EVENT_PS_AWAKE                  0x0000000a
+/** Card Event definition : Power save sleep */
+#define EVENT_PS_SLEEP                  0x0000000b
+/** Card Event definition : MIC error multicast */
+#define EVENT_MIC_ERR_MULTICAST         0x0000000d
+/** Card Event definition : MIC error unicast */
+#define EVENT_MIC_ERR_UNICAST           0x0000000e
+/** Card Event definition : WM awake */
+#define EVENT_WM_AWAKE                  0x0000000f
+/** Card Event definition : Deep Sleep awake */
+#define EVENT_DEEP_SLEEP_AWAKE          0x00000010
+/** Card Event definition : Ad-Hoc BCN lost */
+#define EVENT_ADHOC_BCN_LOST            0x00000011
+/** Card Event definition : Host Sleep awake */
+#define EVENT_HOST_SLEEP_AWAKE          0x00000012
+/** Card Event definition : Stop Tx */
+#define EVENT_STOP_TX                   0x00000013
+/** Card Event definition : Start Tx */
+#define EVENT_START_TX                  0x00000014
+/** Card Event definition : Channel switch */
+#define EVENT_CHANNEL_SWITCH            0x00000015
+/** Card Event definition : MEAS report ready */
+#define EVENT_MEAS_REPORT_RDY           0x00000016
+/** Card Event definition : WMM status change */
+#define EVENT_WMM_STATUS_CHANGE         0x00000017
+/** Card Event definition : BG scan report */
+#define EVENT_BG_SCAN_REPORT            0x00000018
+/** Card Event definition : Beacon RSSI low */
+#define EVENT_RSSI_LOW                  0x00000019
+/** Card Event definition : Beacon SNR low */
+#define EVENT_SNR_LOW                   0x0000001a
+/** Card Event definition : Maximum fail */
+#define EVENT_MAX_FAIL                  0x0000001b
+/** Card Event definition : Beacon RSSI high */
+#define EVENT_RSSI_HIGH                 0x0000001c
+/** Card Event definition : Beacon SNR high */
+#define EVENT_SNR_HIGH                  0x0000001d
+/** Card Event definition : IBSS coalsced */
+#define EVENT_IBSS_COALESCED            0x0000001e
+/** Card Event definition : Data RSSI low */
+#define EVENT_DATA_RSSI_LOW             0x00000024
+/** Card Event definition : Data SNR low */
+#define EVENT_DATA_SNR_LOW              0x00000025
+/** Card Event definition : Data RSSI high */
+#define EVENT_DATA_RSSI_HIGH            0x00000026
+/** Card Event definition : Data SNR high */
+#define EVENT_DATA_SNR_HIGH             0x00000027
+
+/** Define bitmap conditions for HOST_SLEEP_CFG : Cancel */
+#define HOST_SLEEP_CFG_CANCEL			0xffffffff
+/** Define bitmap conditions for HOST_SLEEP_CFG : GPIO FF */
+#define HOST_SLEEP_CFG_GPIO_FF			0xff
+/** Define bitmap conditions for HOST_SLEEP_CFG : GAP FF */
+#define HOST_SLEEP_CFG_GAP_FF			0xff
+
+/** Maximum size of multicast list */
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE	32
+/** Maximum size of channel */
+#define MRVDRV_MAX_CHANNEL_SIZE		14
+/** Maximum length of SSID */
+#define MRVDRV_MAX_SSID_LENGTH			32
+/** Maximum number of BSS descriptors */
+#define MRVDRV_MAX_BSS_DESCRIPTS		16
+/** WEP list macros & data structures */
+/** Size of key buffer in bytes */
+#define MRVL_KEY_BUFFER_SIZE_IN_BYTE  16
+/** Maximum length of WPA key */
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH     32
+
+/** 802.11 b */
+#define BS_802_11B	0
+/** 802.11 g */
+#define BS_802_11G	1
+/** 802.11 a */
+#define BS_802_11A	2
+/** Setup the number of rates pased in the driver/firmware API.*/
+#define A_SUPPORTED_RATES		14
+
+/** Firmware multiple bands support */
+#define FW_MULTI_BANDS_SUPPORT	(BIT(8) | BIT(9) | BIT(10))
+/** Band B */
+#define	BAND_B			(0x01)
+/** Band G */
+#define	BAND_G			(0x02)
+/** Band A */
+#define BAND_A			(0x04)
+/** All bands (B, G, A) */
+#define ALL_802_11_BANDS	(BAND_B | BAND_G | BAND_A)
+
+/** Check if multiple bands support is enabled in firmware */
+#define	IS_SUPPORT_MULTI_BANDS(_adapter) \
+				(_adapter->fwCapInfo & FW_MULTI_BANDS_SUPPORT)
+/** Get default bands of the firmware */
+#define GET_FW_DEFAULT_BANDS(_adapter)	\
+				((_adapter->fwCapInfo >> 8) & ALL_802_11_BANDS)
+
+/** Setup the number of rates passed in the driver/firmware API.*/
+#define HOSTCMD_SUPPORTED_RATES A_SUPPORTED_RATES
+
+/** Rates supported in band B */
+#define B_SUPPORTED_RATES		8
+/** Rates supported in band G */
+#define G_SUPPORTED_RATES		14
+
+/** WLAN supported rates */
+#define	WLAN_SUPPORTED_RATES		14
+
+/** Maximum power adapt group size */
+#define	MAX_POWER_ADAPT_GROUP		5
+
+/** 802.11 supported rates */
+typedef u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES];
+/** 802.11 MAC address */
+typedef u8 WLAN_802_11_MAC_ADDRESS[ETH_ALEN];
+
+/** WLAN_802_11_NETWORK_TYPE */
+typedef enum _WLAN_802_11_NETWORK_TYPE
+{
+    Wlan802_11FH,
+    Wlan802_11DS,
+    /*defined as upper bound */
+    Wlan802_11NetworkTypeMax
+} WLAN_802_11_NETWORK_TYPE, *PWLAN_802_11_NETWORK_TYPE;
+
+/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
+typedef enum _WLAN_802_11_NETWORK_INFRASTRUCTURE
+{
+    Wlan802_11IBSS,
+    Wlan802_11Infrastructure,
+    Wlan802_11AutoUnknown,
+    /*defined as upper bound */
+    Wlan802_11InfrastructureMax
+} WLAN_802_11_NETWORK_INFRASTRUCTURE, *PWLAN_802_11_NETWORK_INFRASTRUCTURE;
+
+/** Maximum size of IEEE Information Elements */
+#define IEEE_MAX_IE_SIZE  256
+
+/** IEEE Type definitions  */
+typedef enum _IEEEtypes_ElementId_e
+{
+    SSID = 0,
+    SUPPORTED_RATES = 1,
+    FH_PARAM_SET = 2,
+    DS_PARAM_SET = 3,
+    CF_PARAM_SET = 4,
+
+    IBSS_PARAM_SET = 6,
+
+    COUNTRY_INFO = 7,
+
+    POWER_CONSTRAINT = 32,
+    POWER_CAPABILITY = 33,
+    TPC_REQUEST = 34,
+    TPC_REPORT = 35,
+    SUPPORTED_CHANNELS = 36,
+    CHANNEL_SWITCH_ANN = 37,
+    QUIET = 40,
+    IBSS_DFS = 41,
+    ERP_INFO = 42,
+    EXTENDED_SUPPORTED_RATES = 50,
+
+    VENDOR_SPECIFIC_221 = 221,
+    WMM_IE = VENDOR_SPECIFIC_221,
+
+    WPS_IE = VENDOR_SPECIFIC_221,
+
+    WPA_IE = VENDOR_SPECIFIC_221,
+    RSN_IE = 48,
+
+} __ATTRIB_PACK__ IEEEtypes_ElementId_e;
+
+/** Capability information mask */
+#define CAPINFO_MASK    (~( BIT(15) | BIT(14) |               \
+                            BIT(12) | BIT(11) | BIT(9)) )
+
+#ifdef BIG_ENDIAN
+/** Capability Bit Map*/
+typedef struct _IEEEtypes_CapInfo_t
+{
+    u8 Rsrvd1:2;
+    u8 DSSSOFDM:1;
+    u8 Rsvrd2:2;
+    u8 ShortSlotTime:1;
+    u8 Rsrvd3:1;
+    u8 SpectrumMgmt:1;
+    u8 ChanAgility:1;
+    u8 Pbcc:1;
+    u8 ShortPreamble:1;
+    u8 Privacy:1;
+    u8 CfPollRqst:1;
+    u8 CfPollable:1;
+    u8 Ibss:1;
+    u8 Ess:1;
+} __ATTRIB_PACK__ IEEEtypes_CapInfo_t;
+#else
+typedef struct _IEEEtypes_CapInfo_t
+{
+    /** Capability Bit Map : ESS */
+    u8 Ess:1;
+    /** Capability Bit Map : IBSS */
+    u8 Ibss:1;
+    /** Capability Bit Map : CF pollable */
+    u8 CfPollable:1;
+    /** Capability Bit Map : CF poll request */
+    u8 CfPollRqst:1;
+    /** Capability Bit Map : Privacy */
+    u8 Privacy:1;
+    /** Capability Bit Map : Short preamble */
+    u8 ShortPreamble:1;
+    /** Capability Bit Map : PBCC */
+    u8 Pbcc:1;
+    /** Capability Bit Map : Channel agility */
+    u8 ChanAgility:1;
+    /** Capability Bit Map : Spectrum management */
+    u8 SpectrumMgmt:1;
+    /** Capability Bit Map : Reserved */
+    u8 Rsrvd3:1;
+    /** Capability Bit Map : Short slot time */
+    u8 ShortSlotTime:1;
+    /** Capability Bit Map : APSD */
+    u8 Apsd:1;
+    /** Capability Bit Map : Reserved */
+    u8 Rsvrd2:1;
+    /** Capability Bit Map : DSS OFDM */
+    u8 DSSSOFDM:1;
+    /** Capability Bit Map : Reserved */
+    u8 Rsrvd1:2;
+} __ATTRIB_PACK__ IEEEtypes_CapInfo_t;
+
+#endif /* BIG_ENDIAN */
+
+typedef struct
+{
+    /** Element ID */
+    u8 ElementId;
+    /** Length */
+    u8 Len;
+} __ATTRIB_PACK__ IEEEtypes_Header_t;
+
+/** IEEEtypes_CfParamSet_t */
+typedef struct _IEEEtypes_CfParamSet_t
+{
+    /** CF peremeter : Element ID */
+    u8 ElementId;
+    /** CF peremeter : Length */
+    u8 Len;
+    /** CF peremeter : Count */
+    u8 CfpCnt;
+    /** CF peremeter : Period */
+    u8 CfpPeriod;
+    /** CF peremeter : Maximum duration */
+    u16 CfpMaxDuration;
+    /** CF peremeter : Remaining duration */
+    u16 CfpDurationRemaining;
+} __ATTRIB_PACK__ IEEEtypes_CfParamSet_t;
+
+typedef struct IEEEtypes_IbssParamSet_t
+{
+    /** Element ID */
+    u8 ElementId;
+    /** Length */
+    u8 Len;
+    /** ATIM window value */
+    u16 AtimWindow;
+} __ATTRIB_PACK__ IEEEtypes_IbssParamSet_t;
+
+/** IEEEtypes_SsParamSet_t */
+typedef union _IEEEtypes_SsParamSet_t
+{
+    /** SS parameter : CF parameter set */
+    IEEEtypes_CfParamSet_t CfParamSet;
+    /** SS parameter : IBSS parameter set */
+    IEEEtypes_IbssParamSet_t IbssParamSet;
+} __ATTRIB_PACK__ IEEEtypes_SsParamSet_t;
+
+/** IEEEtypes_FhParamSet_t */
+typedef struct _IEEEtypes_FhParamSet_t
+{
+    /** FH parameter : Element ID */
+    u8 ElementId;
+    /** FH parameter : Length */
+    u8 Len;
+    /** FH parameter : Dwell time */
+    u16 DwellTime;
+    /** FH parameter : Hop set */
+    u8 HopSet;
+    /** FH parameter : Hop pattern */
+    u8 HopPattern;
+    /** FH parameter : Hop index */
+    u8 HopIndex;
+} __ATTRIB_PACK__ IEEEtypes_FhParamSet_t;
+
+/** IEEEtypes_DsParamSet_t */
+typedef struct _IEEEtypes_DsParamSet_t
+{
+    /** DS parameter : Element ID */
+    u8 ElementId;
+    /** DS parameter : Length */
+    u8 Len;
+    /** DS parameter : Current channel */
+    u8 CurrentChan;
+} __ATTRIB_PACK__ IEEEtypes_DsParamSet_t;
+
+/** IEEEtypes_PhyParamSet_t */
+typedef union IEEEtypes_PhyParamSet_t
+{
+    /** FH parameter set */
+    IEEEtypes_FhParamSet_t FhParamSet;
+    /** DS parameter set */
+    IEEEtypes_DsParamSet_t DsParamSet;
+} __ATTRIB_PACK__ IEEEtypes_PhyParamSet_t;
+
+typedef struct _IEEEtypes_ERPInfo_t
+{
+    /** Element ID */
+    u8 ElementId;
+    /** Length */
+    u8 Len;
+    /** ERP flags */
+    u8 ERPFlags;
+} __ATTRIB_PACK__ IEEEtypes_ERPInfo_t;
+
+/** 16 bit unsigned integer */
+typedef u16 IEEEtypes_AId_t;
+/** 16 bit unsigned integer */
+typedef u16 IEEEtypes_StatusCode_t;
+
+typedef struct
+{
+    /** Capability information */
+    IEEEtypes_CapInfo_t Capability;
+    /** Association response status code */
+    IEEEtypes_StatusCode_t StatusCode;
+    /** Association ID */
+    IEEEtypes_AId_t AId;
+    /** IE data buffer */
+    u8 IEBuffer[1];
+} __ATTRIB_PACK__ IEEEtypes_AssocRsp_t;
+
+typedef struct
+{
+    /** Element ID */
+    u8 ElementId;
+    /** Length */
+    u8 Len;
+    /** OUI */
+    u8 Oui[3];
+    /** OUI type */
+    u8 OuiType;
+    /** OUI subtype */
+    u8 OuiSubtype;
+    /** Version */
+    u8 Version;
+} __ATTRIB_PACK__ IEEEtypes_VendorHeader_t;
+
+typedef struct
+{
+    /** Vendor specific IE header */
+    IEEEtypes_VendorHeader_t VendHdr;
+
+    /** IE Max - size of previous fields */
+    u8 Data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)];
+
+}
+__ATTRIB_PACK__ IEEEtypes_VendorSpecific_t;
+
+typedef struct
+{
+    /** Generic IE header */
+    IEEEtypes_Header_t IeeeHdr;
+
+    /** IE Max - size of previous fields */
+    u8 Data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)];
+
+}
+__ATTRIB_PACK__ IEEEtypes_Generic_t;
+
+/** TLV  type ID definition */
+#define PROPRIETARY_TLV_BASE_ID		0x0100
+
+/** Terminating TLV Type */
+#define MRVL_TERMINATE_TLV_ID		0xffff
+
+/** TLV type : SSID */
+#define TLV_TYPE_SSID				0x0000
+/** TLV type : Rates */
+#define TLV_TYPE_RATES				0x0001
+/** TLV type : PHY FH */
+#define TLV_TYPE_PHY_FH				0x0002
+/** TLV type : PHY DS */
+#define TLV_TYPE_PHY_DS				0x0003
+/** TLV type : CF */
+#define TLV_TYPE_CF				    0x0004
+/** TLV type : IBSS */
+#define TLV_TYPE_IBSS				0x0006
+
+/** TLV type : Domain */
+#define TLV_TYPE_DOMAIN				0x0007
+
+/** TLV type : Power constraint */
+#define TLV_TYPE_POWER_CONSTRAINT   0x0020
+/** TLV type : Power capability */
+#define TLV_TYPE_POWER_CAPABILITY   0x0021
+
+/** TLV type : Key material */
+#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
+/** TLV type : Channel list */
+#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
+/** TLV type : Number of probes */
+#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+/** TLV type : Beacon RSSI low */
+#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
+/** TLV type : Beacon SNR low */
+#define TLV_TYPE_SNR_LOW            (PROPRIETARY_TLV_BASE_ID + 5)
+/** TLV type : Fail count */
+#define TLV_TYPE_FAILCOUNT          (PROPRIETARY_TLV_BASE_ID + 6)
+/** TLV type : BCN miss */
+#define TLV_TYPE_BCNMISS            (PROPRIETARY_TLV_BASE_ID + 7)
+/** TLV type : LED GPIO */
+#define TLV_TYPE_LED_GPIO           (PROPRIETARY_TLV_BASE_ID + 8)
+/** TLV type : LED behavior */
+#define TLV_TYPE_LEDBEHAVIOR        (PROPRIETARY_TLV_BASE_ID + 9)
+/** TLV type : Passthrough */
+#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
+/** TLV type : Power TBL 2.4 Ghz */
+#define TLV_TYPE_POWER_TBL_2_4GHZ   (PROPRIETARY_TLV_BASE_ID + 12)
+/** TLV type : Power TBL 5 GHz */
+#define TLV_TYPE_POWER_TBL_5GHZ     (PROPRIETARY_TLV_BASE_ID + 13)
+/** TLV type : WMM queue status */
+#define TLV_TYPE_WMMQSTATUS         (PROPRIETARY_TLV_BASE_ID + 16)
+/** TLV type : Crypto data */
+#define TLV_TYPE_CRYPTO_DATA        (PROPRIETARY_TLV_BASE_ID + 17)
+/** TLV type : Wildcard SSID */
+#define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
+/** TLV type : TSF timestamp */
+#define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
+/** TLV type : Power adapter configuration ext */
+#define TLV_TYPE_POWERADAPTCFGEXT   (PROPRIETARY_TLV_BASE_ID + 20)
+/** TLV type : Beacon RSSI high */
+#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+/** TLV type : Beacon SNR high */
+#define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
+/** TLV type : Auto Tx */
+#define TLV_TYPE_AUTO_TX            (PROPRIETARY_TLV_BASE_ID + 24)
+
+/** TLV type : Start BG scan later */
+#define TLV_TYPE_STARTBGSCANLATER   (PROPRIETARY_TLV_BASE_ID + 30)
+/** TLV type : Authentication type */
+#define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
+/** TLV type : Data RSSI low */
+#define TLV_TYPE_RSSI_LOW_DATA      (PROPRIETARY_TLV_BASE_ID + 38)
+/** TLV type : Data SNR low */
+#define TLV_TYPE_SNR_LOW_DATA       (PROPRIETARY_TLV_BASE_ID + 39)
+/** TLV type : Data RSSI high */
+#define TLV_TYPE_RSSI_HIGH_DATA     (PROPRIETARY_TLV_BASE_ID + 40)
+/** TLV type : Data SNR high */
+#define TLV_TYPE_SNR_HIGH_DATA      (PROPRIETARY_TLV_BASE_ID + 41)
+
+/** TLV related data structures*/
+/** MrvlIEtypesHeader_t */
+typedef struct _MrvlIEtypesHeader
+{
+    /** Header type */
+    u16 Type;
+    /** Header length */
+    u16 Len;
+} __ATTRIB_PACK__ MrvlIEtypesHeader_t;
+
+/** MrvlIEtypes_Data_t */
+typedef struct _MrvlIEtypes_Data_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Data */
+    u8 Data[1];
+} __ATTRIB_PACK__ MrvlIEtypes_Data_t;
+
+/** MrvlIEtypes_RatesParamSet_t */
+typedef struct _MrvlIEtypes_RatesParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Rates */
+    u8 Rates[1];
+} __ATTRIB_PACK__ MrvlIEtypes_RatesParamSet_t;
+
+/** MrvlIEtypes_SsIdParamSet_t */
+typedef struct _MrvlIEtypes_SsIdParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** SSID */
+    u8 SsId[1];
+} __ATTRIB_PACK__ MrvlIEtypes_SsIdParamSet_t;
+
+/** MrvlIEtypes_WildCardSsIdParamSet_t */
+typedef struct _MrvlIEtypes_WildCardSsIdParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Maximum SSID length */
+    u8 MaxSsidLength;
+    /** SSID */
+    u8 SsId[1];
+} __ATTRIB_PACK__ MrvlIEtypes_WildCardSsIdParamSet_t;
+
+/** ChanScanMode_t */
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    u8 Reserved_2_7:6;
+    u8 DisableChanFilt:1;
+    u8 PassiveScan:1;
+#else
+    /** Channel scan mode passive flag */
+    u8 PassiveScan:1;
+    /** Disble channel filtering flag */
+    u8 DisableChanFilt:1;
+    /** Reserved */
+    u8 Reserved_2_7:6;
+#endif
+} __ATTRIB_PACK__ ChanScanMode_t;
+
+/** ChanScanParamSet_t */
+typedef struct _ChanScanParamSet_t
+{
+    /** Channel scan parameter : radio type */
+    u8 RadioType;
+    /** Channel scan parameter : channel number */
+    u8 ChanNumber;
+    /** Channel scan parameter : channel scan mode */
+    ChanScanMode_t ChanScanMode;
+    /** Channel scan parameter : minimum scan time */
+    u16 MinScanTime;
+    /** Channel scan parameter : maximum scan time */
+    u16 MaxScanTime;
+} __ATTRIB_PACK__ ChanScanParamSet_t;
+
+/** MrvlIEtypes_ChanListParamSet_t */
+typedef struct _MrvlIEtypes_ChanListParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Channel scan parameters */
+    ChanScanParamSet_t ChanScanParam[1];
+} __ATTRIB_PACK__ MrvlIEtypes_ChanListParamSet_t;
+
+/** CfParamSet_t */
+typedef struct _CfParamSet_t
+{
+    /** CF parameter : count */
+    u8 CfpCnt;
+    /** CF parameter : period */
+    u8 CfpPeriod;
+    /** CF parameter : duration */
+    u16 CfpMaxDuration;
+    /** CF parameter : duration remaining */
+    u16 CfpDurationRemaining;
+} __ATTRIB_PACK__ CfParamSet_t;
+
+/** IbssParamSet_t */
+typedef struct _IbssParamSet_t
+{
+    /** ATIM window value */
+    u16 AtimWindow;
+} __ATTRIB_PACK__ IbssParamSet_t;
+
+/** MrvlIEtypes_SsParamSet_t */
+typedef struct _MrvlIEtypes_SsParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    union
+    {
+        /** CF parameter set */
+        CfParamSet_t CfParamSet[1];
+        /** IBSS parameter set */
+        IbssParamSet_t IbssParamSet[1];
+    } cf_ibss;
+} __ATTRIB_PACK__ MrvlIEtypes_SsParamSet_t;
+
+/** FhParamSet_t */
+typedef struct _FhParamSet_t
+{
+    /** FH parameter : Dwell time */
+    u16 DwellTime;
+    /** FH parameter : Hop set */
+    u8 HopSet;
+    /** FH parameter : Hop pattern */
+    u8 HopPattern;
+    /** FH parameter : Hop index */
+    u8 HopIndex;
+} __ATTRIB_PACK__ FhParamSet_t;
+
+/** DsParamSet_t */
+typedef struct _DsParamSet_t
+{
+    /** Current channel number */
+    u8 CurrentChan;
+} __ATTRIB_PACK__ DsParamSet_t;
+
+/** MrvlIEtypes_PhyParamSet_t */
+typedef struct _MrvlIEtypes_PhyParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    union
+    {
+        /** FH parameter set */
+        FhParamSet_t FhParamSet[1];
+        /** DS parameter set */
+        DsParamSet_t DsParamSet[1];
+    } fh_ds;
+} __ATTRIB_PACK__ MrvlIEtypes_PhyParamSet_t;
+
+/** MrvlIEtypes_RsnParamSet_t */
+typedef struct _MrvlIEtypes_RsnParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** RSN IE */
+    u8 RsnIE[1];
+} __ATTRIB_PACK__ MrvlIEtypes_RsnParamSet_t;
+
+/** MrvlIEtypes_WmmParamSet_t */
+typedef struct _MrvlIEtypes_WmmParamSet_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** WMM IE */
+    u8 WmmIE[1];
+} __ATTRIB_PACK__ MrvlIEtypes_WmmParamSet_t;
+
+typedef struct
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Queue index */
+    u8 QueueIndex;
+    /** Disabled flag */
+    u8 Disabled;
+    /** Medium time allocation in 32us units*/
+    u16 MediumTime;
+    /** Flow required flag */
+    u8 FlowRequired;
+    /** Flow created flag */
+    u8 FlowCreated;
+    /** Reserved */
+    u32 Reserved;
+} __ATTRIB_PACK__ MrvlIEtypes_WmmQueueStatus_t;
+
+/** Table of TSF values returned in the scan result */
+typedef struct
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** TSF table */
+    u64 tsfTable[1];
+} __ATTRIB_PACK__ MrvlIEtypes_TsfTimestamp_t;
+
+/**  Local Power Capability */
+typedef struct _MrvlIEtypes_PowerCapability_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Minmum power */
+    s8 MinPower;
+    /** Maximum power */
+    s8 MaxPower;
+} __ATTRIB_PACK__ MrvlIEtypes_PowerCapability_t;
+
+/** MrvlIEtypes_RssiParamSet_t */
+typedef struct _MrvlIEtypes_RssiThreshold_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** RSSI value */
+    u8 RSSIValue;
+    /** RSSI frequency */
+    u8 RSSIFreq;
+} __ATTRIB_PACK__ MrvlIEtypes_RssiThreshold_t;
+
+/** MrvlIEtypes_SnrThreshold_t */
+typedef struct _MrvlIEtypes_SnrThreshold_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** SNR value */
+    u8 SNRValue;
+    /** SNR frequency */
+    u8 SNRFreq;
+} __ATTRIB_PACK__ MrvlIEtypes_SnrThreshold_t;
+
+/** MrvlIEtypes_FailureCount_t */
+typedef struct _MrvlIEtypes_FailureCount_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Failure value */
+    u8 FailValue;
+    /** Failure frequency */
+    u8 FailFreq;
+} __ATTRIB_PACK__ MrvlIEtypes_FailureCount_t;
+
+/** MrvlIEtypes_BeaconsMissed_t */
+typedef struct _MrvlIEtypes_BeaconsMissed_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Number of beacons missed */
+    u8 BeaconMissed;
+    /** Reserved */
+    u8 Reserved;
+} __ATTRIB_PACK__ MrvlIEtypes_BeaconsMissed_t;
+
+/** MrvlIEtypes_NumProbes_t */
+typedef struct _MrvlIEtypes_NumProbes_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Number of probes */
+    u16 NumProbes;
+} __ATTRIB_PACK__ MrvlIEtypes_NumProbes_t;
+
+/** MrvlIEtypes_StartBGScanLater_t */
+typedef struct _MrvlIEtypes_StartBGScanLater_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Start later flag */
+    u16 StartLater;
+} __ATTRIB_PACK__ MrvlIEtypes_StartBGScanLater_t;
+
+typedef struct _LedGpio_t
+{
+    u8 LedNum;                                  /**< LED # mapped to GPIO pin # below */
+    u8 GpioNum;                                 /**< GPIO pin # used to control LED # above */
+} __ATTRIB_PACK__ LedGpio_t;
+
+/** MrvlIEtypes_LedGpio_t */
+typedef struct _MrvlIEtypes_LedGpio_t
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** LED GPIO */
+    LedGpio_t LedGpio[1];
+} __ATTRIB_PACK__ MrvlIEtypes_LedGpio_t;
+
+/** MrvlIEtypes_LedBehavior_t */
+typedef struct _MrvlIEtypes_LedBehavior_t
+{
+    MrvlIEtypesHeader_t Header;         /**< Header */
+    u8 FirmwareState;                           /**< Firmware State */
+    u8 LedNum;                                  /**< LED # */
+    u8 LedState;                                /**< LED State corresponding to Firmware State */
+    u8 LedArgs;                                 /**< Arguments for LED State */
+} __ATTRIB_PACK__ MrvlIEtypes_LedBehavior_t;
+
+typedef struct _PA_Group_t
+{
+    u16 PowerAdaptLevel;                            /**< Power adapt level */
+    u16 RateBitmap;                                 /**< Rate bitmap */
+    u32 Reserved;                                   /**< Reserved */
+} __ATTRIB_PACK__ PA_Group_t;
+
+/** MrvlIEtypes_PA_Group_t */
+typedef struct _MrvlIEtypes_PowerAdapt_Group_t
+{
+    MrvlIEtypesHeader_t Header;                               /**< Header */
+    PA_Group_t PA_Group[MAX_POWER_ADAPT_GROUP];                   /**< Power adapt group */
+} __ATTRIB_PACK__ MrvlIEtypes_PowerAdapt_Group_t;
+
+typedef struct _AutoTx_MacFrame_t
+{
+    u16 Interval;                               /**< in seconds */
+    u8 Priority;                                /**< User Priority: 0~7, ignored if non-WMM */
+    u8 Reserved;                                /**< set to 0 */
+    u16 FrameLen;                               /**< Length of MAC frame payload */
+    u8 DestMacAddr[ETH_ALEN];                           /**< Destination MAC address */
+    u8 SrcMacAddr[ETH_ALEN];                            /**< Source MAC address */
+    u8 Payload[];                                       /**< Payload */
+} __ATTRIB_PACK__ AutoTx_MacFrame_t;
+
+/** MrvlIEtypes_AutoTx_t */
+typedef struct _MrvlIEtypes_AutoTx_t
+{
+    MrvlIEtypesHeader_t Header;                     /**< Header */
+    AutoTx_MacFrame_t AutoTx_MacFrame;              /**< Auto Tx MAC frame */
+} __ATTRIB_PACK__ MrvlIEtypes_AutoTx_t;
+
+/** Auth type to be used in the Authentication portion of an Assoc seq */
+typedef struct
+{
+    /** Header */
+    MrvlIEtypesHeader_t Header;
+    /** Authentication type */
+    u16 AuthType;
+} __ATTRIB_PACK__ MrvlIEtypes_AuthType_t;
+
+/** Maximum subbands for 11d */
+#define MRVDRV_MAX_SUBBAND_802_11D		83
+/** Country code length */
+#define COUNTRY_CODE_LEN			3
+
+/** Data structure for Country IE*/
+typedef struct _IEEEtypes_SubbandSet
+{
+    u8 FirstChan;               /**< First channel */
+    u8 NoOfChan;                /**< Number of channels */
+    u8 MaxTxPwr;                    /**< Maximum Tx power */
+} __ATTRIB_PACK__ IEEEtypes_SubbandSet_t;
+
+typedef struct _IEEEtypes_CountryInfoSet
+{
+    u8 ElementId;                               /**< Element ID */
+    u8 Len;                                     /**< Length */
+    u8 CountryCode[COUNTRY_CODE_LEN];           /**< Country code */
+    IEEEtypes_SubbandSet_t Subband[1];      /**< Set of subbands */
+} __ATTRIB_PACK__ IEEEtypes_CountryInfoSet_t;
+
+typedef struct _IEEEtypes_CountryInfoFullSet
+{
+    u8 ElementId;                               /**< Element ID */
+    u8 Len;                                     /**< Length */
+    u8 CountryCode[COUNTRY_CODE_LEN];           /**< Country code */
+    /** Set of subbands */
+    IEEEtypes_SubbandSet_t Subband[MRVDRV_MAX_SUBBAND_802_11D];
+} __ATTRIB_PACK__ IEEEtypes_CountryInfoFullSet_t;
+
+typedef struct _MrvlIEtypes_DomainParamSet
+{
+    MrvlIEtypesHeader_t Header;                         /**< Header */
+    u8 CountryCode[COUNTRY_CODE_LEN];                           /**< Country code */
+    IEEEtypes_SubbandSet_t Subband[1];              /**< Set of subbands */
+} __ATTRIB_PACK__ MrvlIEtypes_DomainParamSet_t;
+
+/** Size of a TSPEC.  Used to allocate necessary buffer space in commands */
+#define WMM_TSPEC_SIZE              63
+
+/** Extra IE bytes allocated in messages for appended IEs after a TSPEC */
+#define WMM_ADDTS_EXTRA_IE_BYTES    256
+
+/** Extra TLV bytes allocated in messages for configuring WMM Queues */
+#define WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES 64
+
+/** Maximum number of AC QOS queues available in the driver/firmware */
+#define MAX_AC_QUEUES 4
+
+/** enum of WMM AC_QUEUES */
+typedef enum
+{
+    WMM_AC_BK,
+    WMM_AC_BE,
+    WMM_AC_VI,
+    WMM_AC_VO,
+} __ATTRIB_PACK__ wlan_wmm_ac_e;
+
+/** data structure of WMM QoS information */
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    /** QoS UAPSD */
+    u8 QosUAPSD:1;
+    /** Reserved */
+    u8 Reserved:3;
+    /** Parameter set count */
+    u8 ParaSetCount:4;
+#else
+    /** Parameter set count */
+    u8 ParaSetCount:4;
+    /** Reserved */
+    u8 Reserved:3;
+    /** QoS UAPSD */
+    u8 QosUAPSD:1;
+#endif
+} __ATTRIB_PACK__ IEEEtypes_WmmQosInfo_t;
+
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    /** Reserved */
+    u8 Reserved:1;
+    /** Aci */
+    u8 Aci:2;
+    /** Acm */
+    u8 Acm:1;
+    /** Aifsn */
+    u8 Aifsn:4;
+#else
+    /** Aifsn */
+    u8 Aifsn:4;
+    /** Acm */
+    u8 Acm:1;
+    /** Aci */
+    u8 Aci:2;
+    /** Reserved */
+    u8 Reserved:1;
+#endif
+} __ATTRIB_PACK__ IEEEtypes_WmmAciAifsn_t;
+
+/**  data structure of WMM ECW */
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    /** Maximum Ecw */
+    u8 EcwMax:4;
+    /** Minimum Ecw */
+    u8 EcwMin:4;
+#else
+    /** Minimum Ecw */
+    u8 EcwMin:4;
+    /** Maximum Ecw */
+    u8 EcwMax:4;
+#endif
+} __ATTRIB_PACK__ IEEEtypes_WmmEcw_t;
+
+/** data structure of WMM AC parameters  */
+typedef struct
+{
+    IEEEtypes_WmmAciAifsn_t AciAifsn;       /**< AciAifSn */
+    IEEEtypes_WmmEcw_t Ecw;                 /**< Ecw */
+    u16 TxopLimit;                          /**< Tx op limit */
+} __ATTRIB_PACK__ IEEEtypes_WmmAcParameters_t;
+
+/** data structure of WMM Info IE  */
+typedef struct
+{
+
+    /**
+     * WMM Info IE - Vendor Specific Header:
+     *   ElementId   [221/0xdd]
+     *   Len         [7] 
+     *   Oui         [00:50:f2]
+     *   OuiType     [2]
+     *   OuiSubType  [0]
+     *   Version     [1]
+     */
+    IEEEtypes_VendorHeader_t VendHdr;
+
+    /** QoS information */
+    IEEEtypes_WmmQosInfo_t QoSInfo;
+
+} __ATTRIB_PACK__ IEEEtypes_WmmInfo_t;
+
+/** data structure of WMM parameter IE  */
+typedef struct
+{
+    /**
+     * WMM Parameter IE - Vendor Specific Header:
+     *   ElementId   [221/0xdd]
+     *   Len         [24] 
+     *   Oui         [00:50:f2]
+     *   OuiType     [2]
+     *   OuiSubType  [1]
+     *   Version     [1]
+     */
+    IEEEtypes_VendorHeader_t VendHdr;
+
+    /** QoS information */
+    IEEEtypes_WmmQosInfo_t QoSInfo;
+    /** Reserved */
+    u8 Reserved;
+
+    /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */
+    IEEEtypes_WmmAcParameters_t AcParams[MAX_AC_QUEUES];
+
+} __ATTRIB_PACK__ IEEEtypes_WmmParameter_t;
+
+/**
+ *  @brief Firmware command structure to retrieve the firmware WMM status.
+ *
+ *  Used to retrieve the status of each WMM AC Queue in TLV 
+ *    format (MrvlIEtypes_WmmQueueStatus_t) as well as the current WMM
+ *    parameter IE advertised by the AP.  
+ *  
+ *  Used in response to a EVENT_WMM_STATUS_CHANGE event signalling
+ *    a QOS change on one of the ACs or a change in the WMM Parameter in
+ *    the Beacon.
+ *
+ *  TLV based command, byte arrays used for max sizing purpose. There are no 
+ *    arguments sent in the command, the TLVs are returned by the firmware.
+ */
+typedef struct
+{
+    /** Queue status TLV */
+    u8 queueStatusTlv[sizeof(MrvlIEtypes_WmmQueueStatus_t) * MAX_AC_QUEUES];
+    /** WMM parameter TLV */
+    u8 wmmParamTlv[sizeof(IEEEtypes_WmmParameter_t) + 2];
+
+}
+__ATTRIB_PACK__ HostCmd_DS_WMM_GET_STATUS;
+
+/**
+ *  @brief Enumeration for the command result from an ADDTS or DELTS command 
+ */
+typedef enum
+{
+    TSPEC_RESULT_SUCCESS = 0,
+    TSPEC_RESULT_EXEC_FAILURE = 1,
+    TSPEC_RESULT_TIMEOUT = 2,
+    TSPEC_RESULT_DATA_INVALID = 3,
+
+} __ATTRIB_PACK__ wlan_wmm_tspec_result_e;
+
+/**
+ *  @brief IOCTL structure to send an ADDTS request and retrieve the response.
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    instigate an ADDTS management frame with an appropriate TSPEC IE as well
+ *    as any additional IEs appended in the ADDTS Action frame.
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Firmware execution result
+    u32 timeout_ms;             //!< Timeout value in milliseconds
+
+    u8 ieeeStatusCode;          //!< IEEE status code
+
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC to send in the ADDTS
+
+    u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];       //!< ADDTS extra IE buffer
+
+} __ATTRIB_PACK__ wlan_ioctl_wmm_addts_req_t;
+
+/**
+ *  @brief IOCTL structure to send a DELTS request.
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    instigate an DELTS management frame with an appropriate TSPEC IE.
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Firmware execution result
+
+    u8 ieeeReasonCode;          //!< IEEE reason code sent, unused for WMM 
+
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC to send in the DELTS
+
+} __ATTRIB_PACK__ wlan_ioctl_wmm_delts_req_t;
+
+/**
+ *  @brief Internal command structure used in executing an ADDTS command.
+ *
+ *  Relay information between the IOCTL layer and the firmware command and 
+ *    command response procedures.
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ *  @sa wlan_cmd_wmm_addts_req
+ *  @sa wlan_cmdresp_wmm_addts_req
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Firmware execution result
+    u32 timeout_ms;             //!< Timeout value in milliseconds
+
+    u8 dialogToken;             //!< Dialog token
+    u8 ieeeStatusCode;          //!< IEEE status code
+
+    int tspecDataLen;           //!< TSPEC data length
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC to send in the ADDTS
+    u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];       //!< ADDTS extra IE buffer
+
+} wlan_cmd_wmm_addts_req_t;
+
+/**
+ *  @brief Internal command structure used in executing an DELTS command.
+ *
+ *  Relay information between the IOCTL layer and the firmware command and 
+ *    command response procedures.
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ *  @sa wlan_cmd_wmm_delts_req
+ *  @sa wlan_cmdresp_wmm_delts_req
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Firmware execution result
+
+    u8 dialogToken;             //!< Dialog token
+
+    u8 ieeeReasonCode;          //!< IEEE reson code sent
+
+    int tspecDataLen;           //!< TSPEC data length
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC data
+
+} wlan_cmd_wmm_delts_req_t;
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_ADDTS_REQ firmware command
+ *
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Command result
+    u32 timeout_ms;             //!< Timeout value in milliseconds
+
+    u8 dialogToken;             //!< Dialog token
+    u8 ieeeStatusCode;          //!< IEEE status code
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC data
+    u8 addtsExtraIEBuf[WMM_ADDTS_EXTRA_IE_BYTES];       //!< ADDTS extra IE buffer
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_ADDTS_REQ;
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_DELTS_REQ firmware command
+ */
+typedef struct
+{
+    wlan_wmm_tspec_result_e commandResult;      //!< Command result
+    u8 dialogToken;             //!< Dialog token
+    u8 ieeeReasonCode;          //!< IEEE reason code
+    u8 tspecData[WMM_TSPEC_SIZE];       //!< TSPEC data
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_DELTS_REQ;
+
+/**
+ *  @brief Enumeration for the action field in the Queue configure command
+ */
+typedef enum
+{
+    WMM_QUEUE_CONFIG_ACTION_GET = 0,
+    WMM_QUEUE_CONFIG_ACTION_SET = 1,
+    WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2,
+
+    WMM_QUEUE_CONFIG_ACTION_MAX
+} __ATTRIB_PACK__ wlan_wmm_queue_config_action_e;
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_QUEUE_CONFIG firmware cmd
+ *
+ *  Set/Get/Default the Queue parameters for a specific AC in the firmware.
+ *
+ */
+typedef struct
+{
+    wlan_wmm_queue_config_action_e action;      //!< Set, Get, or Default
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+
+    /** @brief MSDU lifetime expiry per 802.11e
+     *
+     *   - Ignored if 0 on a set command 
+     *   - Set to the 802.11e specified 500 TUs when defaulted
+     */
+    u16 msduLifetimeExpiry;
+
+    u8 tlvBuffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES];     //!< Not supported yet
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_QUEUE_CONFIG;
+
+/**
+ *  @brief Internal command structure used in executing a queue config command.
+ *
+ *  Relay information between the IOCTL layer and the firmware command and 
+ *    command response procedures.
+ *
+ *  @sa wlan_wmm_queue_config_ioctl
+ *  @sa wlan_cmd_wmm_queue_config
+ *  @sa wlan_cmdresp_wmm_queue_config
+ */
+typedef struct
+{
+    wlan_wmm_queue_config_action_e action;      //!< Set, Get, or Default
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+    u16 msduLifetimeExpiry;     //!< lifetime expiry in TUs
+
+    int tlvBufLen;              //!< Not supported yet
+    u8 tlvBuffer[WMM_QUEUE_CONFIG_EXTRA_TLV_BYTES];     //!< Not supported yet
+
+} wlan_cmd_wmm_queue_config_t;
+
+/**
+ *  @brief IOCTL structure to configure a specific AC Queue's parameters
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    get, set, or default the WMM AC queue parameters.
+ *
+ *  - msduLifetimeExpiry is ignored if set to 0 on a set command
+ *
+ *  @sa wlan_wmm_queue_config_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_queue_config_action_e action;      //!< Set, Get, or Default
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+    u16 msduLifetimeExpiry;     //!< lifetime expiry in TUs
+
+    u8 supportedRates[10];      //!< Not supported yet
+
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_config_t;
+
+/**
+ *   @brief Enumeration for the action field in the queue stats command
+ */
+typedef enum
+{
+    WMM_STATS_ACTION_START = 0,
+    WMM_STATS_ACTION_STOP = 1,
+    WMM_STATS_ACTION_GET_CLR = 2,
+    WMM_STATS_ACTION_SET_CFG = 3,       /* Not currently used */
+    WMM_STATS_ACTION_GET_CFG = 4,       /* Not currently used */
+
+    WMM_STATS_ACTION_MAX
+} __ATTRIB_PACK__ wlan_wmm_stats_action_e;
+
+/** Number of bins in the histogram for the HostCmd_DS_WMM_QUEUE_STATS */
+#define WMM_STATS_PKTS_HIST_BINS  7
+
+/**
+ *  @brief Command structure for the HostCmd_CMD_WMM_QUEUE_STATS firmware cmd
+ *
+ *  Turn statistical collection on/off for a given AC or retrieve the 
+ *    accumulated stats for an AC and clear them in the firmware.
+ */
+typedef struct
+{
+    wlan_wmm_stats_action_e action;     //!< Start, Stop, or Get 
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+
+    u16 pktCount;               //!< Number of successful packets transmitted
+    u16 pktLoss;                //!< Packets lost; not included in pktCount
+    u32 avgQueueDelay;          //!< Average Queue delay in microseconds
+    u32 avgTxDelay;             //!< Average Transmission delay in microseconds
+    u16 usedTime;               //!< Calculated used time - units of 32 microseconds
+    u16 policedTime;            //!< Calculated policed time - units of 32 microseconds
+
+    /** @brief Queue Delay Histogram; number of packets per queue delay range
+     * 
+     *  [0] -  0ms <= delay < 5ms
+     *  [1] -  5ms <= delay < 10ms
+     *  [2] - 10ms <= delay < 20ms
+     *  [3] - 20ms <= delay < 30ms
+     *  [4] - 30ms <= delay < 40ms
+     *  [5] - 40ms <= delay < 50ms
+     *  [6] - 50ms <= delay < msduLifetime (TUs)
+     */
+    u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
+
+    /** Reserved */
+    u16 reserved_u16_1;
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_QUEUE_STATS;
+
+/**
+ *  @brief IOCTL structure to start, stop, and get statistics for a WMM AC
+ *
+ *  IOCTL structure from the application layer relayed to firmware to 
+ *    start or stop statistical collection for a given AC.  Also used to 
+ *    retrieve and clear the collected stats on a given AC.
+ *
+ *  @sa wlan_wmm_queue_stats_ioctl
+ */
+typedef struct
+{
+    wlan_wmm_stats_action_e action;     //!< Start, Stop, or Get 
+    wlan_wmm_ac_e accessCategory;       //!< WMM_AC_BK(0) to WMM_AC_VO(3)
+    u16 pktCount;               //!< Number of successful packets transmitted  
+    u16 pktLoss;                //!< Packets lost; not included in pktCount    
+    u32 avgQueueDelay;          //!< Average Queue delay in microseconds
+    u32 avgTxDelay;             //!< Average Transmission delay in microseconds
+    u16 usedTime;               //!< Calculated used time - units of 32 microseconds
+    u16 policedTime;            //!< Calculated policed time - units of 32 microseconds
+
+    /** @brief Queue Delay Histogram; number of packets per queue delay range
+     * 
+     *  [0] -  0ms <= delay < 5ms
+     *  [1] -  5ms <= delay < 10ms
+     *  [2] - 10ms <= delay < 20ms
+     *  [3] - 20ms <= delay < 30ms
+     *  [4] - 30ms <= delay < 40ms
+     *  [5] - 40ms <= delay < 50ms
+     *  [6] - 50ms <= delay < msduLifetime (TUs)
+     */
+    u16 delayHistogram[WMM_STATS_PKTS_HIST_BINS];
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_stats_t;
+
+/** 
+ *  @brief IOCTL and command sub structure for a Traffic stream status.
+ */
+typedef struct
+{
+    u8 tid;                     //!< TSID: Range: 0->7
+    u8 valid;                   //!< TSID specified is valid 
+    u8 accessCategory;          //!< AC TSID is active on
+    u8 userPriority;            //!< UP specified for the TSID
+
+    u8 psb;                     //!< Power save mode for TSID: 0 (legacy), 1 (UAPSD)
+    u8 flowDir;                 //!< Upstream (0), Downlink(1), Bidirectional(3)
+    u16 mediumTime;             //!< Medium time granted for the TSID
+
+} __ATTRIB_PACK__ HostCmd_DS_WMM_TS_STATUS,
+    wlan_ioctl_wmm_ts_status_t, wlan_cmd_wmm_ts_status_t;
+
+/** 
+ *  @brief IOCTL sub structure for a specific WMM AC Status
+ */
+typedef struct
+{
+    /** WMM Acm */
+    u8 wmmAcm;
+    /** Flow required flag */
+    u8 flowRequired;
+    /** Flow created flag */
+    u8 flowCreated;
+    /** Disabled flag */
+    u8 disabled;
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_status_ac_t;
+
+/**
+ *  @brief IOCTL structure to retrieve the WMM AC Queue status
+ *
+ *  IOCTL structure from the application layer to retrieve:
+ *     - ACM bit setting for the AC
+ *     - Firmware status (flow required, flow created, flow disabled)
+ *
+ *  @sa wlan_wmm_queue_status_ioctl
+ */
+typedef struct
+{
+    /** WMM AC queue status */
+    wlan_ioctl_wmm_queue_status_ac_t acStatus[MAX_AC_QUEUES];
+} __ATTRIB_PACK__ wlan_ioctl_wmm_queue_status_t;
+
+/** Firmware status for a specific AC */
+typedef struct
+{
+    /** Disabled flag */
+    u8 Disabled;
+    /** Flow required flag */
+    u8 FlowRequired;
+    /** Flow created flag */
+    u8 FlowCreated;
+} WmmAcStatus_t;
+
+/* hostcmd.h */
+/*  802.11-related definitions */
+
+/** TxPD descriptor */
+typedef struct _TxPD
+{
+    /** Current Tx packet status */
+    u32 TxStatus;
+    /** Tx Control */
+    u32 TxControl;
+    /** Tx packet location */
+    u32 TxPacketLocation;
+    /** Tx packet length */
+    u16 TxPacketLength;
+    /**Destination MAC address */
+    u8 TxDestAddr[ETH_ALEN];
+    /** Pkt Priority */
+    u8 Priority;
+    /** Trasnit Pkt Flags*/
+    u8 Flags;
+    /** Amount of time the packet has been queued in the driver (units = 2ms)*/
+    u8 PktDelay_2ms;
+    /** Reserved */
+    u8 Reserved1;
+
+} __ATTRIB_PACK__ TxPD, *PTxPD;
+
+/** RxPD Descriptor */
+typedef struct _RxPD
+{
+        /** Current Rx packet status */
+    u16 RxStatus;
+
+        /** SNR */
+    u8 SNR;
+
+        /** Tx Control */
+    u8 RxControl;
+
+        /** Pkt Length */
+    u16 PktLen;
+
+        /** Noise Floor */
+    u8 NF;
+
+        /** Rx Packet Rate */
+    u8 RxRate;
+
+        /** Pkt offset */
+    u32 PktOffset;
+    /** Received packet type */
+    u8 RxPacketType;
+    /** Reserved */
+    u8 Reserved_1[3];
+        /** Pkt Priority */
+    u8 Priority;
+    /** Reserved */
+    u8 Reserved[3];
+
+} __ATTRIB_PACK__ RxPD, *PRxPD;
+
+#if defined(__KERNEL__)
+
+/** CmdCtrlNode */
+typedef struct _CmdCtrlNode
+{
+    /* CMD link list */
+    struct list_head list;
+
+    u32 Status;
+
+    /* CMD ID */
+    WLAN_OID cmd_oid;
+
+    /*CMD wait option: wait for finish or no wait */
+    u16 wait_option;
+
+    /* command parameter */
+    void *pdata_buf;
+
+    /*command data */
+    u8 *BufVirtualAddr;
+
+    u16 CmdFlags;
+
+    /* wait queue */
+    u16 CmdWaitQWoken;
+    wait_queue_head_t cmdwait_q __ATTRIB_ALIGN__;
+} __ATTRIB_PACK__ CmdCtrlNode, *PCmdCtrlNode;
+
+#endif
+
+/** MRVL_WEP_KEY */
+typedef struct _MRVL_WEP_KEY
+{
+    /** Length */
+    u32 Length;
+    /** WEP key index */
+    u32 KeyIndex;
+    /** WEP key length */
+    u32 KeyLength;
+    /** WEP keys */
+    u8 KeyMaterial[MRVL_KEY_BUFFER_SIZE_IN_BYTE];
+} __ATTRIB_PACK__ MRVL_WEP_KEY, *PMRVL_WEP_KEY;
+
+/** Unsigned long long */
+typedef ULONGLONG WLAN_802_11_KEY_RSC;
+
+/** WLAN_802_11_KEY */
+typedef struct _WLAN_802_11_KEY
+{
+    /** Length */
+    u32 Length;
+    /** Key index */
+    u32 KeyIndex;
+    /** Key length */
+    u32 KeyLength;
+    /** BSSID */
+    WLAN_802_11_MAC_ADDRESS BSSID;
+    /** Key RSC */
+    WLAN_802_11_KEY_RSC KeyRSC;
+    /** Key */
+    u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+} __ATTRIB_PACK__ WLAN_802_11_KEY;
+
+/** MRVL_WPA_KEY */
+typedef struct _MRVL_WPA_KEY
+{
+    /** Key index */
+    u32 KeyIndex;
+    /** Key length */
+    u32 KeyLength;
+    /** Key RSC */
+    u32 KeyRSC;
+    /** Key material */
+    u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+} MRVL_WPA_KEY, *PMRVL_WPA_KEY;
+
+/** MRVL_WLAN_WPA_KEY */
+typedef struct _MRVL_WLAN_WPA_KEY
+{
+    /** Encryption key */
+    u8 EncryptionKey[16];
+    /** MIC key 1 */
+    u8 MICKey1[8];
+    /** MIC key 2 */
+    u8 MICKey2[8];
+} MRVL_WLAN_WPA_KEY, *PMRVL_WLAN_WPA_KEY;
+
+/** Received Signal Strength Indication  in dBm*/
+typedef LONG WLAN_802_11_RSSI;
+
+/** WLAN_802_11_WEP */
+typedef struct _WLAN_802_11_WEP
+{
+        /** Length of this structure */
+    u32 Length;
+
+        /** 0 is the per-client key, 1-N are the global keys */
+    u32 KeyIndex;
+
+        /** length of key in bytes */
+    u32 KeyLength;
+
+        /** variable length depending on above field */
+    u8 KeyMaterial[1];
+} __ATTRIB_PACK__ WLAN_802_11_WEP;
+
+/** WLAN_802_11_SSID */
+typedef struct _WLAN_802_11_SSID
+{
+        /** SSID Length*/
+    u32 SsidLength;
+
+        /** SSID information field */
+    u8 Ssid[MRVDRV_MAX_SSID_LENGTH];
+} __ATTRIB_PACK__ WLAN_802_11_SSID;
+
+/** Framentation threshold */
+typedef u32 WLAN_802_11_FRAGMENTATION_THRESHOLD;
+/** RTS threshold */
+typedef u32 WLAN_802_11_RTS_THRESHOLD;
+/** 802.11 antenna */
+typedef u32 WLAN_802_11_ANTENNA;
+
+/** wlan_offset_value */
+typedef struct _wlan_offset_value
+{
+    /** Offset */
+    u32 offset;
+    /** Value */
+    u32 value;
+} wlan_offset_value;
+
+/** WLAN_802_11_FIXED_IEs */
+typedef struct _WLAN_802_11_FIXED_IEs
+{
+    /** Timestamp */
+    u8 Timestamp[8];
+    /** Beacon interval */
+    u16 BeaconInterval;
+    /** Capabilities*/
+    u16 Capabilities;
+} WLAN_802_11_FIXED_IEs;
+
+/** WLAN_802_11_VARIABLE_IEs */
+typedef struct _WLAN_802_11_VARIABLE_IEs
+{
+    /** Element ID */
+    u8 ElementID;
+    /** Length */
+    u8 Length;
+    /** IE data */
+    u8 data[1];
+} WLAN_802_11_VARIABLE_IEs;
+
+/** WLAN_802_11_AI_RESFI */
+typedef struct _WLAN_802_11_AI_RESFI
+{
+    /** Capabilities */
+    u16 Capabilities;
+    /** Status code */
+    u16 StatusCode;
+    /** Association ID */
+    u16 AssociationId;
+} WLAN_802_11_AI_RESFI;
+
+/** WLAN_802_11_AI_REQFI */
+typedef struct _WLAN_802_11_AI_REQFI
+{
+    /** Capabilities */
+    u16 Capabilities;
+    /** Listen interval */
+    u16 ListenInterval;
+    /** Current AP address */
+    WLAN_802_11_MAC_ADDRESS CurrentAPAddress;
+} WLAN_802_11_AI_REQFI;
+
+/* Define general data structure */
+/** HostCmd_DS_GEN */
+typedef struct _HostCmd_DS_GEN
+{
+    /** Command */
+    u16 Command;
+    /** Size */
+    u16 Size;
+    /** Sequence number */
+    u16 SeqNum;
+    /** Result */
+    u16 Result;
+} __ATTRIB_PACK__ HostCmd_DS_GEN, HostCmd_DS_802_11_DEEP_SLEEP;
+
+/** Size of HostCmd_DS_GEN */
+#define S_DS_GEN    sizeof(HostCmd_DS_GEN)
+/*
+ * Define data structure for HostCmd_CMD_GET_HW_SPEC
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+/** HostCmd_DS_GET_HW_SPEC */
+typedef struct _HostCmd_DS_GET_HW_SPEC
+{
+        /** HW Interface version number */
+    u16 HWIfVersion;
+
+        /** HW version number */
+    u16 Version;
+
+        /** Max number of TxPD FW can handle*/
+    u16 NumOfTxPD;
+
+        /** Max no of Multicast address  */
+    u16 NumOfMCastAdr;
+
+        /** MAC address */
+    u8 PermanentAddr[ETH_ALEN];
+
+        /** Region Code */
+    u16 RegionCode;
+
+        /** Number of antenna used */
+    u16 NumberOfAntenna;
+
+        /** FW release number, example 0x1234=1.2.3.4 */
+    u32 FWReleaseNumber;
+
+    /** Reserved field */
+    u32 Reserved_1;
+
+    /** Reserved field */
+    u32 Reserved_2;
+
+    /** Reserved field */
+    u32 Reserved_3;
+
+        /** FW/HW Capability */
+    u32 fwCapInfo;
+} __ATTRIB_PACK__ HostCmd_DS_GET_HW_SPEC;
+
+typedef struct _HostCmd_DS_802_11_SUBSCRIBE_EVENT
+{
+    /** Action */
+    u16 Action;
+    /** Events */
+    u16 Events;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SUBSCRIBE_EVENT;
+
+/* 
+ * This scan handle Country Information IE(802.11d compliant) 
+ * Define data structure for HostCmd_CMD_802_11_SCAN 
+ */
+/** HostCmd_DS_802_11_SCAN */
+typedef struct _HostCmd_DS_802_11_SCAN
+{
+    /** BSS type */
+    u8 BSSType;
+    /** BSSID */
+    u8 BSSID[ETH_ALEN];
+    /** TLV buffer */
+    u8 TlvBuffer[1];
+    /* MrvlIEtypes_SsIdParamSet_t   SsIdParamSet; 
+     * MrvlIEtypes_ChanListParamSet_t       ChanListParamSet;
+     * MrvlIEtypes_RatesParamSet_t  OpRateSet; 
+     * */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SCAN;
+
+typedef struct _HostCmd_DS_802_11_SCAN_RSP
+{
+    /** Size of BSS descriptor */
+    u16 BSSDescriptSize;
+    /** Numner of sets */
+    u8 NumberOfSets;
+    /** BSS descriptor and TLV buffer */
+    u8 BssDescAndTlvBuffer[1];
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SCAN_RSP;
+
+/** HostCmd_CMD_802_11_GET_LOG */
+typedef struct _HostCmd_DS_802_11_GET_LOG
+{
+    /** Number of multicast transmitted frames */
+    u32 mcasttxframe;
+    /** Number of failures */
+    u32 failed;
+    /** Number of retries */
+    u32 retry;
+    /** Number of multiretries */
+    u32 multiretry;
+    /** Number of duplicate frames */
+    u32 framedup;
+    /** Number of RTS success */
+    u32 rtssuccess;
+    /** Number of RTS failure */
+    u32 rtsfailure;
+    /** Number of acknowledgement failure */
+    u32 ackfailure;
+    /** Number of fragmented packets received */
+    u32 rxfrag;
+    /** Number of multicast frames received */
+    u32 mcastrxframe;
+    /** FCS error */
+    u32 fcserror;
+    /** Number of transmitted frames */
+    u32 txframe;
+    /** Reserved field */
+    u32 reserved;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_GET_LOG;
+
+/**  HostCmd_CMD_MAC_CONTROL */
+typedef struct _HostCmd_DS_MAC_CONTROL
+{
+    /** Action */
+    u16 Action;
+    /** Reserved field */
+    u16 Reserved;
+} __ATTRIB_PACK__ HostCmd_DS_MAC_CONTROL;
+
+/**  HostCmd_CMD_MAC_MULTICAST_ADR */
+typedef struct _HostCmd_DS_MAC_MULTICAST_ADR
+{
+    /** Action */
+    u16 Action;
+    /** Number of addresses */
+    u16 NumOfAdrs;
+    /** List of MAC */
+    u8 MACList[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+} __ATTRIB_PACK__ HostCmd_DS_MAC_MULTICAST_ADR;
+
+/**  HostCmd_CMD_802_11_DEAUTHENTICATE */
+typedef struct _HostCmd_DS_802_11_DEAUTHENTICATE
+{
+    /** MAC address */
+    u8 MacAddr[ETH_ALEN];
+    /** Deauthentication resaon code */
+    u16 ReasonCode;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_DEAUTHENTICATE;
+
+/** HostCmd_DS_802_11_ASSOCIATE */
+typedef struct _HostCmd_DS_802_11_ASSOCIATE
+{
+    /** Peer STA address */
+    u8 PeerStaAddr[ETH_ALEN];
+    /** Capability information */
+    IEEEtypes_CapInfo_t CapInfo;
+    /** Listen interval */
+    u16 ListenInterval;
+    /** Reserved field */
+    u8 Reserved1[3];
+
+    /*
+     *  MrvlIEtypes_SsIdParamSet_t  SsIdParamSet;
+     *  MrvlIEtypes_PhyParamSet_t   PhyParamSet;
+     *  MrvlIEtypes_SsParamSet_t    SsParamSet;
+     *  MrvlIEtypes_RatesParamSet_t RatesParamSet;
+     */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_ASSOCIATE;
+
+/** HostCmd_CMD_802_11_ASSOCIATE response */
+typedef struct
+{
+    /** Association response structure */
+    IEEEtypes_AssocRsp_t assocRsp;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_ASSOCIATE_RSP;
+
+/**  HostCmd_CMD_802_11_AD_HOC_START response */
+typedef struct _HostCmd_DS_802_11_AD_HOC_RESULT
+{
+    /** Padding */
+    u8 PAD[3];
+    /** AdHoc BSSID */
+    u8 BSSID[ETH_ALEN];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_RESULT;
+
+/**  HostCmd_CMD_802_11_SET_WEP */
+typedef struct _HostCmd_DS_802_11_SET_WEP
+{
+        /** ACT_ADD, ACT_REMOVE or ACT_ENABLE  */
+    u16 Action;
+
+        /** Key Index selected for Tx */
+    u16 KeyIndex;
+
+    /* 40, 128bit or TXWEP */
+    /** Type of WEP for key 1 */
+    u8 WEPTypeForKey1;
+
+    /** Type of WEP for key 2 */
+    u8 WEPTypeForKey2;
+    /** Type of WEP for key 3 */
+    u8 WEPTypeForKey3;
+    /** Type of WEP for key 4 */
+    u8 WEPTypeForKey4;
+    /** WEP key 1 */
+    u8 WEP1[16];
+    /** WEP key 2 */
+    u8 WEP2[16];
+    /** WEP key 3 */
+    u8 WEP3[16];
+    /** WEP key 4 */
+    u8 WEP4[16];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SET_WEP;
+
+/** HostCmd_DS_802_11_AD_HOC_STOP */
+typedef struct _HostCmd_DS_802_11_AD_HOC_STOP
+{
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_STOP;
+
+/**  HostCmd_CMD_802_11_SNMP_MIB */
+typedef struct _HostCmd_DS_802_11_SNMP_MIB
+{
+    /** SNMP query type */
+    u16 QueryType;
+    /** SNMP object ID */
+    u16 OID;
+    /** SNMP buffer size */
+    u16 BufSize;
+    /** Value */
+    u8 Value[128];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SNMP_MIB;
+
+/** HostCmd_CMD_MAC_REG_ACCESS */
+typedef struct _HostCmd_DS_MAC_REG_ACCESS
+{
+    /** Action */
+    u16 Action;
+    /** MAC register offset */
+    u16 Offset;
+    /** MAC register value */
+    u32 Value;
+} __ATTRIB_PACK__ HostCmd_DS_MAC_REG_ACCESS;
+
+/** HostCmd_CMD_BBP_REG_ACCESS */
+typedef struct _HostCmd_DS_BBP_REG_ACCESS
+{
+    /** Acion */
+    u16 Action;
+    /** BBP register offset */
+    u16 Offset;
+    /** BBP register value */
+    u8 Value;
+    /** Reserved field */
+    u8 Reserved[3];
+} __ATTRIB_PACK__ HostCmd_DS_BBP_REG_ACCESS;
+
+/**  HostCmd_CMD_RF_REG_ACCESS */
+typedef struct _HostCmd_DS_RF_REG_ACCESS
+{
+    /** Action */
+    u16 Action;
+    /** RF register offset */
+    u16 Offset;
+    /** RF register value */
+    u8 Value;
+    /** Reserved field */
+    u8 Reserved[3];
+} __ATTRIB_PACK__ HostCmd_DS_RF_REG_ACCESS;
+
+/** HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef struct _HostCmd_DS_802_11_RADIO_CONTROL
+{
+    /** Action */
+    u16 Action;
+    /** Control */
+    u16 Control;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RADIO_CONTROL;
+
+/* HostCmd_DS_802_11_SLEEP_PARAMS */
+typedef struct _HostCmd_DS_802_11_SLEEP_PARAMS
+{
+        /** ACT_GET/ACT_SET */
+    u16 Action;
+
+        /** Sleep clock error in ppm */
+    u16 Error;
+
+        /** Wakeup offset in usec */
+    u16 Offset;
+
+        /** Clock stabilization time in usec */
+    u16 StableTime;
+
+        /** Control periodic calibration */
+    u8 CalControl;
+
+        /** Control the use of external sleep clock */
+    u8 ExternalSleepClk;
+
+        /** Reserved field, should be set to zero */
+    u16 Reserved;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SLEEP_PARAMS;
+
+/* HostCmd_DS_802_11_SLEEP_PERIOD */
+typedef struct _HostCmd_DS_802_11_SLEEP_PERIOD
+{
+        /** ACT_GET/ACT_SET */
+    u16 Action;
+
+        /** Sleep Period in msec */
+    u16 Period;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_SLEEP_PERIOD;
+
+/* HostCmd_DS_802_11_BCA_TIMESHARE */
+typedef struct _HostCmd_DS_802_11_BCA_TIMESHARE
+{
+    /** ACT_GET/ACT_SET */
+    u16 Action;
+
+    /** Type: WLAN, BT */
+    u16 TrafficType;
+
+    /** 20msec - 60000msec */
+    u32 TimeShareInterval;
+
+    /** PTA arbiter time in msec */
+    u32 BTTime;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BCA_TIMESHARE;
+
+/* HostCmd_DS_802_11_INACTIVITY_TIMEOUT */
+typedef struct _HostCmd_DS_802_11_INACTIVITY_TIMEOUT
+{
+    /** ACT_GET/ACT_SET */
+    u16 Action;
+
+    /** Inactivity timeout in msec */
+    u16 Timeout;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_INACTIVITY_TIMEOUT;
+
+/** HostCmd_CMD_802_11_RF_CHANNEL */
+typedef struct _HostCmd_DS_802_11_RF_CHANNEL
+{
+    /** Action */
+    u16 Action;
+    /** Current channel */
+    u16 CurrentChannel;
+    /** RF type */
+    u16 RFType;
+    /** Reserved field */
+    u16 Reserved;
+    /** List of channels */
+    u8 ChannelList[32];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_CHANNEL;
+
+/**  HostCmd_CMD_802_11_RSSI */
+typedef struct _HostCmd_DS_802_11_RSSI
+{
+        /** weighting factor */
+    u16 N;
+
+    /** Reserved field 0 */
+    u16 Reserved_0;
+    /** Reserved field 1 */
+    u16 Reserved_1;
+    /** Reserved field 2 */
+    u16 Reserved_2;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RSSI;
+
+/** HostCmd_DS_802_11_RSSI_RSP */
+typedef struct _HostCmd_DS_802_11_RSSI_RSP
+{
+    /** Signal to Noise ratio */
+    u16 SNR;
+    /** Noise Floor */
+    u16 NoiseFloor;
+    /** Average Signal to Noise ratio */
+    u16 AvgSNR;
+    /** Average Noise Floor */
+    u16 AvgNoiseFloor;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RSSI_RSP;
+
+/** HostCmd_DS_802_11_MAC_ADDRESS */
+typedef struct _HostCmd_DS_802_11_MAC_ADDRESS
+{
+    /** Action */
+    u16 Action;
+    /** MAC address */
+    u8 MacAdd[ETH_ALEN];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_MAC_ADDRESS;
+
+/** HostCmd_CMD_802_11_RF_TX_POWER */
+typedef struct _HostCmd_DS_802_11_RF_TX_POWER
+{
+    /** Action */
+    u16 Action;
+    /** Current power level */
+    u16 CurrentLevel;
+    /** Maximum power */
+    u8 MaxPower;
+    /** Minimum power */
+    u8 MinPower;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_TX_POWER;
+
+/** HostCmd_CMD_802_11_RF_ANTENNA */
+typedef struct _HostCmd_DS_802_11_RF_ANTENNA
+{
+    /** Action */
+    u16 Action;
+
+    /**  Number of antennas or 0xffff(diversity) */
+    u16 AntennaMode;
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RF_ANTENNA;
+
+/** HostCmd_CMD_802_11_PS_MODE */
+typedef struct _HostCmd_DS_802_11_PS_MODE
+{
+    /** Action */
+    u16 Action;
+    /** NULL packet interval */
+    u16 NullPktInterval;
+    /** Multiple DTIM */
+    u16 MultipleDtim;
+    /** Beacon miss timeout */
+    u16 BCNMissTimeOut;
+    /** Local listen interval */
+    u16 LocalListenInterval;
+    /** AdHoc awake period */
+    u16 AdhocAwakePeriod;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_PS_MODE;
+
+/** PS_CMD_ConfirmSleep */
+typedef struct _PS_CMD_ConfirmSleep
+{
+    /** Command */
+    u16 Command;
+    /** Size */
+    u16 Size;
+    /** Sequence number */
+    u16 SeqNum;
+    /** Result */
+    u16 Result;
+
+    /** Action */
+    u16 Action;
+    /** Reserved */
+    u16 Reserved1;
+    /** Multiple DTIM */
+    u16 MultipleDtim;
+    /** Reserved */
+    u16 Reserved;
+    /** Local listen interval */
+    u16 LocalListenInterval;
+} __ATTRIB_PACK__ PS_CMD_ConfirmSleep, *PPS_CMD_ConfirmSleep;
+
+/** HostCmd_CMD_802_11_FW_WAKE_METHOD */
+typedef struct _HostCmd_DS_802_11_FW_WAKEUP_METHOD
+{
+    /** Action */
+    u16 Action;
+    /** Method */
+    u16 Method;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_FW_WAKEUP_METHOD;
+
+/** HostCmd_DS_802_11_RATE_ADAPT_RATESET */
+typedef struct _HostCmd_DS_802_11_RATE_ADAPT_RATESET
+{
+    /** Action */
+    u16 Action;
+    /** Hardware drop rate mode */
+    u16 HWRateDropMode;
+    /** Rate bitmap */
+    u16 Bitmap;
+    /** Rate adapt threshold */
+    u16 Threshold;
+    /** Final rate */
+    u16 FinalRate;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_RATE_ADAPT_RATESET;
+
+/** HostCmd_DS_802_11_AD_HOC_START*/
+typedef struct _HostCmd_DS_802_11_AD_HOC_START
+{
+    /** AdHoc SSID */
+    u8 SSID[MRVDRV_MAX_SSID_LENGTH];
+    /** BSS type */
+    u8 BSSType;
+    /** Beacon period */
+    u16 BeaconPeriod;
+    /** DTIM period */
+    u8 DTIMPeriod;
+    /** SS parameter set */
+    IEEEtypes_SsParamSet_t SsParamSet;
+    /** PHY parameter set */
+    IEEEtypes_PhyParamSet_t PhyParamSet;
+    /** Reserved field */
+    u16 Reserved1;
+    /** Capability information */
+    IEEEtypes_CapInfo_t Cap;
+    /** Supported data rates */
+    u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_START;
+
+/** AdHoc_BssDesc_t */
+typedef struct _AdHoc_BssDesc_t
+{
+    /** BSSID */
+    u8 BSSID[ETH_ALEN];
+    /** SSID */
+    u8 SSID[MRVDRV_MAX_SSID_LENGTH];
+    /** BSS type */
+    u8 BSSType;
+    /** Beacon period */
+    u16 BeaconPeriod;
+    /** DTIM period */
+    u8 DTIMPeriod;
+    /** Tiemstamp */
+    u8 TimeStamp[8];
+    /** Local time */
+    u8 LocalTime[8];
+    /** PHY parameter set */
+    IEEEtypes_PhyParamSet_t PhyParamSet;
+    /** SS parameter set */
+    IEEEtypes_SsParamSet_t SsParamSet;
+    /** Capability information */
+    IEEEtypes_CapInfo_t Cap;
+    /** Supported data rates */
+    u8 DataRates[HOSTCMD_SUPPORTED_RATES];
+
+    /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE.      It is used below in the
+     *      Adhoc join command and will cause a binary layout mismatch with 
+     *      the firmware 
+     */
+} __ATTRIB_PACK__ AdHoc_BssDesc_t;
+
+/** HostCmd_DS_802_11_AD_HOC_JOIN */
+typedef struct _HostCmd_DS_802_11_AD_HOC_JOIN
+{
+    /** AdHoc BSS descriptor */
+    AdHoc_BssDesc_t BssDescriptor;
+    /** Reserved field */
+    u16 Reserved1;
+    /** Reserved field */
+    u16 Reserved2;
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AD_HOC_JOIN;
+
+typedef union _KeyInfo_WEP_t
+{
+    /** Reserved */
+    u8 Reserved;
+
+    /** bits 1-4: Specifies the index of key */
+    u8 WepKeyIndex;
+
+    /** bit 0: Specifies that this key is 
+     * to be used as the default for TX data packets 
+     */
+    u8 isWepDefaultKey;
+} __ATTRIB_PACK__ KeyInfo_WEP_t;
+
+typedef union _KeyInfo_TKIP_t
+{
+    /** Reserved */
+    u8 Reserved;
+
+    /** bit 2: Specifies that this key is 
+     * enabled and valid to use */
+    u8 isKeyEnabled;
+
+    /** bit 1: Specifies that this key is
+     * to be used as the unicast key */
+    u8 isUnicastKey;
+
+    /** bit 0: Specifies that this key is 
+     * to be used as the multicast key */
+    u8 isMulticastKey;
+} __ATTRIB_PACK__ KeyInfo_TKIP_t;
+
+typedef union _KeyInfo_AES_t
+{
+    /** Reserved */
+    u8 Reserved;
+
+    /** bit 2: Specifies that this key is
+     * enabled and valid to use */
+    u8 isKeyEnabled;
+
+    /** bit 1: Specifies that this key is
+     * to be used as the unicast key */
+    u8 isUnicastKey;
+
+    /** bit 0: Specifies that this key is 
+     * to be used as the multicast key */
+    u8 isMulticastKey;
+} __ATTRIB_PACK__ KeyInfo_AES_t;
+
+/** KeyMaterial_TKIP_t */
+typedef struct _KeyMaterial_TKIP_t
+{
+    /** TKIP encryption/decryption key */
+    u8 TkipKey[16];
+
+    /** TKIP TX MIC Key */
+    u8 TkipTxMicKey[16];
+
+    /** TKIP RX MIC Key */
+    u8 TkipRxMicKey[16];
+} __ATTRIB_PACK__ KeyMaterial_TKIP_t, *PKeyMaterial_TKIP_t;
+
+/** KeyMaterial_AES_t */
+typedef struct _KeyMaterial_AES_t
+{
+    /** AES encryption/decryption key */
+    u8 AesKey[16];
+} __ATTRIB_PACK__ KeyMaterial_AES_t, *PKeyMaterial_AES_t;
+
+/** MrvlIEtype_KeyParamSet_t */
+typedef struct _MrvlIEtype_KeyParamSet_t
+{
+    /** Type ID */
+    u16 Type;
+
+    /** Length of Payload */
+    u16 Length;
+
+    /** Type of Key: WEP=0, TKIP=1, AES=2 */
+    u16 KeyTypeId;
+
+    /** Key Control Info specific to a KeyTypeId */
+    u16 KeyInfo;
+
+    /** Length of key */
+    u16 KeyLen;
+
+    /** Key material of size KeyLen */
+    u8 Key[32];
+} __ATTRIB_PACK__ MrvlIEtype_KeyParamSet_t, *PMrvlIEtype_KeyParamSet_t;
+
+/** HostCmd_DS_802_11_KEY_MATERIAL */
+typedef struct _HostCmd_DS_802_11_KEY_MATERIAL
+{
+    /** Action */
+    u16 Action;
+
+    /** Key parameter set */
+    MrvlIEtype_KeyParamSet_t KeyParamSet;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_KEY_MATERIAL;
+
+/** HostCmd_DS_802_11_HOST_SLEEP_CFG */
+typedef struct _HostCmd_DS_HOST_802_11_HOST_SLEEP_CFG
+{
+       /** bit0=1: non-unicast data
+        * bit1=1: unicast data
+        * bit2=1: mac events
+     	* bit3=1: magic packet 
+	*/
+    u32 conditions;
+
+    /** GPIO */
+    u8 gpio;
+
+        /** in milliseconds */
+    u8 gap;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_HOST_SLEEP_CFG;
+
+#define CAL_DATA_HEADER_LEN	6       /**< sizeof(HostCmd_DS_802_11_CAL_DATA_EXT)-sizeof(CalData) */
+
+/** HostCmd_DS_802_11_CAL_DATA_EXT */
+typedef struct _HostCmd_DS_802_11_CAL_DATA_EXT
+{
+    /** Action */
+    u16 Action;
+    /** Revision number */
+    u16 Revision;
+    /** Calibration data length */
+    u16 CalDataLen;
+    /** Calibration data */
+    u8 CalData[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CAL_DATA_EXT;
+
+typedef struct _HostCmd_DS_802_11_CFG_DATA
+{
+    /** Action */
+    u16 u16Action;
+    /** Type */
+    u16 u16Type;
+    /** Data length */
+    u16 u16DataLen;
+    /** Data */
+    u8 u8Data[1];
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CFG_DATA, *pHostCmd_DS_802_11_CFG_DATA;
+
+/** HostCmd_DS_802_11_EEPROM_ACCESS */
+typedef struct _HostCmd_DS_802_11_EEPROM_ACCESS
+{
+    /** Action */
+    u16 Action;
+
+   /** multiple 4 */
+    u16 Offset;
+    /** Number of bytes */
+    u16 ByteCount;
+    /** Value */
+    u8 Value;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_EEPROM_ACCESS;
+
+/** HostCmd_DS_802_11_BG_SCAN_CONFIG */
+typedef struct _HostCmd_DS_802_11_BG_SCAN_CONFIG
+{
+    /** Action */
+    u8 Action;
+
+    /** Configuration type */
+    u8 ConfigType;
+
+    /** 
+     *  Enable/Disable
+     *  0 - Disable
+     *  1 - Enable 
+     */
+    u8 Enable;
+
+    /**
+     *  bssType
+     *  1 - Infrastructure
+     *  2 - IBSS
+     *  3 - any 
+     */
+    u8 BssType;
+
+    /** 
+     * ChannelsPerScan 
+     *   Number of channels to scan during a single scanning opportunity
+     */
+    u8 ChannelsPerScan;
+
+    /** Reserved */
+    u8 Reserved1[3];
+
+    /** ScanInterval */
+    u32 ScanInterval;
+
+    /** Reserved */
+    u8 Reserved2[4];
+
+    /** 
+     * ReportConditions
+     * - SSID Match
+     * - Exceed SNR Threshold
+     * - Exceed RSSI Threshold
+     * - Complete all channels
+     */
+    u32 ReportConditions;
+
+    /** Reserved */
+    u8 Reserved3[2];
+
+    /*  Attach TLV based parameters as needed:
+     *
+     *  MrvlIEtypes_SsIdParamSet_t          Set specific SSID filter
+     *  MrvlIEtypes_ChanListParamSet_t      Set the channels & channel params
+     *  MrvlIEtypes_NumProbes_t             Number of probes per SSID/broadcast
+     *  MrvlIEtypes_WildCardSsIdParamSet_t  Wildcard SSID matching patterns
+     *  MrvlIEtypes_SnrThreshold_t          SNR Threshold for match/report  
+     */
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_CONFIG;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY */
+typedef struct _HostCmd_DS_802_11_BG_SCAN_QUERY
+{
+    /** Flush */
+    u8 Flush;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_QUERY;
+
+/** HostCmd_DS_802_11_BG_SCAN_QUERY_RSP */
+typedef struct _HostCmd_DS_802_11_BG_SCAN_QUERY_RSP
+{
+    /** Report condition */
+    u32 ReportCondition;
+    /** Scan response */
+    HostCmd_DS_802_11_SCAN_RSP scanresp;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_BG_SCAN_QUERY_RSP;
+
+/** HostCmd_DS_802_11_TPC_CFG */
+typedef struct _HostCmd_DS_802_11_TPC_CFG
+{
+    /** Action */
+    u16 Action;
+    /** Enable flag */
+    u8 Enable;
+    /** P0 value */
+    s8 P0;
+    /** P1 value */
+    s8 P1;
+    /** P2 value */
+    s8 P2;
+    /** SNR */
+    u8 UseSNR;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_TPC_CFG;
+
+/** HostCmd_DS_802_11_LED_CTRL */
+typedef struct _HostCmd_DS_802_11_LED_CTRL
+{
+    u16 Action;                                 /**< 0 = ACT_GET; 1 = ACT_SET; */
+    u16 LedNums;                                 /**< Numbers of LEDs supported */
+    MrvlIEtypes_LedGpio_t LedGpio;                      /**< LED GPIO */
+    MrvlIEtypes_LedBehavior_t LedBehavior[1];           /**< LED behavior */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_LED_CTRL;
+
+/** HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT */
+typedef struct _HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT
+{
+        /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    /** Enable power adapt */
+    u16 EnablePA;               /* 0 = disable; 1 = enable; */
+    /** Power adapt group */
+    MrvlIEtypes_PowerAdapt_Group_t PowerAdaptGroup;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_POWER_ADAPT_CFG_EXT;
+
+typedef struct _HostCmd_DS_SDIO_PULL_CTRL
+{
+    u16 Action;                 /**< 0: get; 1: set*/
+    u16 PullUp;                 /**< the delay of pulling up in us */
+    u16 PullDown;               /**< the delay of pulling down in us */
+} __ATTRIB_PACK__ HostCmd_DS_SDIO_PULL_CTRL;
+typedef struct _HostCmd_DS_802_11_IBSS_Status
+{
+    /** Action */
+    u16 Action;
+    /** Enable */
+    u16 Enable;
+    /** BSSID */
+    u8 BSSID[ETH_ALEN];
+    /** Beacon interval */
+    u16 BeaconInterval;
+    /** ATIM window interval */
+    u16 ATIMWindow;
+    /** User G rate protection */
+    u16 UseGRateProtection;
+} __ATTRIB_PACK__ HostCmd_DS_802_11_IBSS_Status;
+
+/** RC4 cipher test */
+#define CIPHER_TEST_RC4 (1)
+/** AES cipher test */
+#define CIPHER_TEST_AES (2)
+/** AES key wrap cipher test */
+#define CIPHER_TEST_AES_KEY_WRAP (3)
+
+/** HostCmd_DS_802_11_CRYPTO */
+typedef struct _HostCmd_DS_802_11_CRYPTO
+{
+    u16 EncDec;                 //!< Decrypt=0, Encrypt=1
+    u16 Algorithm;              //!<  RC4=1 AES=2 , AES_KEY_WRAP=3
+    u16 KeyIVLength;            //!< Length of Key IV (bytes)           
+    u8 KeyIV[32];               //!< Key IV
+    u16 KeyLength;              //!< Length of Key (bytes)
+    u8 Key[32];                 //!< Key
+    /* MrvlIEtypes_Data_t   data  Plain text if EncDec=Encrypt, Ciphertext data if EncDec=Decrypt */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CRYPTO;
+
+typedef struct _HostCmd_TX_RATE_QUERY
+{
+    /** Tx rate */
+    u16 TxRate;
+} __ATTRIB_PACK__ HostCmd_TX_RATE_QUERY;
+
+/** HostCmd_DS_802_11_AUTO_TX */
+typedef struct _HostCmd_DS_802_11_AUTO_TX
+{
+        /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    MrvlIEtypes_AutoTx_t AutoTx;            /**< Auto Tx */
+} __ATTRIB_PACK__ HostCmd_DS_802_11_AUTO_TX;
+
+/** HostCmd_MEM_ACCESS */
+typedef struct _HostCmd_DS_MEM_ACCESS
+{
+        /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    /** Reserved field */
+    u16 Reserved;
+    /** Address */
+    u32 Addr;
+    /** Value */
+    u32 Value;
+} __ATTRIB_PACK__ HostCmd_DS_MEM_ACCESS;
+
+typedef struct
+{
+    /** TSF value structure */
+    u64 TsfValue;
+} __ATTRIB_PACK__ HostCmd_DS_GET_TSF;
+
+typedef struct _HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG
+{
+    /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    /** System clock */
+    u16 SystemClock;
+    /** Supported system clock length */
+    u16 SupportedSysClockLen;
+    /** Supported system clock */
+    u16 SupportedSysClock[16];
+} __ATTRIB_PACK__ HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG;
+
+typedef struct _HostCmd_DS_MODULE_TYPE_CONFIG
+{
+    /** Action */
+    u16 Action;                 /* 0 = ACT_GET; 1 = ACT_SET; */
+    /** Module */
+    u16 Module;
+} __ATTRIB_PACK__ HostCmd_DS_MODULE_TYPE_CONFIG;
+
+typedef struct _HostCmd_DS_VERSION_EXT
+{
+    /** Selected version string */
+    u8 versionStrSel;
+    /** Version string */
+    char versionStr[128];
+} __ATTRIB_PACK__ HostCmd_DS_VERSION_EXT;
+
+/** Define data structure for HostCmd_CMD_802_11D_DOMAIN_INFO */
+typedef struct _HostCmd_DS_802_11D_DOMAIN_INFO
+{
+    /** Action */
+    u16 Action;
+    /** Domain parameter set */
+    MrvlIEtypes_DomainParamSet_t Domain;
+} __ATTRIB_PACK__ HostCmd_DS_802_11D_DOMAIN_INFO;
+
+/** Define data structure for HostCmd_CMD_802_11D_DOMAIN_INFO response */
+typedef struct _HostCmd_DS_802_11D_DOMAIN_INFO_RSP
+{
+    /** Action */
+    u16 Action;
+    /** Domain parameter set */
+    MrvlIEtypes_DomainParamSet_t Domain;
+} __ATTRIB_PACK__ HostCmd_DS_802_11D_DOMAIN_INFO_RSP;
+
+typedef struct _HostCmd_DS_MEF_CFG
+{
+    /** Criteria */
+    u32 Criteria;
+    /** Number of entries */
+    u16 NumEntries;
+} __ATTRIB_PACK__ HostCmd_DS_MEF_CFG;
+
+typedef struct _MEF_CFG_DATA
+{
+    /** Size */
+    u16 size;
+    /** Data */
+    HostCmd_DS_MEF_CFG data;
+} __ATTRIB_PACK__ MEF_CFG_DATA;
+
+typedef struct _HostCmd_DS_DBGS_CFG
+{
+    /** Destination */
+    u8 Destination;
+    /** To air channel */
+    u8 ToAirChan;
+    /** Reserved */
+    u8 reserved;
+    /** Number of entries */
+    u8 En_NumEntries;
+} __ATTRIB_PACK__ HostCmd_DS_DBGS_CFG;
+
+typedef struct _DBGS_ENTRY_DATA
+{
+    /** Mode and mask or ID */
+    u16 ModeAndMaskorID;
+    /** Base or ID */
+    u16 BaseOrID;
+} __ATTRIB_PACK__ DBGS_ENTRY_DATA;
+
+typedef struct _DBGS_CFG_DATA
+{
+    /** Size */
+    u16 size;
+    /** Data */
+    HostCmd_DS_DBGS_CFG data;
+} __ATTRIB_PACK__ DBGS_CFG_DATA;
+
+typedef struct _HostCmd_DS_GET_MEM
+{
+    /** Starting address */
+    u32 StartAddr;
+    /** Length */
+    u16 Len;
+} __ATTRIB_PACK__ HostCmd_DS_GET_MEM;
+
+typedef struct _FW_MEM_DATA
+{
+    /** Size */
+    u16 size;
+    /** Data */
+    HostCmd_DS_GET_MEM data;
+} __ATTRIB_PACK__ FW_MEM_DATA;
+
+typedef struct
+{
+    /** Packet Tx init count */
+    u32 PktInitCnt;
+    /** Packet Tx success count */
+    u32 PktSuccessCnt;
+    /** Packets Tx attempts count */
+    u32 TxAttempts;
+    /** Packet Tx retry failures count */
+    u32 RetryFailure;
+    /** Packet Tx expiry failures count */
+    u32 ExpiryFailure;
+} __ATTRIB_PACK__ HostCmd_DS_TX_PKT_STAT_Entry;
+
+typedef struct
+{
+    /** DS Tx packet statistics */
+    HostCmd_DS_TX_PKT_STAT_Entry StatEntry[HOSTCMD_SUPPORTED_RATES];
+} __ATTRIB_PACK__ HostCmd_DS_TX_PKT_STATS;
+
+/**
+ * @brief 802.11h Local Power Constraint Marvell extended TLV
+ */
+typedef struct
+{
+    MrvlIEtypesHeader_t Header; //!< Marvell TLV header: ID/Len
+    u8 Chan;                    //!< Channel local constraint applies to
+
+    //! Power constraint included in beacons and used by fw to offset 11d info
+    u8 Constraint;
+
+} __ATTRIB_PACK__ MrvlIEtypes_LocalPowerConstraint_t;
+
+/*
+ *
+ * Data structures for driver/firmware command processing
+ *
+ */
+
+//!  TPC Info structure sent in CMD_802_11_TPC_INFO command to firmware
+typedef struct
+{
+    MrvlIEtypes_LocalPowerConstraint_t localConstraint; //!< Local constraint
+    MrvlIEtypes_PowerCapability_t powerCap;     //!< Power Capability
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_TPC_INFO;
+
+//!  TPC Request structure sent in CMD_802_11_TPC_ADAPT_REQ command to firmware
+typedef struct
+{
+    u8 destMac[ETH_ALEN];       //!< Destination STA address 
+    u16 timeout;                //!< Response timeout in ms
+    u8 rateIndex;               //!< IEEE Rate index to send request
+
+} __ATTRIB_PACK__ HostCmd_TpcRequest;
+
+//!  TPC Response structure received from the CMD_802_11_TPC_ADAPT_REQ command
+typedef struct
+{
+    u8 tpcRetCode;              //!< Firmware command result status code
+    s8 txPower;                 //!< Reported TX Power from the TPC Report element
+    s8 linkMargin;              //!< Reported link margin from the TPC Report element
+    s8 rssi;                    //!< RSSI of the received TPC Report frame
+
+} __ATTRIB_PACK__ HostCmd_TpcResponse;
+
+//!  CMD_802_11_TPC_ADAPT_REQ substruct. Union of the TPC request and response
+typedef union
+{
+    HostCmd_TpcRequest req;     //!< Request struct sent to firmware
+    HostCmd_TpcResponse resp;   //!< Response struct received from firmware
+
+} __ATTRIB_PACK__ HostCmd_DS_802_11_TPC_ADAPT_REQ;
+
+//!  CMD_802_11_CHAN_SW_ANN firmware command substructure
+typedef struct
+{
+    u8 switchMode;              //!< Set to 1 for a quiet switch request, no STA tx
+    u8 newChan;                 //!< Requested new channel                       
+    u8 switchCount;             //!< Number of TBTTs until the switch is to occur
+} __ATTRIB_PACK__ HostCmd_DS_802_11_CHAN_SW_ANN;
+
+/**        
+*** @brief Include extra 11h measurement types (not currently supported 
+***                                             in firmware)
+**/
+#define  WLAN_MEAS_EXTRA_11H_TYPES   0
+
+/**        
+*** @brief Include extra 11k measurement types (not currently implemented)
+**/
+#define  WLAN_MEAS_EXTRA_11K_TYPES   0
+
+/**        
+*** @brief Enumeration of measurement types, including max supported 
+***        enum for 11h/11k
+**/
+typedef enum
+{
+    WLAN_MEAS_BASIC = 0,        //!< 11h: Basic
+#if WLAN_MEAS_EXTRA_11H_TYPES
+    /* Not supported in firmware */
+    WLAN_MEAS_CCA = 1,          //!< 11h: CCA
+    WLAN_MEAS_RPI = 2,          //!< 11h: RPI
+#endif
+#if WLAN_MEAS_EXTRA_11K_TYPES
+    /* Future 11k extensions */
+    WLAN_MEAS_CHAN_LOAD = 3,    //!< 11k: Channel Load
+    WLAN_MEAS_NOISE_HIST = 4,   //!< 11k: Noise Histogram 
+    WLAN_MEAS_BEACON = 5,       //!< 11k: Beacon 
+    WLAN_MEAS_FRAME = 6,        //!< 11k: Frame
+    WLAN_MEAS_HIDDEN_NODE = 7,  //!< 11k: Hidden Node
+    WLAN_MEAS_MEDIUM_SENS_HIST = 8,     //!< 11k: Medium Sense Histogram
+    WLAN_MEAS_STA_STATS = 9,    //!< 11k: Station Statistics
+#endif
+
+    WLAN_MEAS_NUM_TYPES,        //!< Number of enumerated measurements
+
+#if WLAN_MEAS_EXTRA_11H_TYPES
+    WLAN_MEAS_11H_MAX_TYPE = WLAN_MEAS_RPI,     //!< Max 11h measurement
+#else
+    WLAN_MEAS_11H_MAX_TYPE = WLAN_MEAS_BASIC,   //!< Max 11h measurement
+#endif
+
+#if WLAN_MEAS_EXTRA_11K_TYPES
+    /* Future 11k extensions */
+    WLAN_MEAS_11K_MAX_TYPE = WLAN_MEAS_STA_STATS,       //!< Max 11k measurement
+#endif
+
+} __ATTRIB_PACK__ MeasType_t;
+
+/**        
+*** @brief Mode octet of the measurement request element (7.3.2.21)
+**/
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    u8 rsvd5_7:3;               //!< Reserved
+    u8 durationMandatory:1;     //!< 11k: duration spec. for meas. is mandatory
+    u8 report:1;                //!< 11h: en/disable report rcpt. of spec. type
+    u8 request:1;               //!< 11h: en/disable requests of specified type
+    u8 enable:1;                //!< 11h: enable report/request bits
+    u8 parallel:1;              //!< 11k: series or parallel with previous meas
+#else
+    u8 parallel:1;              //!< 11k: series or parallel with previous meas
+    u8 enable:1;                //!< 11h: enable report/request bits
+    u8 request:1;               //!< 11h: en/disable requests of specified type
+    u8 report:1;                //!< 11h: en/disable report rcpt. of spec. type
+    u8 durationMandatory:1;     //!< 11k: duration spec. for meas. is mandatory
+    u8 rsvd5_7:3;               //!< Reserved
+#endif
+
+} __ATTRIB_PACK__ MeasReqMode_t;
+
+/**        
+*** @brief Common measurement request structure (7.3.2.21.1 to 7.3.2.21.3)
+**/
+typedef struct
+{
+    u8 channel;                 //!< Channel to measure
+    u64 startTime;              //!< TSF Start time of measurement (0 for immediate)
+    u16 duration;               //!< TU duration of the measurement
+
+} __ATTRIB_PACK__ MeasReqCommonFormat_t;
+
+/**        
+*** @brief Basic measurement request structure (7.3.2.21.1)
+**/
+typedef MeasReqCommonFormat_t MeasReqBasic_t;
+
+/**        
+*** @brief CCA measurement request structure (7.3.2.21.2)
+**/
+typedef MeasReqCommonFormat_t MeasReqCCA_t;
+
+/**        
+*** @brief RPI measurement request structure (7.3.2.21.3)
+**/
+typedef MeasReqCommonFormat_t MeasReqRPI_t;
+
+/**        
+*** @brief Union of the availble measurement request types.  Passed in the 
+***        driver/firmware interface.
+**/
+typedef union
+{
+    MeasReqBasic_t basic;       //!< Basic measurement request
+    MeasReqCCA_t cca;           //!< CCA measurement request
+    MeasReqRPI_t rpi;           //!< RPI measurement request
+
+} MeasRequest_t;
+
+/**        
+*** @brief Mode octet of the measurement report element (7.3.2.22)
+**/
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    u8 rsvd3_7:5;               //!< Reserved
+    u8 refused:1;               //!< Measurement refused
+    u8 incapable:1;             //!< Incapable of performin measurement
+    u8 late:1;                  //!< Start TSF time missed for measurement
+#else
+    u8 late:1;                  //!< Start TSF time missed for measurement
+    u8 incapable:1;             //!< Incapable of performin measurement
+    u8 refused:1;               //!< Measurement refused
+    u8 rsvd3_7:5;               //!< Reserved
+#endif
+
+} __ATTRIB_PACK__ MeasRptMode_t;
+
+/**
+***  @brief Map octet of the basic measurment report (7.3.2.22.1)
+**/
+typedef struct
+{
+#ifdef BIG_ENDIAN
+    u8 rsvd5_7:3;               //!< Reserved
+    u8 unmeasured:1;            //!< Channel is unmeasured
+    u8 radar:1;                 //!< Radar detected on channel
+    u8 unidentifiedSig:1;       //!< Unidentified signal found on channel
+    u8 OFDM_Preamble:1;         //!< OFDM preamble detected on channel
+    u8 BSS:1;                   //!< At least one valid MPDU received on channel
+#else
+    u8 BSS:1;                   //!< At least one valid MPDU received on channel
+    u8 OFDM_Preamble:1;         //!< OFDM preamble detected on channel
+    u8 unidentifiedSig:1;       //!< Unidentified signal found on channel
+    u8 radar:1;                 //!< Radar detected on channel
+    u8 unmeasured:1;            //!< Channel is unmeasured
+    u8 rsvd5_7:3;               //!< Reserved
+#endif
+
+} __ATTRIB_PACK__ MeasRptBasicMap_t;
+
+/**        
+*** @brief Basic measurement report (7.3.2.22.1)
+**/
+typedef struct
+{
+    u8 channel;                 //!< Channel to measured
+    u64 startTime;              //!< Start time (TSF) of measurement
+    u16 duration;               //!< Duration of measurement in TUs
+    MeasRptBasicMap_t map;      //!< Basic measurement report
+
+} __ATTRIB_PACK__ MeasRptBasic_t;
+
+/**        
+*** @brief CCA measurement report (7.3.2.22.2)
+**/
+typedef struct
+{
+    u8 channel;                 //!< Channel to measured            
+    u64 startTime;              //!< Start time (TSF) of measurement
+    u16 duration;               //!< Duration of measurement in TUs 
+    u8 busyFraction;            //!< Fractional duration CCA indicated chan busy
+
+} __ATTRIB_PACK__ MeasRptCCA_t;
+
+/**        
+*** @brief RPI measurement report (7.3.2.22.3)
+**/
+typedef struct
+{
+    u8 channel;                 //!< Channel to measured            
+    u64 startTime;              //!< Start time (TSF) of measurement
+    u16 duration;               //!< Duration of measurement in TUs 
+    u8 density[8];              //!< RPI Density histogram report
+
+} __ATTRIB_PACK__ MeasRptRPI_t;
+
+/**        
+*** @brief Union of the availble measurement report types.  Passed in the 
+***        driver/firmware interface.
+**/
+typedef union
+{
+    MeasRptBasic_t basic;       //!< Basic measurement report
+    MeasRptCCA_t cca;           //!< CCA measurement report
+    MeasRptRPI_t rpi;           //!< RPI measurement report
+
+} MeasReport_t;
+
+/**        
+*** @brief Structure passed to firmware to perform a measurement
+**/
+typedef struct
+{
+    u8 macAddr[ETH_ALEN];       //!< Reporting STA address  
+    u8 dialogToken;             //!< Measurement dialog toke
+    MeasReqMode_t reqMode;      //!< Report mode            
+    MeasType_t measType;        //!< Measurement type       
+    MeasRequest_t req;          //!< Measurement request data
+
+} __ATTRIB_PACK__ HostCmd_DS_MEASUREMENT_REQUEST;
+
+/**        
+*** @brief Structure passed back from firmware with a measurement report,
+***        also can be to send a measurement report to another STA
+**/
+typedef struct
+{
+    u8 macAddr[ETH_ALEN];       //!< Reporting STA address
+    u8 dialogToken;             //!< Measurement dialog token
+    MeasRptMode_t rptMode;      //!< Report mode 
+    MeasType_t measType;        //!< Measurement type
+    MeasReport_t rpt;           //!< Measurement report data
+
+} __ATTRIB_PACK__ HostCmd_DS_MEASUREMENT_REPORT;
+
+/** _HostCmd_DS_COMMAND*/
+struct _HostCmd_DS_COMMAND
+{
+
+    /** Command Header : Command */
+    u16 Command;
+    /** Command Header : Size */
+    u16 Size;
+    /** Command Header : Sequence number */
+    u16 SeqNum;
+    /** Command Header : Result */
+    u16 Result;
+
+    /** Command Body */
+    union
+    {
+        HostCmd_DS_GET_HW_SPEC hwspec;
+        HostCmd_DS_802_11_PS_MODE psmode;
+        HostCmd_DS_802_11_SCAN scan;
+        HostCmd_DS_802_11_SCAN_RSP scanresp;
+        HostCmd_DS_MAC_CONTROL macctrl;
+        HostCmd_DS_802_11_ASSOCIATE associate;
+        HostCmd_DS_802_11_ASSOCIATE_RSP associatersp;
+        HostCmd_DS_802_11_DEAUTHENTICATE deauth;
+        HostCmd_DS_802_11_SET_WEP wep;
+        HostCmd_DS_802_11_AD_HOC_START ads;
+        HostCmd_DS_802_11_AD_HOC_RESULT result;
+        HostCmd_DS_802_11_GET_LOG glog;
+        HostCmd_DS_802_11_SNMP_MIB smib;
+        HostCmd_DS_802_11_RF_TX_POWER txp;
+        HostCmd_DS_802_11_RF_ANTENNA rant;
+        HostCmd_DS_802_11_RATE_ADAPT_RATESET rateset;
+        HostCmd_DS_MAC_MULTICAST_ADR madr;
+        HostCmd_DS_802_11_AD_HOC_JOIN adj;
+        HostCmd_DS_802_11_RADIO_CONTROL radio;
+        HostCmd_DS_802_11_RF_CHANNEL rfchannel;
+        HostCmd_DS_802_11_RSSI rssi;
+        HostCmd_DS_802_11_RSSI_RSP rssirsp;
+        HostCmd_DS_802_11_AD_HOC_STOP adhoc_stop;
+        HostCmd_DS_802_11_MAC_ADDRESS macadd;
+        HostCmd_DS_802_11_KEY_MATERIAL keymaterial;
+        HostCmd_DS_MAC_REG_ACCESS macreg;
+        HostCmd_DS_BBP_REG_ACCESS bbpreg;
+        HostCmd_DS_RF_REG_ACCESS rfreg;
+        HostCmd_DS_802_11_CAL_DATA_EXT caldataext;
+        HostCmd_DS_802_11_HOST_SLEEP_CFG hostsleepcfg;
+        HostCmd_DS_802_11_EEPROM_ACCESS rdeeprom;
+
+        HostCmd_DS_802_11D_DOMAIN_INFO domaininfo;
+        HostCmd_DS_802_11D_DOMAIN_INFO_RSP domaininforesp;
+        HostCmd_DS_802_11_TPC_ADAPT_REQ tpcReq;
+        HostCmd_DS_802_11_TPC_INFO tpcInfo;
+        HostCmd_DS_802_11_CHAN_SW_ANN chan_sw_ann;
+        HostCmd_DS_MEASUREMENT_REQUEST meas_req;
+        HostCmd_DS_MEASUREMENT_REPORT meas_rpt;
+        HostCmd_DS_802_11_BG_SCAN_CONFIG bgscancfg;
+        HostCmd_DS_802_11_BG_SCAN_QUERY bgscanquery;
+        HostCmd_DS_802_11_BG_SCAN_QUERY_RSP bgscanqueryresp;
+        HostCmd_DS_WMM_GET_STATUS getWmmStatus;
+        HostCmd_DS_WMM_ADDTS_REQ addTsReq;
+        HostCmd_DS_WMM_DELTS_REQ delTsReq;
+        HostCmd_DS_WMM_QUEUE_CONFIG queueConfig;
+        HostCmd_DS_WMM_QUEUE_STATS queueStats;
+        HostCmd_DS_WMM_TS_STATUS tsStatus;
+        HostCmd_DS_TX_PKT_STATS txPktStats;
+        HostCmd_DS_802_11_SLEEP_PARAMS sleep_params;
+        HostCmd_DS_802_11_BCA_TIMESHARE bca_timeshare;
+        HostCmd_DS_802_11_INACTIVITY_TIMEOUT inactivity_timeout;
+        HostCmd_DS_802_11_SLEEP_PERIOD ps_sleeppd;
+        HostCmd_DS_802_11_TPC_CFG tpccfg;
+        HostCmd_DS_802_11_LED_CTRL ledgpio;
+        HostCmd_DS_802_11_FW_WAKEUP_METHOD fwwakeupmethod;
+
+        HostCmd_DS_802_11_CRYPTO crypto;
+        HostCmd_TX_RATE_QUERY txrate;
+        HostCmd_DS_GET_TSF gettsf;
+        HostCmd_DS_802_11_IBSS_Status ibssCoalescing;
+        HostCmd_DS_SDIO_PULL_CTRL sdiopullctl;
+        HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG sysclockcfg;
+        HostCmd_DS_MODULE_TYPE_CONFIG moduletypecfg;
+        HostCmd_DS_VERSION_EXT verext;
+        HostCmd_DS_MEF_CFG mefcfg;
+        HostCmd_DS_DBGS_CFG dbgcfg;
+        HostCmd_DS_GET_MEM getmem;
+    } params;
+} __ATTRIB_PACK__;
+
+/** Find minimum */
+#ifndef MIN
+#define MIN(a,b)		((a) < (b) ? (a) : (b))
+#endif
+
+/** Find maximum */
+#ifndef MAX
+#define MAX(a,b)		((a) > (b) ? (a) : (b))
+#endif
+
+/** Find number of elements */
+#ifndef NELEMENTS
+#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+/** Buffer Constants */
+
+/*	The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+*	addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+*	driver has more local TxPDs. Each TxPD on the host memory is associated 
+*	with a Tx control node. The driver maintains 8 RxPD descriptors for 
+*	station firmware to store Rx packet information.
+*
+*	Current version of MAC has a 32x6 multicast address buffer.
+*
+*	802.11b can have up to  14 channels, the driver keeps the
+*	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+/** Size of SQ memory PPA */
+#define MRVDRV_SIZE_OF_PPA		0x00000008
+/** Size of SQ memory DPA */
+#define MRVDRV_SIZE_OF_DPA		0x00000008
+/** Number of TxPD in station */
+#define MRVDRV_NUM_OF_TxPD		0x00000020
+/** Numner of command buffers */
+#define MRVDRV_NUM_OF_CMD_BUFFER        10
+/** Size of command buffer */
+#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
+/** Maximum number of BSSIDs */
+#define MRVDRV_MAX_BSSID_LIST		64
+/** 10 seconds */
+#define MRVDRV_TIMER_10S		10000
+/** 5 seconds */
+#define MRVDRV_TIMER_5S			5000
+/** 1 second */
+#define MRVDRV_TIMER_1S			1000
+/** Size of ethernet header */
+#define MRVDRV_ETH_HEADER_SIZE          14
+
+/** Maximum buffer size for ARP filter */
+#define ARP_FILTER_MAX_BUF_SIZE		20
+
+/** WLAN upload size */
+#define	WLAN_UPLD_SIZE			2312
+/** Length of device length */
+#define DEV_NAME_LEN			32
+
+/** Length of ethernet address */
+#ifndef	ETH_ALEN
+#define ETH_ALEN			6
+#endif
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+#define SDIO_HEADER_LEN		4
+
+/** Maximum number of region codes */
+#define MRVDRV_MAX_REGION_CODE			7
+
+/** Maximum length of SSID list */
+#define MRVDRV_MAX_SSID_LIST_LENGTH     10
+
+/** Ignore multiple DTIM */
+#define MRVDRV_IGNORE_MULTIPLE_DTIM		0xfffe
+/** Minimum multiple DTIM */
+#define MRVDRV_MIN_MULTIPLE_DTIM		1
+/** Maximum multiple DTIM */
+#define MRVDRV_MAX_MULTIPLE_DTIM		5
+/** Default multiple DTIM */
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM		1
+
+/** Default listen interval */
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL		10
+/** Default local listen interval */
+#define MRVDRV_DEFAULT_LOCAL_LISTEN_INTERVAL		0
+
+/** Number of channels per active scan */
+#define	MRVDRV_CHANNELS_PER_ACTIVE_SCAN		14
+/** Minimum beacon interval */
+#define MRVDRV_MIN_BEACON_INTERVAL		20
+/** Maximum beacon interval */
+#define MRVDRV_MAX_BEACON_INTERVAL		1000
+/** Default beacon interval */
+#define MRVDRV_BEACON_INTERVAL			100
+
+/** Default watchdog timeout */
+#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (2 * HZ)
+/** Watchdog timeout for scan */
+#define MRVDRV_SCAN_WATCHDOG_TIMEOUT    (10 * HZ)
+/** Tiemout value for exiting sleep mode */
+#define MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT  (10 * HZ)
+
+/** TxPD Status */
+
+/*	Station firmware use TxPD status field to report final Tx transmit
+*	result, Bit masks are used to present combined situations.
+*/
+
+/** Bit mask for TxPD status field for null packet */
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+/** Bit mask for TxPD status field for last packet */
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Tx control node status */
+
+#define MRVDRV_TX_CTRL_NODE_STATUS_IDLE      0x0000
+
+/* Link spped */
+/** Link speed : 1 Mbps */
+#define MRVDRV_LINK_SPEED_1mbps          10000  /* in unit of 100bps */
+/** Link speed : 11 Mbps */
+#define MRVDRV_LINK_SPEED_11mbps         110000
+
+/** RSSI-related defines */
+/*	RSSI constants are used to implement 802.11 RSSI threshold 
+*	indication. if the Rx packet signal got too weak for 5 consecutive
+*	times, miniport driver (driver) will report this event to wrapper
+*/
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE		(-96)
+
+/** RTS/FRAG related defines */
+/** Minimum RTS value */
+#define MRVDRV_RTS_MIN_VALUE		0
+/** Maximum RTS value */
+#define MRVDRV_RTS_MAX_VALUE		2347
+/** Minimum FRAG value */
+#define MRVDRV_FRAG_MIN_VALUE		256
+/** Maximum FRAG value */
+#define MRVDRV_FRAG_MAX_VALUE		2346
+
+/** Fixed IE size is 8 bytes time stamp + 2 bytes beacon interval +
+ * 2 bytes cap */
+#define MRVL_FIXED_IE_SIZE      12
+
+/** Host comamnd flag in command */
+#define	CMD_F_HOSTCMD		(1 << 0)
+
+/* to resolve CISCO AP extension */
+/** Space for Variable IE in scan list */
+#define MRVDRV_SCAN_LIST_VAR_IE_SPACE  	256
+/** Checks whether WPA enabled in firmware */
+#define FW_IS_WPA_ENABLED(_adapter) \
+		(_adapter->fwCapInfo & FW_CAPINFO_WPA)
+
+/** WPA capability bit in firmware capability */
+#define FW_CAPINFO_WPA  	(1 << 0)
+/** REQFI capabilities */
+#define WLAN_802_11_AI_REQFI_CAPABILITIES 	1
+/** REQFI listen interval */
+#define WLAN_802_11_AI_REQFI_LISTENINTERVAL 	2
+/** REQFI current AP address */
+#define WLAN_802_11_AI_REQFI_CURRENTAPADDRESS 	4
+
+/** RESFI capabilities */
+#define WLAN_802_11_AI_RESFI_CAPABILITIES 	1
+/** RESFI status code */
+#define WLAN_802_11_AI_RESFI_STATUSCODE 	2
+/** RESFI association ID */
+#define WLAN_802_11_AI_RESFI_ASSOCIATIONID 	4
+
+/** Number of WEP keys */
+#define MRVL_NUM_WEP_KEY		4
+
+/** Support 4 keys per key set */
+#define MRVL_NUM_WPA_KEY_PER_SET        4
+/** WPA Key LENGTH*/
+#define MRVL_MAX_WPA_KEY_LENGTH 	32
+
+/** WPA AES key length */
+#define WPA_AES_KEY_LEN 		16
+/** WPA TKIP key length */
+#define WPA_TKIP_KEY_LEN 		32
+
+/* A few details needed for WEP (Wireless Equivalent Privacy) */
+/** 104 bits */
+#define MAX_WEP_KEY_SIZE	13
+/** 40 bits RC4 - WEP */
+#define MIN_WEP_KEY_SIZE	5
+
+/** RF antenna select 1 */
+#define RF_ANTENNA_1		0x1
+/** RF antenna select 2 */
+#define RF_ANTENNA_2		0x2
+/** RF antenna auto select */
+#define RF_ANTENNA_AUTO		0xFFFF
+
+/** Key information enabled */
+#define KEY_INFO_ENABLED	0x01
+
+/** Beacon Signal to Noise Ratio */
+#define SNR_BEACON		0
+/** RXPD Signal to Noise Ratio */
+#define SNR_RXPD		1
+/** Beacon Noise Floor */
+#define NF_BEACON		2
+/** RXPD Noise Floor */
+#define NF_RXPD			3
+
+/** MACRO DEFINITIONS */
+/** NF calculation */
+#define CAL_NF(NF)			((s32)(-(s32)(NF)))
+/** RSSI calculation */
+#define CAL_RSSI(SNR, NF) 		((s32)((s32)(SNR) + CAL_NF(NF)))
+/** RSSI scan */
+#define SCAN_RSSI(RSSI)			(0x100 - ((u8)(RSSI)))
+
+/** Default factor for calculating beacon average */
+#define DEFAULT_BCN_AVG_FACTOR		8
+/** Default factor for calculating data average */
+#define DEFAULT_DATA_AVG_FACTOR		8
+/** Minimum factor for calculating beacon average */
+#define MIN_BCN_AVG_FACTOR		1
+/** Maximum factor for calculating beacon average */
+#define MAX_BCN_AVG_FACTOR		8
+/** Minimum factor for calculating data average */
+#define MIN_DATA_AVG_FACTOR		1
+/** Maximum factor for calculating data average */
+#define MAX_DATA_AVG_FACTOR		8
+/** Scale used to measure average */
+#define AVG_SCALE			100
+/** Average SNR NF calculations */
+#define CAL_AVG_SNR_NF(AVG, SNRNF, N)         \
+                        (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
+                        ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+                        AVG_SCALE))  / N))
+
+/** Success */
+#define WLAN_STATUS_SUCCESS			(0)
+/** Failure */
+#define WLAN_STATUS_FAILURE			(-1)
+/** Not accepted */
+#define WLAN_STATUS_NOT_ACCEPTED                (-2)
+
+/** Maximum number of LEDs */
+#define	MAX_LEDS			3
+/** LED disabled */
+#define	LED_DISABLED			16
+/** LED blinking */
+#define	LED_BLINKING			2
+
+/** Max loop count (* 100ms) for waiting device ready at init time */
+#define MAX_WAIT_DEVICE_READY_COUNT	50
+
+/** S_SWAP : To swap 2 u8 */
+#define S_SWAP(a,b) 	do { \
+				u8  t = SArr[a]; \
+				SArr[a] = SArr[b]; SArr[b] = t; \
+			} while(0)
+
+/** SWAP: swap u8 */
+#define SWAP_U8(a,b)	{u8 t; t=a; a=b; b=t;}
+
+/** SWAP: swap u8 */
+#define SWAP_U16(a,b)	{u16 t; t=a; a=b; b=t;}
+
+#ifdef BIG_ENDIAN
+/** Convert from 16 bit little endian format to CPU format */
+#define wlan_le16_to_cpu(x) le16_to_cpu(x)
+/** Convert from 32 bit little endian format to CPU format */
+#define wlan_le32_to_cpu(x) le32_to_cpu(x)
+/** Convert from 64 bit little endian format to CPU format */
+#define wlan_le64_to_cpu(x) le64_to_cpu(x)
+/** Convert to 16 bit little endian format from CPU format */
+#define wlan_cpu_to_le16(x) cpu_to_le16(x)
+/** Convert to 32 bit little endian format from CPU format */
+#define wlan_cpu_to_le32(x) cpu_to_le32(x)
+/** Convert to 64 bit little endian format from CPU format */
+#define wlan_cpu_to_le64(x) cpu_to_le64(x)
+
+/** Convert TxPD to little endian format from CPU format */
+#define endian_convert_TxPD(x);                                         \
+    {                                                                   \
+        (x)->TxStatus = wlan_cpu_to_le32((x)->TxStatus);                \
+        (x)->TxPacketLength = wlan_cpu_to_le16((x)->TxPacketLength);    \
+        (x)->TxPacketLocation = wlan_cpu_to_le32((x)->TxPacketLocation);\
+        (x)->TxControl = wlan_cpu_to_le32((x)->TxControl);              \
+    }
+
+/** Convert RxPD from little endian format to CPU format */
+#define endian_convert_RxPD(x);                             \
+    {                                                       \
+        (x)->RxStatus = wlan_le16_to_cpu((x)->RxStatus);    \
+        (x)->PktLen = wlan_le16_to_cpu((x)->PktLen);        \
+        (x)->PktOffset = wlan_le32_to_cpu((x)->PktOffset);  \
+    }
+
+/** Convert log from little endian format to CPU format */
+#define endian_convert_GET_LOG(x); { \
+		Adapter->LogMsg.mcastrxframe = wlan_le32_to_cpu(Adapter->LogMsg.mcastrxframe); \
+		Adapter->LogMsg.failed = wlan_le32_to_cpu(Adapter->LogMsg.failed); \
+		Adapter->LogMsg.retry = wlan_le32_to_cpu(Adapter->LogMsg.retry); \
+		Adapter->LogMsg.multiretry = wlan_le32_to_cpu(Adapter->LogMsg.multiretry); \
+		Adapter->LogMsg.framedup = wlan_le32_to_cpu(Adapter->LogMsg.framedup); \
+		Adapter->LogMsg.rtssuccess = wlan_le32_to_cpu(Adapter->LogMsg.rtssuccess); \
+		Adapter->LogMsg.rtsfailure = wlan_le32_to_cpu(Adapter->LogMsg.rtsfailure); \
+		Adapter->LogMsg.ackfailure = wlan_le32_to_cpu(Adapter->LogMsg.ackfailure); \
+		Adapter->LogMsg.rxfrag = wlan_le32_to_cpu(Adapter->LogMsg.rxfrag); \
+		Adapter->LogMsg.mcastrxframe = wlan_le32_to_cpu(Adapter->LogMsg.mcastrxframe); \
+		Adapter->LogMsg.fcserror = wlan_le32_to_cpu(Adapter->LogMsg.fcserror); \
+		Adapter->LogMsg.txframe = wlan_le32_to_cpu(Adapter->LogMsg.txframe); \
+}
+
+#else /* BIG_ENDIAN */
+/** Do nothing */
+#define wlan_le16_to_cpu(x) x
+/** Do nothing */
+#define wlan_le32_to_cpu(x) x
+/** Do nothing */
+#define wlan_le64_to_cpu(x) x
+/** Do nothing */
+#define wlan_cpu_to_le16(x) x
+/** Do nothing */
+#define wlan_cpu_to_le32(x) x
+/** Do nothing */
+#define wlan_cpu_to_le64(x) x
+
+/** Do nothing */
+#define endian_convert_TxPD(x)
+/** Do nothing */
+#define endian_convert_RxPD(x)
+/** Do nothing */
+#define endian_convert_GET_LOG(x)
+#endif /* BIG_ENDIAN */
+
+/** Global Varibale Declaration */
+/** Private data structure of the device */
+typedef struct _wlan_private wlan_private;
+/** Adapter data structure of the device */
+typedef struct _wlan_adapter wlan_adapter;
+/** Host command data structure */
+typedef struct _HostCmd_DS_COMMAND HostCmd_DS_COMMAND;
+
+/** DS frequency list */
+extern u32 DSFreqList[15];
+/** Driver version */
+extern const char driver_version[];
+extern u32 DSFreqList[];
+extern u16 RegionCodeToIndex[MRVDRV_MAX_REGION_CODE];
+
+extern u8 WlanDataRates[WLAN_SUPPORTED_RATES];
+
+extern u8 SupportedRates_B[B_SUPPORTED_RATES];
+extern u8 SupportedRates_G[G_SUPPORTED_RATES];
+extern u8 SupportedRates_A[A_SUPPORTED_RATES];
+extern u8 AdhocRates_A[A_SUPPORTED_RATES];
+
+extern u8 AdhocRates_G[G_SUPPORTED_RATES];
+
+extern u8 AdhocRates_B[4];
+extern wlan_private *wlanpriv;
+
+#ifdef MFG_CMD_SUPPORT
+#define SIOCCFMFG SIOCDEVPRIVATE
+#endif /* MFG_CMD_SUPPORT */
+
+/** ENUM definition*/
+/** SNRNF_TYPE */
+typedef enum _SNRNF_TYPE
+{
+    TYPE_BEACON = 0,
+    TYPE_RXPD,
+    MAX_TYPE_B
+} SNRNF_TYPE;
+
+/** SNRNF_DATA*/
+typedef enum _SNRNF_DATA
+{
+    TYPE_NOAVG = 0,
+    TYPE_AVG,
+    MAX_TYPE_AVG
+} SNRNF_DATA;
+
+/** WLAN_802_11_AUTH_ALG*/
+typedef enum _WLAN_802_11_AUTH_ALG
+{
+    AUTH_ALG_OPEN_SYSTEM = 1,
+    AUTH_ALG_SHARED_KEY = 2,
+    AUTH_ALG_NETWORK_EAP = 8,
+} WLAN_802_11_AUTH_ALG;
+
+/** WLAN_802_11_ENCRYPTION_MODE */
+typedef enum _WLAN_802_11_ENCRYPTION_MODE
+{
+    CIPHER_NONE,
+    CIPHER_WEP40,
+    CIPHER_TKIP,
+    CIPHER_CCMP,
+    CIPHER_WEP104,
+} WLAN_802_11_ENCRYPTION_MODE;
+
+/** WLAN_802_11_POWER_MODE */
+typedef enum _WLAN_802_11_POWER_MODE
+{
+    Wlan802_11PowerModeCAM,
+    Wlan802_11PowerModeMAX_PSP,
+    Wlan802_11PowerModeFast_PSP,
+
+    /*not a real mode, defined as an upper bound */
+    Wlan802_11PowerModeMax
+} WLAN_802_11_POWER_MODE;
+
+/** PS_STATE */
+typedef enum _PS_STATE
+{
+    PS_STATE_FULL_POWER,
+    PS_STATE_AWAKE,
+    PS_STATE_PRE_SLEEP,
+    PS_STATE_SLEEP
+} PS_STATE;
+
+/** DNLD_STATE */
+typedef enum _DNLD_STATE
+{
+    DNLD_RES_RECEIVED,
+    DNLD_DATA_SENT,
+    DNLD_CMD_SENT
+} DNLD_STATE;
+
+/** WLAN_MEDIA_STATE */
+typedef enum _WLAN_MEDIA_STATE
+{
+    WlanMediaStateDisconnected,
+    WlanMediaStateConnected
+} WLAN_MEDIA_STATE;
+
+/** WLAN_802_11_PRIVACY_FILTER */
+typedef enum _WLAN_802_11_PRIVACY_FILTER
+{
+    Wlan802_11PrivFilterAcceptAll,
+    Wlan802_11PrivFilter8021xWEP
+} WLAN_802_11_PRIVACY_FILTER;
+
+/** Hardware status codes */
+typedef enum _WLAN_HARDWARE_STATUS
+{
+    WlanHardwareStatusReady,
+    WlanHardwareStatusInitializing,
+    WlanHardwareStatusReset,
+    WlanHardwareStatusClosing,
+    WlanHardwareStatusNotReady
+} WLAN_HARDWARE_STATUS;
+
+/** WLAN_802_11_AUTHENTICATION_MODE */
+typedef enum _WLAN_802_11_AUTHENTICATION_MODE
+{
+    Wlan802_11AuthModeOpen = 0x00,
+    Wlan802_11AuthModeShared = 0x01,
+    Wlan802_11AuthModeNetworkEAP = 0x80,
+} WLAN_802_11_AUTHENTICATION_MODE;
+
+/** WLAN_802_11_WEP_STATUS */
+typedef enum _WLAN_802_11_WEP_STATUS
+{
+    Wlan802_11WEPEnabled,
+    Wlan802_11WEPDisabled,
+    Wlan802_11WEPKeyAbsent,
+    Wlan802_11WEPNotSupported
+} WLAN_802_11_WEP_STATUS;
+
+/** SNMP_MIB_INDEX_e */
+typedef enum _SNMP_MIB_INDEX_e
+{
+    DesiredBssType_i = 0,
+    OpRateSet_i,
+    BcnPeriod_i,
+    DtimPeriod_i,
+    AssocRspTimeOut_i,
+    RtsThresh_i,
+    ShortRetryLim_i,
+    LongRetryLim_i,
+    FragThresh_i,
+    Dot11D_i,
+    Dot11H_i,
+    ManufId_i,
+    ProdId_i,
+    ManufOui_i,
+    ManufName_i,
+    ManufProdName_i,
+    ManufProdVer_i
+} SNMP_MIB_INDEX_e;
+
+/** KEY_TYPE_ID */
+typedef enum _KEY_TYPE_ID
+{
+    KEY_TYPE_ID_WEP = 0,
+    KEY_TYPE_ID_TKIP,
+    KEY_TYPE_ID_AES
+} KEY_TYPE_ID;
+
+/** KEY_INFO_WEP*/
+typedef enum _KEY_INFO_WEP
+{
+    KEY_INFO_WEP_DEFAULT_KEY = 0x01
+} KEY_INFO_WEP;
+
+/** KEY_INFO_TKIP */
+typedef enum _KEY_INFO_TKIP
+{
+    KEY_INFO_TKIP_MCAST = 0x01,
+    KEY_INFO_TKIP_UNICAST = 0x02,
+    KEY_INFO_TKIP_ENABLED = 0x04
+} KEY_INFO_TKIP;
+
+/** KEY_INFO_AES*/
+typedef enum _KEY_INFO_AES
+{
+    KEY_INFO_AES_MCAST = 0x01,
+    KEY_INFO_AES_UNICAST = 0x02,
+    KEY_INFO_AES_ENABLED = 0x04
+} KEY_INFO_AES;
+
+/** SNMP_MIB_VALUE_e */
+typedef enum _SNMP_MIB_VALUE_e
+{
+    SNMP_MIB_VALUE_INFRA = 1,
+    SNMP_MIB_VALUE_ADHOC
+} SNMP_MIB_VALUE_e;
+
+/** HWRateDropMode */
+typedef enum _HWRateDropMode
+{
+    NO_HW_RATE_DROP,
+    HW_TABLE_RATE_DROP,
+    HW_SINGLE_RATE_DROP
+} HWRateDropMode;
+
+#ifdef __KERNEL__
+extern struct iw_handler_def wlan_handler_def;
+struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev);
+int wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+#endif
+
+#endif /* _WLAN_FW_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_headers.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_headers.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_headers.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_headers.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,102 @@
+/** @file wlan_headers.h
+ * 
+ * @brief This file contains all the necessary include file.
+ *
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	05/30/07: Initial creation
+********************************************************/
+
+#ifndef _WLAN_HEADERS_H
+#define _WLAN_HEADERS_H
+
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+
+/* Linux header files */
+#include        <linux/kernel.h>
+#include        <linux/module.h>
+#include        <linux/init.h>
+#include        <linux/version.h>
+#include        <linux/param.h>
+#include        <linux/delay.h>
+#include        <linux/slab.h>
+#include        <linux/mm.h>
+#include        <linux/types.h>
+#include        <linux/sched.h>
+#include        <linux/timer.h>
+#include        <linux/types.h>
+#include        <linux/ioport.h>
+#include        <linux/pci.h>
+#include        <linux/ctype.h>
+#include        <linux/proc_fs.h>
+#include	<linux/ptrace.h>
+#include	<linux/string.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include	<linux/config.h>
+#endif
+
+#include	<linux/ioport.h>
+
+/* ASM files */
+#include        <asm/semaphore.h>
+#include        <asm/byteorder.h>
+#include        <asm/irq.h>
+#include        <asm/uaccess.h>
+#include        <asm/io.h>
+#include	<asm/system.h>
+
+/* Net header files */
+#include        <linux/wireless.h>
+#include        <linux/netdevice.h>
+#include        <linux/net.h>
+#include        <linux/ip.h>
+#include        <linux/skbuff.h>
+#include        <linux/if_arp.h>
+#include        <linux/if_ether.h>
+#include        <linux/etherdevice.h>
+#include        <net/arp.h>
+#include        <linux/rtnetlink.h>
+
+/* Wireless header */
+#include        <net/iw_handler.h>
+
+#include    "wlan_linux.h"
+#include    "wlan_fw.h"
+
+#include    "wlan_wmm.h"
+#include    "wlan_11d.h"
+#include    "wlan_meas.h"
+#include    "wlan_11h.h"
+
+#include    "wlan_scan.h"
+#include    "wlan_join.h"
+
+#include    "wlan_drv.h"
+
+#include    "wlan_wext.h"
+#include    "wlan_decl.h"
+#include    "wlan_sdio.h"
+#endif /* _WLAN_HEADERS_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_init.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_init.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_init.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_init.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,511 @@
+/** @file wlan_init.c
+  * @brief This file contains the initialization for FW
+  * and HW
+  *
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  * 
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	09/28/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join functions.
+	          Cleanup association response handler initialization.
+	01/06/05: Add FW file read
+	05/08/06: Remove the 2nd GET_HW_SPEC command and TempAddr/PermanentAddr
+	06/30/06: replaced MODULE_PARM(name, type) with module_param(name, type, perm)
+
+********************************************************/
+
+#include	"wlan_headers.h"
+
+#include	<linux/firmware.h>
+
+/* add by feng */
+#include	<linux/mmc/core.h>
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/** Helper name */
+char *helper_name = NULL;
+/** Firmware name */
+char *fw_name = NULL;
+
+module_param(helper_name, charp, 0);
+module_param(fw_name, charp, 0);
+
+#ifdef MFG_CMD_SUPPORT
+int mfgmode = 0;
+module_param(mfgmode, int, 0);
+#endif
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function allocates buffer for the member of adapter
+ *  structure like command buffer and BSSID list.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_allocate_adapter(wlan_private * priv)
+{
+    u32 ulBufSize;
+    wlan_adapter *Adapter = priv->adapter;
+
+    BSSDescriptor_t *pTempScanTable;
+
+    /* Allocate buffer to store the BSSID list */
+    ulBufSize = sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST;
+    if (!(pTempScanTable = kmalloc(ulBufSize, GFP_KERNEL))) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    Adapter->ScanTable = pTempScanTable;
+    memset(Adapter->ScanTable, 0, ulBufSize);
+
+    if (!(Adapter->bgScanConfig =
+          kmalloc(sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG), GFP_KERNEL))) {
+        return WLAN_STATUS_FAILURE;
+    }
+    Adapter->bgScanConfigSize = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
+    memset(Adapter->bgScanConfig, 0, Adapter->bgScanConfigSize);
+
+    spin_lock_init(&Adapter->QueueSpinLock);
+    INIT_LIST_HEAD(&Adapter->CmdFreeQ);
+    INIT_LIST_HEAD(&Adapter->CmdPendingQ);
+
+    /* Allocate the command buffers */
+    if (wlan_alloc_cmd_buffer(priv) != WLAN_STATUS_SUCCESS) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memset(&Adapter->PSConfirmSleep, 0, sizeof(PS_CMD_ConfirmSleep));
+    Adapter->PSConfirmSleep.SeqNum = wlan_cpu_to_le16(++Adapter->SeqNum);
+    Adapter->PSConfirmSleep.Command =
+        wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE);
+    Adapter->PSConfirmSleep.Size =
+        wlan_cpu_to_le16(sizeof(PS_CMD_ConfirmSleep));
+    Adapter->PSConfirmSleep.Result = 0;
+    Adapter->PSConfirmSleep.Action =
+        wlan_cpu_to_le16(HostCmd_SubCmd_Sleep_Confirmed);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function initializes the adapter structure
+ *  and set default value to the member of adapter.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+static void
+wlan_init_adapter(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+
+    Adapter->ScanProbes = 0;
+
+    Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+    Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+    /* ATIM params */
+    Adapter->AtimWindow = 0;
+    Adapter->ATIMEnabled = FALSE;
+
+    Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
+    memset(Adapter->CurrentAddr, 0xff, ETH_ALEN);
+
+    /* Status variables */
+    Adapter->HardwareStatus = WlanHardwareStatusInitializing;
+
+    /* scan type */
+    Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE;
+
+    /* scan mode */
+    Adapter->ScanMode = HostCmd_BSS_TYPE_ANY;
+
+    /* scan time */
+    Adapter->SpecificScanTime = MRVDRV_SPECIFIC_SCAN_CHAN_TIME;
+    Adapter->ActiveScanTime = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+    Adapter->PassiveScanTime = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+
+    /* 802.11 specific */
+    Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled;
+    for (i = 0; i < sizeof(Adapter->WepKey) / sizeof(Adapter->WepKey[0]); i++)
+        memset(&Adapter->WepKey[i], 0, sizeof(MRVL_WEP_KEY));
+    Adapter->CurrentWepKeyIndex = 0;
+    Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+    Adapter->SecInfo.EncryptionMode = CIPHER_NONE;
+    Adapter->AdhocAESEnabled = FALSE;
+    Adapter->AdhocState = ADHOC_IDLE;
+    Adapter->InfrastructureMode = Wlan802_11Infrastructure;
+
+    Adapter->NumInScanTable = 0;
+    Adapter->pAttemptedBSSDesc = NULL;
+#ifdef REASSOCIATION
+    OS_INIT_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+    Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
+
+    Adapter->HisRegCpy |= HIS_TxDnLdRdy;
+
+    memset(&Adapter->CurBssParams, 0, sizeof(Adapter->CurBssParams));
+
+    /* PnP and power profile */
+    Adapter->SurpriseRemoved = FALSE;
+
+    Adapter->CurrentPacketFilter =
+        HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON;
+
+    Adapter->RadioOn = RADIO_ON;
+#ifdef REASSOCIATION
+#if (WIRELESS_EXT >= 18)
+    Adapter->Reassoc_on = FALSE;
+#else
+    Adapter->Reassoc_on = TRUE;
+#endif
+#endif /* REASSOCIATION */
+    Adapter->TxAntenna = RF_ANTENNA_2;
+    Adapter->RxAntenna = RF_ANTENNA_AUTO;
+
+    Adapter->HWRateDropMode = HW_TABLE_RATE_DROP;
+    Adapter->Is_DataRate_Auto = TRUE;
+    Adapter->BeaconPeriod = MRVDRV_BEACON_INTERVAL;
+
+    Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+    Adapter->AdhocAutoSel = TRUE;
+
+    Adapter->PSMode = Wlan802_11PowerModeCAM;
+    Adapter->MultipleDtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+    Adapter->ListenInterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+    Adapter->PSState = PS_STATE_FULL_POWER;
+    Adapter->NeedToWakeup = FALSE;
+    Adapter->LocalListenInterval = 0;   /* default value in firmware will be used */
+    Adapter->fwWakeupMethod = WAKEUP_FW_UNCHANGED;
+
+    Adapter->IsDeepSleep = FALSE;
+    Adapter->IsAutoDeepSleepEnabled = FALSE;
+
+    Adapter->IsEnhancedPSEnabled = FALSE;
+
+    Adapter->bWakeupDevRequired = FALSE;
+    Adapter->WakeupTries = 0;
+    Adapter->bHostSleepConfigured = FALSE;
+    Adapter->HSCfg.conditions = HOST_SLEEP_CFG_CANCEL;
+    Adapter->HSCfg.gpio = 0;
+    Adapter->HSCfg.gap = 0;
+
+    Adapter->DataRate = 0;      // Initially indicate the rate as auto 
+
+    Adapter->adhoc_grate_enabled = FALSE;
+
+    Adapter->IntCounter = Adapter->IntCounterSaved = 0;
+
+    Adapter->gen_null_pkg = TRUE;       /*Enable NULL Pkg generation */
+
+    init_waitqueue_head(&Adapter->cmd_EncKey);
+    init_waitqueue_head(&Adapter->ds_awake_q);
+
+    spin_lock_init(&Adapter->CurrentTxLock);
+    spin_lock_init(&Adapter->driver_lock);
+
+    Adapter->CurrentTxSkb = NULL;
+    Adapter->PktTxCtrl = 0;
+
+    return;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function initializes software
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_init_sw(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /* Allocate adapter structure */
+    if ((ret = wlan_allocate_adapter(priv)) != WLAN_STATUS_SUCCESS) {
+        goto done;
+    }
+
+    /* Initialize adapter structure */
+    wlan_init_adapter(priv);
+
+    /* Initialize the timer for command handling */
+    wlan_initialize_timer(&Adapter->MrvDrvCommandTimer,
+                          wlan_cmd_timeout_func, priv);
+    Adapter->CommandTimerIsSet = FALSE;
+
+#ifdef REASSOCIATION
+    /* Initialize the timer for the reassociation */
+    wlan_initialize_timer(&Adapter->MrvDrvTimer,
+                          wlan_reassoc_timer_func, priv);
+    Adapter->ReassocTimerIsSet = FALSE;
+#endif /* REASSOCIATION */
+
+    /* Initialize 802.11d */
+    wlan_init_11d(priv);
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function initializes firmware
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_init_fw(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* download firmware etc. */
+
+    ENTER();
+
+    sbi_disable_host_int(priv);
+
+    umd_dbg("helper_name: %s, fw_name: %s", helper_name, fw_name);
+
+    /* Check if firmware is already running */
+    if (sbi_check_fw_status(priv, 1) == WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "FW already running! Skipping firmware download\n");
+    } else {
+        if ((ret =
+             request_firmware(&priv->fw_helper, helper_name,
+                              priv->hotplug_device)) < 0) {
+            PRINTM(FATAL,
+                   "request_firmware() failed (helper), error code = %#x\n",
+                   ret);
+            goto done;
+        }
+
+	umd_dbg("start downloading helper");
+        /* Download the helper */
+        ret = sbi_prog_helper(priv);
+
+        if (ret) {
+            PRINTM(INFO,
+                   "Bootloader in invalid state! Helper download failed!\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        if ((ret =
+             request_firmware(&priv->firmware, fw_name,
+                              priv->hotplug_device)) < 0) {
+            PRINTM(FATAL, "request_firmware() failed, error code = %#x\n",
+                   ret);
+            goto done;
+        }
+
+	umd_dbg("start downloading fw");
+        /* Download the main firmware via the helper firmware */
+        if (sbi_prog_fw_w_helper(priv)) {
+            PRINTM(INFO, "Wlan FW download failed!\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        /* Check if the firmware is downloaded successfully or not */
+        if (sbi_check_fw_status(priv, MAX_FIRMWARE_POLL_TRIES) ==
+            WLAN_STATUS_FAILURE) {
+            PRINTM(FATAL, "FW failed to be active in time!\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    }
+
+#define RF_REG_OFFSET 0x07
+#define RF_REG_VALUE  0xc8
+
+    sbi_enable_host_int(priv);
+
+#ifdef MFG_CMD_SUPPORT
+    if (mfgmode == 0) {
+#endif
+
+        /*
+         * Read MAC address from HW
+         */
+        memset(Adapter->CurrentAddr, 0xff, ETH_ALEN);
+
+        ret = wlan_prepare_cmd(priv, HostCmd_CMD_GET_HW_SPEC,
+                               0,
+                               HostCmd_OPTION_WAITFORRSP |
+                               HostCmd_OPTION_TIMEOUT, 0, NULL);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_MAC_CONTROL,
+                               0,
+                               HostCmd_OPTION_WAITFORRSP |
+                               HostCmd_OPTION_TIMEOUT, 0,
+                               &Adapter->CurrentPacketFilter);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_FW_WAKE_METHOD,
+                               HostCmd_ACT_GEN_GET,
+                               HostCmd_OPTION_WAITFORRSP |
+                               HostCmd_OPTION_TIMEOUT, 0,
+                               &priv->adapter->fwWakeupMethod);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+#ifdef MFG_CMD_SUPPORT
+    }
+#endif
+
+#ifdef MFG_CMD_SUPPORT
+    if (mfgmode == 0) {
+#endif
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                               HostCmd_ACT_GEN_GET,
+                               HostCmd_OPTION_WAITFORRSP |
+                               HostCmd_OPTION_TIMEOUT, 0, NULL);
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        priv->adapter->DataRate = 0;
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RF_TX_POWER,
+                               HostCmd_ACT_GEN_GET,
+                               HostCmd_OPTION_WAITFORRSP |
+                               HostCmd_OPTION_TIMEOUT, 0, NULL);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+#ifdef MFG_CMD_SUPPORT
+    }
+#endif
+
+    Adapter->HardwareStatus = WlanHardwareStatusReady;
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    if (priv->fw_helper) {
+        release_firmware(priv->fw_helper);
+    }
+    if (priv->firmware) {
+        release_firmware(priv->firmware);
+    }
+
+    if (ret != WLAN_STATUS_SUCCESS) {
+        Adapter->HardwareStatus = WlanHardwareStatusNotReady;
+        ret = WLAN_STATUS_FAILURE;
+    }
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function frees the structure of adapter
+ *    
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void
+wlan_free_adapter(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!Adapter) {
+        PRINTM(INFO, "Why double free adapter?:)\n");
+        return;
+    }
+
+    PRINTM(INFO, "Free Command buffer\n");
+    wlan_free_cmd_buffer(priv);
+
+    PRINTM(INFO, "Free CommandTimer\n");
+    if (Adapter->CommandTimerIsSet) {
+        wlan_cancel_timer(&Adapter->MrvDrvCommandTimer);
+        Adapter->CommandTimerIsSet = FALSE;
+    }
+    FreeTimer(&Adapter->MrvDrvCommandTimer);
+#ifdef REASSOCIATION
+    PRINTM(INFO, "Free MrvDrvTimer\n");
+    if (Adapter->ReassocTimerIsSet) {
+        wlan_cancel_timer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+    FreeTimer(&Adapter->MrvDrvTimer);
+#endif /* REASSOCIATION */
+
+    if (Adapter->bgScanConfig) {
+        kfree(Adapter->bgScanConfig);
+        Adapter->bgScanConfig = NULL;
+    }
+
+    OS_FREE_LOCK(&Adapter->CurrentTxLock);
+    OS_FREE_LOCK(&Adapter->QueueSpinLock);
+
+    PRINTM(INFO, "Free ScanTable\n");
+    if (Adapter->ScanTable) {
+        kfree(Adapter->ScanTable);
+        Adapter->ScanTable = NULL;
+    }
+
+    PRINTM(INFO, "Free Adapter\n");
+
+    /* Free the adapter object itself */
+    kfree(Adapter);
+    priv->adapter = NULL;
+    LEAVE();
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_join.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_join.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_join.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_join.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,2255 @@
+/** @file wlan_join.c
+ *
+ *  @brief Functions implementing wlan infrastructure and adhoc join routines
+ *
+ *  IOCTL handlers as well as command preperation and response routines
+ *   for sending adhoc start, adhoc join, and association commands
+ *   to the firmware.
+ *  
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *   
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    01/11/06: Initial revision. Match new scan code, relocate related functions
+    01/19/06: Fix failure to save adhoc ssid as current after adhoc start
+    03/16/06: Add a semaphore to protect reassociation thread
+
+************************************************************/
+
+#include    "wlan_headers.h"
+
+/**
+ *  @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ *   care, either before or after calling this function
+ *
+ *  @param Adapter     A pointer to wlan_adapter structure
+ *  @param rate1       the buffer which keeps input and output
+ *  @param rate1_size  the size of rate1 buffer
+ *  @param rate2       the buffer which keeps rate2
+ *  @param rate2_size  the size of rate2 buffer.
+ *
+ *  @return            WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+get_common_rates(wlan_adapter * Adapter, u8 * rate1,
+                 int rate1_size, u8 * rate2, int rate2_size)
+{
+    u8 *ptr = rate1;
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 *tmp = NULL;
+    int i, j;
+
+    if (!(tmp = kmalloc(rate1_size, GFP_KERNEL))) {
+        PRINTM(WARN, "Allocate buffer for common rates failed\n");
+        return -ENOMEM;
+    }
+
+    memcpy(tmp, rate1, rate1_size);
+    memset(rate1, 0, rate1_size);
+
+    for (i = 0; rate2[i] && i < rate2_size; i++) {
+        for (j = 0; tmp[j] && j < rate1_size; j++) {
+            /* Check common rate, excluding the bit for basic rate */
+            if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+                *rate1++ = tmp[j];
+                break;
+            }
+        }
+    }
+
+    HEXDUMP("rate1 (AP) Rates", tmp, rate1_size);
+    HEXDUMP("rate2 (Card) Rates", rate2, rate2_size);
+    HEXDUMP("Common Rates", ptr, rate1 - ptr);
+    PRINTM(INFO, "Tx DataRate is set to 0x%X\n", Adapter->DataRate);
+
+    if (!Adapter->Is_DataRate_Auto) {
+        while (*ptr) {
+            if ((*ptr & 0x7f) == Adapter->DataRate) {
+                ret = WLAN_STATUS_SUCCESS;
+                goto done;
+            }
+            ptr++;
+        }
+        PRINTM(MSG, "Previously set fixed data rate %#x isn't "
+               "compatible with the network.\n", Adapter->DataRate);
+
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    kfree(tmp);
+    return ret;
+}
+
+/**
+ *  @brief Create the intersection of the rates supported by a target BSS and
+ *         our Adapter settings for use in an assoc/join command.
+ *
+ *  @param Adapter       A pointer to wlan_adapter structure
+ *  @param pBSSDesc      BSS Descriptor whose rates are used in the setup
+ *  @param pOutRates     Output: Octet array of rates common between the BSS
+ *                       and the Adapter supported rates settings
+ *  @param pOutRatesSize Output: Number of rates/octets set in pOutRates
+ *
+ *  @return              WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ */
+static int
+setup_rates_from_bssdesc(wlan_adapter * Adapter,
+                         BSSDescriptor_t * pBSSDesc,
+                         u8 * pOutRates, int *pOutRatesSize)
+{
+    u8 *card_rates;
+    int card_rates_size;
+
+    ENTER();
+
+    memcpy(pOutRates, pBSSDesc->SupportedRates, WLAN_SUPPORTED_RATES);
+
+    switch (pBSSDesc->bss_band) {
+    case BAND_B:
+    case BAND_G:
+        PRINTM(INFO, "Setup BG-Band Rates: %d\n", pBSSDesc->bss_band);
+        card_rates = SupportedRates_G;
+        card_rates_size = sizeof(SupportedRates_G);
+        break;
+
+    case BAND_A:
+        PRINTM(INFO, "Setup A-Band Rates: %d\n", pBSSDesc->bss_band);
+        card_rates = SupportedRates_A;
+        card_rates_size = sizeof(SupportedRates_A);
+        break;
+
+    default:
+        PRINTM(INFO, "Invalid band setting: %d\n", pBSSDesc->bss_band);
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    if (get_common_rates(Adapter, pOutRates, WLAN_SUPPORTED_RATES,
+                         card_rates, card_rates_size)) {
+        *pOutRatesSize = 0;
+        PRINTM(INFO, "get_common_rates failed\n");
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    *pOutRatesSize = MIN(strlen(pOutRates), WLAN_SUPPORTED_RATES);
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Convert band to radio type used in channel TLV
+ *
+ *  @param scanBand  Band enumeration to convert to a channel TLV radio type
+ *
+ *  @return          Radio type designator for use in a channel TLV
+ *
+ */
+static u8
+band_to_radio_type(u8 band)
+{
+    u8 retRadioType;
+
+    switch (band) {
+    case BAND_A:
+        retRadioType = HostCmd_SCAN_RADIO_TYPE_A;
+        break;
+    case BAND_B:
+    case BAND_G:
+    default:
+        retRadioType = HostCmd_SCAN_RADIO_TYPE_BG;
+        break;
+    }
+
+    return retRadioType;
+}
+
+/**
+ *  @brief Retrieve the association response
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_assoc_rsp_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int copySize;
+
+    /*
+     * Set the amount to copy back to the application as the minimum of the
+     *   available assoc resp data or the buffer provided by the application
+     */
+    copySize = MIN(Adapter->assocRspSize, wrq->u.data.length);
+
+    /* Copy the (re)association response back to the application */
+    if (copy_to_user(wrq->u.data.pointer, Adapter->assocRspBuffer, copySize)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    /* Returned copy length */
+    wrq->u.data.length = copySize;
+
+    /* Reset assoc buffer */
+    Adapter->assocRspSize = 0;
+
+    /* No error on return */
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Set an opaque block of Marvell TLVs for insertion into the
+ *         association command
+ *
+ *  Pass an opaque block of data, expected to be Marvell TLVs, to the driver
+ *    for eventual passthrough to the firmware in an associate/join
+ *    (and potentially start) command.
+ *
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_mrvl_tlv_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    /* If the passed length is zero, reset the buffer */
+    if (wrq->u.data.length == 0) {
+        Adapter->mrvlAssocTlvBufferLen = 0;
+    } else {
+        /*
+         * Verify that the passed length is not larger than the available
+         *   space remaining in the buffer
+         */
+        if (wrq->u.data.length < (sizeof(Adapter->mrvlAssocTlvBuffer)
+                                  - Adapter->mrvlAssocTlvBufferLen)) {
+            /* Append the passed data to the end of the mrvlAssocTlvBuffer */
+            if (copy_from_user(Adapter->mrvlAssocTlvBuffer
+                               + Adapter->mrvlAssocTlvBufferLen,
+                               wrq->u.data.pointer, wrq->u.data.length)) {
+                PRINTM(INFO, "Copy from user failed\n");
+                return -EFAULT;
+            }
+
+            /* Increment the stored buffer length by the size passed */
+            Adapter->mrvlAssocTlvBufferLen += wrq->u.data.length;
+        } else {
+            /* Passed data does not fit in the remaining buffer space */
+            ret = WLAN_STATUS_FAILURE;
+        }
+    }
+
+    /* Return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE */
+    return ret;
+}
+
+/**
+ *  @brief Stop Adhoc Network
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_do_adhocstop_ioctl(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+        ret = wlan_disconnect(priv);
+    } else {
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Set essid
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    WLAN_802_11_SSID reqSSID;
+    int i;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    /* Clear any past association response stored for application retrieval */
+    Adapter->assocRspSize = 0;
+
+#ifdef REASSOCIATION
+    // cancel re-association timer if there's one
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        wlan_cancel_timer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_set_essid\n");
+        return -EBUSY;
+    }
+#endif /* REASSOCIATION */
+
+    /* Check the size of the string */
+    if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+        ret = -E2BIG;
+        goto setessid_ret;
+    }
+
+    memset(&reqSSID, 0, sizeof(WLAN_802_11_SSID));
+
+    /*
+     * Check if we asked for `any' or 'particular'
+     */
+    if (!dwrq->flags) {
+        if (wlan_find_best_network_ssid(priv, &reqSSID)) {
+            PRINTM(INFO, "Could not find best network\n");
+            ret = WLAN_STATUS_SUCCESS;
+            goto setessid_ret;
+        }
+    } else {
+        /* Set the SSID */
+#if WIRELESS_EXT > 20
+        reqSSID.SsidLength = dwrq->length;
+#else
+        reqSSID.SsidLength = dwrq->length - 1;
+#endif
+        memcpy(reqSSID.Ssid, extra, reqSSID.SsidLength);
+
+    }
+
+    PRINTM(INFO, "Requested new SSID = %s\n",
+           (reqSSID.SsidLength > 0) ? (char *) reqSSID.Ssid : "NULL");
+
+    if (!reqSSID.SsidLength || reqSSID.Ssid[0] < 0x20) {
+        PRINTM(INFO, "Invalid SSID - aborting set_essid\n");
+        ret = -EINVAL;
+        goto setessid_ret;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+        /* infrastructure mode */
+        PRINTM(INFO, "SSID requested = %s\n", reqSSID.Ssid);
+
+        if ((dwrq->flags & IW_ENCODE_INDEX) > 1) {
+            i = (dwrq->flags & IW_ENCODE_INDEX) - 1;    /* convert to 0 based */
+
+            PRINTM(INFO, "Request SSID by index = %d\n", i);
+
+            if (i > Adapter->NumInScanTable) {
+                /* Failed to find in table since index is > current max. */
+                i = -EINVAL;
+            }
+        } else {
+            wlan_cmd_specific_scan_ssid(priv, &reqSSID);
+            i = wlan_find_ssid_in_list(Adapter,
+                                       &reqSSID,
+                                       NULL, Wlan802_11Infrastructure);
+        }
+
+        if (i >= 0) {
+            PRINTM(INFO, "SSID found in scan list ... associating...\n");
+
+            ret = wlan_associate(priv, &Adapter->ScanTable[i]);
+
+            if (ret) {
+                goto setessid_ret;
+            }
+        } else {                /* i >= 0 */
+            ret = i;            /* return -ENETUNREACH, passed from wlan_find_ssid_in_list */
+            goto setessid_ret;
+        }
+    } else {
+        /* ad hoc mode */
+        /* If the requested SSID matches current SSID return */
+        if (!wlan_ssid_cmp
+            (&Adapter->CurBssParams.BSSDescriptor.Ssid, &reqSSID)) {
+            ret = WLAN_STATUS_SUCCESS;
+            goto setessid_ret;
+        }
+
+        /*
+         * Exit Adhoc mode
+         */
+        PRINTM(INFO, "Sending Adhoc Stop\n");
+        ret = wlan_disconnect(priv);
+
+        if (ret) {
+            goto setessid_ret;
+        }
+
+        Adapter->AdhocLinkSensed = FALSE;
+
+        if ((dwrq->flags & IW_ENCODE_INDEX) > 1) {
+            i = (dwrq->flags & IW_ENCODE_INDEX) - 1;    /* 0 based */
+            if (i > Adapter->NumInScanTable) {
+                /* Failed to find in table since index is > current max. */
+                i = -EINVAL;
+            }
+        } else {
+            /* Scan for the network */
+            wlan_cmd_specific_scan_ssid(priv, &reqSSID);
+
+            /* Search for the requested SSID in the scan table */
+            i = wlan_find_ssid_in_list(Adapter, &reqSSID, NULL,
+                                       Wlan802_11IBSS);
+        }
+
+        if (i >= 0) {
+            PRINTM(INFO, "SSID found at %d in List, so join\n", i);
+            wlan_join_adhoc(priv, &Adapter->ScanTable[i]);
+        } else {
+            /* else send START command */
+            PRINTM(INFO, "SSID not found in list, "
+                   "so creating adhoc with ssid = %s\n", reqSSID.Ssid);
+
+            wlan_start_adhoc(priv, &reqSSID);
+        }                       /* end of else (START command) */
+    }                           /* end of else (Ad hoc mode) */
+
+    /*
+     * The MediaConnectStatus change can be removed later when
+     *   the ret code is being properly returned.
+     */
+    /* Check to see if we successfully connected */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        ret = WLAN_STATUS_SUCCESS;
+    } else {
+        ret = -ENETDOWN;
+    }
+
+  setessid_ret:
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * NOTE: Scan should be issued by application before this function is called
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param awrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+             struct sockaddr *awrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
+    u8 reqBSSID[ETH_ALEN];
+    int i;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    /* Clear any past association response stored for application retrieval */
+    Adapter->assocRspSize = 0;
+
+    if (awrq->sa_family != ARPHRD_ETHER)
+        return -EINVAL;
+
+    PRINTM(INFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n",
+           (u8) awrq->sa_data[0], (u8) awrq->sa_data[1],
+           (u8) awrq->sa_data[2], (u8) awrq->sa_data[3],
+           (u8) awrq->sa_data[4], (u8) awrq->sa_data[5]);
+
+#ifdef REASSOCIATION
+    // cancel re-association timer if there's one
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        wlan_cancel_timer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+#endif /* REASSOCIATION */
+
+    if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
+        i = wlan_find_best_ssid_in_list(Adapter);
+    } else {
+        //check if we already assoicate to the AP           
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            if (memcmp
+                (awrq->sa_data,
+                 Adapter->CurBssParams.BSSDescriptor.MacAddress,
+                 ETH_ALEN) == 0)
+                return WLAN_STATUS_SUCCESS;
+        }
+        memcpy(reqBSSID, awrq->sa_data, ETH_ALEN);
+
+        PRINTM(INFO, "ASSOC: WAP: Bssid = %02x:%02x:%02x:%02x:%02x:%02x\n",
+               reqBSSID[0], reqBSSID[1], reqBSSID[2],
+               reqBSSID[3], reqBSSID[4], reqBSSID[5]);
+
+        /* Search for index position in list for requested MAC */
+        i = wlan_find_bssid_in_list(Adapter, reqBSSID,
+                                    Adapter->InfrastructureMode);
+    }
+
+    if (i < 0) {
+        PRINTM(INFO, "ASSOC: WAP: MAC address not found in BSSID List\n");
+        return -ENETUNREACH;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+        ret = wlan_associate(priv, &Adapter->ScanTable[i]);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    } else {
+        /* Exit Adhoc mode */
+        ret = wlan_disconnect(priv);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+        Adapter->AdhocLinkSensed = FALSE;
+
+        wlan_join_adhoc(priv, &Adapter->ScanTable[i]);
+    }
+
+    /* Check to see if we successfully connected */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        ret = WLAN_STATUS_SUCCESS;
+    } else {
+        ret = -ENETDOWN;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Associated to a specific BSS discovered in a scan
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param pBSSDesc  Pointer to the BSS descriptor to associate with.
+ *
+ *  @return          WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int enableData = TRUE;
+    union iwreq_data wrqu;
+    int ret;
+    IEEEtypes_AssocRsp_t *pAssocRsp;
+    u8 currentBSSID[ETH_ALEN];
+    int reassocAttempt = FALSE;
+
+    ENTER();
+
+    /* Return error if the Adapter or table entry is not marked as infra */
+    if ((Adapter->InfrastructureMode != Wlan802_11Infrastructure)
+        || (pBSSDesc->InfrastructureMode != Wlan802_11Infrastructure)) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    memcpy(&currentBSSID,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress,
+           sizeof(currentBSSID));
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        reassocAttempt = TRUE;
+        PRINTM(INFO, "Attempting reassociation, stopping wmm queues\n");
+        wmm_stop_queue(priv);
+    }
+
+    /* Clear any past association response stored for application retrieval */
+    Adapter->assocRspSize = 0;
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc);
+
+    if (Adapter->wmm.enabled) {
+        /* Don't re-enable carrier until we get the WMM_GET_STATUS event */
+        enableData = FALSE;
+    } else {
+        /* Since WMM is not enabled, setup the queues with the defaults */
+        wmm_setup_queues(priv);
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+        if (reassocAttempt
+            && (memcmp(&currentBSSID,
+                       &Adapter->CurBssParams.BSSDescriptor.MacAddress,
+                       sizeof(currentBSSID)) == 0)) {
+
+            /* Reassociation attempt failed, still associated to old AP,
+             **   no need to wait for WMM notification to restart data
+             */
+            enableData = TRUE;
+        }
+        if (enableData) {
+            PRINTM(INFO, "Post association, re-enabling data flow\n");
+            wmm_start_queue(priv);
+            os_carrier_on(priv);
+            os_start_queue(priv);
+        }
+    } else {
+        PRINTM(INFO, "Post association, stopping data flow\n");
+        os_carrier_off(priv);
+        os_stop_queue(priv);
+    }
+
+    memcpy(wrqu.ap_addr.sa_data,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    pAssocRsp = (IEEEtypes_AssocRsp_t *) Adapter->assocRspBuffer;
+
+    if (ret || pAssocRsp->StatusCode) {
+        ret = -ENETUNREACH;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Associated to a specific indexed entry in the ScanTable
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param tableIdx  Index into the ScanTable to associate to, index parameter
+ *                   base value is 1.  No scanning is done before the 
+ *                   association attempt.
+ *
+ *  @return          WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+wlan_associate_to_table_idx(wlan_private * priv, int tableIdx)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret;
+
+    ENTER();
+
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error\n");
+        return -EBUSY;
+    }
+#endif
+
+    PRINTM(INFO, "ASSOC: iwpriv: Index = %d, NumInScanTable = %d\n",
+           tableIdx, Adapter->NumInScanTable);
+
+    /* Check index in table, subtract 1 if within range and call association
+     *   sub-function.  ScanTable[] is 0 based, parameter is 1 based to
+     *   conform with IW_ENCODE_INDEX flag parameter passing in iwconfig/iwlist
+     */
+    if (tableIdx && (tableIdx <= Adapter->NumInScanTable)) {
+        ret = wlan_associate(priv, &Adapter->ScanTable[tableIdx - 1]);
+    } else {
+        ret = -EINVAL;
+    }
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief Start an Adhoc Network
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param AdhocSSID    The ssid of the Adhoc Network
+ *  @return             WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+wlan_start_adhoc(wlan_private * priv, WLAN_802_11_SSID * AdhocSSID)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if ((Adapter->adhoc_start_band == BAND_A) && (Adapter->AdhocAutoSel)) {
+        Adapter->AdhocChannel = wlan_11h_get_adhoc_start_channel(priv);
+
+        /*
+         ** Check if the region and channel requires a channel availability
+         **   check.
+         */
+        if (wlan_11h_radar_detect_required(priv, Adapter->AdhocChannel)) {
+            /*
+             ** Radar detection is required for this channel, make sure
+             **   11h is activated in the firmware
+             */
+            wlan_11h_activate(priv, TRUE);
+
+            /* Check for radar on the channel */
+            if (wlan_11h_radar_detected(priv, Adapter->AdhocChannel)) {
+                LEAVE();
+                return WLAN_STATUS_FAILURE;
+            }
+        }
+    }
+
+    PRINTM(INFO, "Adhoc Channel = %d\n", priv->adapter->AdhocChannel);
+    PRINTM(INFO, "CurBssParams.channel = %d\n",
+           priv->adapter->CurBssParams.BSSDescriptor.Channel);
+    PRINTM(INFO, "CurBssParams.band = %d\n",
+           priv->adapter->CurBssParams.band);
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, AdhocSSID);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Join an adhoc network found in a previous scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pBSSDesc     Pointer to a BSS descriptor found in a previous scan
+ *                      to attempt to join
+ *
+ *  @return             WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+wlan_join_adhoc(wlan_private * priv, BSSDescriptor_t * pBSSDesc)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    PRINTM(INFO, "wlan_join_adhoc: CurBss.ssid =%s\n",
+           Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
+    PRINTM(INFO, "wlan_join_adhoc: CurBss.ssid_len =%u\n",
+           Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength);
+    PRINTM(INFO, "wlan_join_adhoc: ssid =%s\n", pBSSDesc->Ssid.Ssid);
+    PRINTM(INFO, "wlan_join_adhoc: ssid len =%u\n",
+           pBSSDesc->Ssid.SsidLength);
+
+    /* check if the requested SSID is already joined */
+    if (Adapter->CurBssParams.BSSDescriptor.Ssid.SsidLength
+        && !wlan_ssid_cmp(&pBSSDesc->Ssid,
+                          &Adapter->CurBssParams.BSSDescriptor.Ssid)
+        && (Adapter->CurBssParams.BSSDescriptor.InfrastructureMode ==
+            Wlan802_11IBSS)) {
+
+        PRINTM(INFO,
+               "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+               "not attempting to re-join");
+
+        return WLAN_STATUS_FAILURE;
+    }
+
+    PRINTM(INFO, "CurBssParams.channel = %d\n",
+           Adapter->CurBssParams.BSSDescriptor.Channel);
+    PRINTM(INFO, "CurBssParams.band = %c\n", Adapter->CurBssParams.band);
+
+    // store the SSID info temporarily
+    memset(&Adapter->AttemptedSSIDBeforeScan, 0, sizeof(WLAN_802_11_SSID));
+    memcpy(&Adapter->AttemptedSSIDBeforeScan,
+           &pBSSDesc->Ssid, sizeof(WLAN_802_11_SSID));
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Send Deauthentication Request or Stop the AdHoc network depending on mode
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @return          WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+int
+wlan_disconnect(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    struct sockaddr saddr;
+    int ret = WLAN_STATUS_SUCCESS;
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            memcpy((void *) saddr.sa_data,
+                   (void *) &Adapter->CurBssParams.BSSDescriptor.MacAddress,
+                   ETH_ALEN);
+            ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+                                   0, HostCmd_OPTION_WAITFORRSP,
+                                   0, (void *) &saddr);
+
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+            ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
+                                   0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+        }
+    }
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Set Idle Off
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlanidle_off(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    const u8 zeroMac[] = { 0, 0, 0, 0, 0, 0 };
+    int i;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            if (memcmp(Adapter->PreviousBSSID, zeroMac, sizeof(zeroMac)) != 0) {
+
+                PRINTM(INFO, "Previous SSID = %s\n",
+                       Adapter->PreviousSSID.Ssid);
+                PRINTM(INFO, "Previous BSSID = "
+                       "%02x:%02x:%02x:%02x:%02x:%02x:\n",
+                       Adapter->PreviousBSSID[0], Adapter->PreviousBSSID[1],
+                       Adapter->PreviousBSSID[2], Adapter->PreviousBSSID[3],
+                       Adapter->PreviousBSSID[4], Adapter->PreviousBSSID[5]);
+
+                i = wlan_find_ssid_in_list(Adapter,
+                                           &Adapter->PreviousSSID,
+                                           Adapter->PreviousBSSID,
+                                           Adapter->InfrastructureMode);
+
+                if (i < 0) {
+                    wlan_cmd_specific_scan_bssid(priv,
+                                                 Adapter->PreviousBSSID);
+                    i = wlan_find_ssid_in_list(Adapter,
+                                               &Adapter->PreviousSSID,
+                                               Adapter->PreviousBSSID,
+                                               Adapter->InfrastructureMode);
+                }
+
+                if (i < 0) {
+                    /* If the BSSID could not be found, try just the SSID */
+                    i = wlan_find_ssid_in_list(Adapter,
+                                               &Adapter->PreviousSSID,
+                                               NULL,
+                                               Adapter->InfrastructureMode);
+                }
+
+                if (i < 0) {
+                    wlan_cmd_specific_scan_ssid(priv, &Adapter->PreviousSSID);
+                    i = wlan_find_ssid_in_list(Adapter,
+                                               &Adapter->PreviousSSID,
+                                               NULL,
+                                               Adapter->InfrastructureMode);
+                }
+
+                if (i >= 0) {
+                    ret = wlan_associate(priv, &Adapter->ScanTable[i]);
+                }
+            }
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+            ret = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_802_11_AD_HOC_START,
+                                   0, HostCmd_OPTION_WAITFORRSP,
+                                   0, &Adapter->PreviousSSID);
+        }
+    }
+    /* else it is connected */
+
+    PRINTM(INFO, "\nwlanidle is off");
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Set Idle On
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlanidle_on(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            PRINTM(INFO, "Previous SSID = %s\n", Adapter->PreviousSSID.Ssid);
+            memcpy(&Adapter->PreviousSSID,
+                   &Adapter->CurBssParams.BSSDescriptor.Ssid,
+                   sizeof(WLAN_802_11_SSID));
+            wlan_disconnect(priv);
+
+        } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+            ret = wlan_disconnect(priv);
+        }
+
+    }
+#ifdef REASSOCIATION
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        wlan_cancel_timer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+#endif /* REASSOCIATION */
+
+    PRINTM(INFO, "\nwlanidle is on");
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Append a generic IE as a passthrough TLV to a TLV buffer.
+ *
+ *  This function is called from the network join command prep. routine. 
+ *    If the IE buffer has been setup by the application, this routine appends
+ *    the buffer as a passthrough TLV type to the request.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ppBuffer pointer to command buffer pointer
+ *
+ *  @return         bytes added to the buffer
+ */
+static int
+wlan_cmd_append_generic_ie(wlan_private * priv, u8 ** ppBuffer)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int retLen = 0;
+    MrvlIEtypesHeader_t ieHeader;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    /*
+     * If there is a generic ie buffer setup, append it to the return
+     *   parameter buffer pointer.
+     */
+    if (Adapter->genIeBufferLen) {
+        PRINTM(INFO, "append generic %d to %p\n", Adapter->genIeBufferLen,
+               *ppBuffer);
+
+        /* Wrap the generic IE buffer with a passthrough TLV type */
+        ieHeader.Type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+        ieHeader.Len = wlan_cpu_to_le16(Adapter->genIeBufferLen);
+        memcpy(*ppBuffer, &ieHeader, sizeof(ieHeader));
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += sizeof(ieHeader);
+        retLen += sizeof(ieHeader);
+
+        /* Copy the generic IE buffer to the output buffer, advance pointer */
+        memcpy(*ppBuffer, Adapter->genIeBuffer, Adapter->genIeBufferLen);
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += Adapter->genIeBufferLen;
+        retLen += Adapter->genIeBufferLen;
+
+        /* Reset the generic IE buffer */
+        Adapter->genIeBufferLen = 0;
+    }
+
+    /* return the length appended to the buffer */
+    return retLen;
+}
+
+/**
+ *  @brief Append any application provided Marvell TLVs to a TLV buffer.
+ *
+ *  This function is called from the network join command prep. routine. 
+ *    If the Marvell TLV buffer has been setup by the application, this routine
+ *    appends the buffer to the request.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ppBuffer pointer to command buffer pointer
+ *
+ *  @return         bytes added to the buffer
+ */
+static int
+wlan_cmd_append_marvell_tlv(wlan_private * priv, u8 ** ppBuffer)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int retLen = 0;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    /*
+     * If there is a Marvell TLV buffer setup, append it to the return
+     *   parameter buffer pointer.
+     */
+    if (Adapter->mrvlAssocTlvBufferLen) {
+        PRINTM(INFO, "append tlv %d to %p\n",
+               Adapter->mrvlAssocTlvBufferLen, *ppBuffer);
+
+        /* Copy the TLV buffer to the output buffer, advance pointer */
+        memcpy(*ppBuffer,
+               Adapter->mrvlAssocTlvBuffer, Adapter->mrvlAssocTlvBufferLen);
+
+        /* Increment the return size and the return buffer pointer param */
+        *ppBuffer += Adapter->mrvlAssocTlvBufferLen;
+        retLen += Adapter->mrvlAssocTlvBufferLen;
+
+        /* Reset the Marvell TLV buffer */
+        Adapter->mrvlAssocTlvBufferLen = 0;
+    }
+
+    /* return the length appended to the buffer */
+    return retLen;
+}
+
+/**
+ *  @brief Append TSF tracking info from the scan table for the target AP
+ *
+ *  This function is called from the network join command prep. routine. 
+ *    The TSF table TSF sent to the firmware contians two TSF values:
+ *      - the TSF of the target AP from its previous beacon/probe response
+ *      - the TSF timestamp of our local MAC at the time we observed the
+ *        beacon/probe response.
+ *
+ *    The firmware uses the timestamp values to set an initial TSF value
+ *      in the MAC for the new association after a reassociation attempt.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ppBuffer A pointer to command buffer pointer
+ *  @param pBSSDesc A pointer to the BSS Descriptor from the scan table of
+ *                  the AP we are trying to join
+ *
+ *  @return         bytes added to the buffer
+ */
+static int
+wlan_cmd_append_tsf_tlv(wlan_private * priv, u8 ** ppBuffer,
+                        BSSDescriptor_t * pBSSDesc)
+{
+    MrvlIEtypes_TsfTimestamp_t tsfTlv;
+    u64 tsfVal;
+
+    /* Null Checks */
+    if (ppBuffer == 0)
+        return 0;
+    if (*ppBuffer == 0)
+        return 0;
+
+    tsfTlv.Header.Type = wlan_cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+    tsfTlv.Header.Len = wlan_cpu_to_le16(2 * sizeof(tsfVal));
+
+    memcpy(*ppBuffer, &tsfTlv, sizeof(tsfTlv.Header));
+    *ppBuffer += sizeof(tsfTlv.Header);
+
+    /* TSF timestamp from the firmware TSF when the bcn/prb rsp was received */
+    tsfVal = wlan_cpu_to_le64(pBSSDesc->networkTSF);
+    memcpy(*ppBuffer, &tsfVal, sizeof(tsfVal));
+    *ppBuffer += sizeof(tsfVal);
+
+    memcpy(&tsfVal, pBSSDesc->TimeStamp, sizeof(tsfVal));
+
+    PRINTM(INFO, "ASSOC: TSF offset calc: %016llx - %016llx\n",
+           tsfVal, pBSSDesc->networkTSF);
+
+    tsfVal = wlan_cpu_to_le64(tsfVal);
+    memcpy(*ppBuffer, &tsfVal, sizeof(tsfVal));
+    *ppBuffer += sizeof(tsfVal);
+
+    return (sizeof(tsfTlv.Header) + (2 * sizeof(tsfVal)));
+}
+
+/**
+ *  @brief This function prepares command of deauthenticate.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf Void cast of MAC Address to deauth
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_deauthenticate(wlan_private * priv,
+                               HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_802_11_DEAUTHENTICATE *pDeauth = &cmd->params.deauth;
+    struct sockaddr *p_saddr = (struct sockaddr *) pdata_buf;
+
+    ENTER();
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_DEAUTHENTICATE) + S_DS_GEN);
+
+    /* set AP MAC address */
+    memcpy(pDeauth->MacAddr, p_saddr->sa_data, ETH_ALEN);
+
+    /* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+    pDeauth->ReasonCode = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function prepares command of association.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf Void cast of BSSDescriptor_t from the scan table to assoc
+ *  @return          WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_associate(wlan_private * priv,
+                          HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_ASSOCIATE *pAsso = &cmd->params.associate;
+    int ret = WLAN_STATUS_SUCCESS;
+    BSSDescriptor_t *pBSSDesc;
+    WLAN_802_11_RATES rates;
+    int ratesSize;
+    u8 *pos;
+    u16 TmpCap;
+    MrvlIEtypes_SsIdParamSet_t *pSsidTlv;
+    MrvlIEtypes_PhyParamSet_t *pPhyTlv;
+    MrvlIEtypes_SsParamSet_t *pSsTlv;
+    MrvlIEtypes_RatesParamSet_t *pRatesTlv;
+    MrvlIEtypes_AuthType_t *pAuthTlv;
+    MrvlIEtypes_RsnParamSet_t *pRsnTlv;
+    MrvlIEtypes_ChanListParamSet_t *pChanTlv;
+
+    ENTER();
+
+    pBSSDesc = (BSSDescriptor_t *) pdata_buf;
+    pos = (u8 *) pAsso;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+    /* Save so we know which BSS Desc to use in the response handler */
+    Adapter->pAttemptedBSSDesc = pBSSDesc;
+
+    memcpy(pAsso->PeerStaAddr,
+           pBSSDesc->MacAddress, sizeof(pAsso->PeerStaAddr));
+    pos += sizeof(pAsso->PeerStaAddr);
+
+    /* set the listen interval */
+    pAsso->ListenInterval = wlan_cpu_to_le16(Adapter->ListenInterval);
+
+    pos += sizeof(pAsso->CapInfo);
+    pos += sizeof(pAsso->ListenInterval);
+    pos += sizeof(pAsso->Reserved1);
+
+    pSsidTlv = (MrvlIEtypes_SsIdParamSet_t *) pos;
+    pSsidTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_SSID);
+    pSsidTlv->Header.Len = pBSSDesc->Ssid.SsidLength;
+    memcpy(pSsidTlv->SsId, pBSSDesc->Ssid.Ssid, pSsidTlv->Header.Len);
+    pos += sizeof(pSsidTlv->Header) + pSsidTlv->Header.Len;
+    pSsidTlv->Header.Len = wlan_cpu_to_le16(pSsidTlv->Header.Len);
+
+    pPhyTlv = (MrvlIEtypes_PhyParamSet_t *) pos;
+    pPhyTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS);
+    pPhyTlv->Header.Len = sizeof(pPhyTlv->fh_ds.DsParamSet);
+    memcpy(&pPhyTlv->fh_ds.DsParamSet,
+           &pBSSDesc->PhyParamSet.DsParamSet.CurrentChan,
+           sizeof(pPhyTlv->fh_ds.DsParamSet));
+    pos += sizeof(pPhyTlv->Header) + pPhyTlv->Header.Len;
+    pPhyTlv->Header.Len = wlan_cpu_to_le16(pPhyTlv->Header.Len);
+
+    pSsTlv = (MrvlIEtypes_SsParamSet_t *) pos;
+    pSsTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CF);
+    pSsTlv->Header.Len = sizeof(pSsTlv->cf_ibss.CfParamSet);
+    pos += sizeof(pSsTlv->Header) + pSsTlv->Header.Len;
+    pSsTlv->Header.Len = wlan_cpu_to_le16(pSsTlv->Header.Len);
+
+    /* Get the common rates supported between the driver and the BSS Desc */
+    if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Setup the Rates TLV in the association command */
+    pRatesTlv = (MrvlIEtypes_RatesParamSet_t *) pos;
+    pRatesTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_RATES);
+    pRatesTlv->Header.Len = wlan_cpu_to_le16(ratesSize);
+    memcpy(pRatesTlv->Rates, rates, ratesSize);
+    pos += sizeof(pRatesTlv->Header) + ratesSize;
+    PRINTM(INFO, "ASSOC_CMD: Rates size = %d\n", ratesSize);
+
+    /* Add the Authentication type to be used for Auth frames if needed */
+    pAuthTlv = (MrvlIEtypes_AuthType_t *) pos;
+    pAuthTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+    pAuthTlv->Header.Len = sizeof(pAuthTlv->AuthType);
+    pAuthTlv->AuthType = Adapter->SecInfo.AuthenticationMode;
+    pos += sizeof(pAuthTlv->Header) + pAuthTlv->Header.Len;
+    pAuthTlv->Header.Len = wlan_cpu_to_le16(pAuthTlv->Header.Len);
+
+    /* Append a channel TLV for the channel the attempted AP was found on */
+    pChanTlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+    pChanTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+    pChanTlv->Header.Len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+    memset(pChanTlv->ChanScanParam, 0x00, sizeof(ChanScanParamSet_t));
+    pChanTlv->ChanScanParam[0].ChanNumber =
+        (pBSSDesc->PhyParamSet.DsParamSet.CurrentChan);
+    PRINTM(INFO, "Assoc: TLV Chan = %d\n",
+           pChanTlv->ChanScanParam[0].ChanNumber);
+
+    pChanTlv->ChanScanParam[0].RadioType
+        = band_to_radio_type(pBSSDesc->bss_band);
+
+    PRINTM(INFO, "Assoc: TLV Band = %d\n",
+           pChanTlv->ChanScanParam[0].RadioType);
+    pos += sizeof(pChanTlv->Header) + sizeof(ChanScanParamSet_t);
+
+    if (!Adapter->wps.SessionEnable) {
+        if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled) {
+            pRsnTlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+            pRsnTlv->Header.Type = (u16) Adapter->Wpa_ie[0];    /* WPA_IE or WPA2_IE */
+            pRsnTlv->Header.Type = pRsnTlv->Header.Type & 0x00FF;
+            pRsnTlv->Header.Type = wlan_cpu_to_le16(pRsnTlv->Header.Type);
+            pRsnTlv->Header.Len = (u16) Adapter->Wpa_ie[1];
+            pRsnTlv->Header.Len = pRsnTlv->Header.Len & 0x00FF;
+            if (pRsnTlv->Header.Len <= (sizeof(Adapter->Wpa_ie) - 2)) {
+                memcpy(pRsnTlv->RsnIE, &Adapter->Wpa_ie[2],
+                       pRsnTlv->Header.Len);
+            } else {
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            HEXDUMP("ASSOC_CMD: RSN IE", (u8 *) pRsnTlv,
+                    sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len);
+            pos += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
+            pRsnTlv->Header.Len = wlan_cpu_to_le16(pRsnTlv->Header.Len);
+        }
+    }
+
+    wlan_wmm_process_association_req(priv, &pos, &pBSSDesc->wmmIE);
+
+    wlan_cmd_append_generic_ie(priv, &pos);
+
+    wlan_cmd_append_marvell_tlv(priv, &pos);
+
+    wlan_cmd_append_tsf_tlv(priv, &pos, pBSSDesc);
+
+    if (wlan_parse_dnld_countryinfo_11d(priv)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /*
+     * Call 11h join API after capability bits are set so adhoc/infra 11h
+     * behavior can be properly triggered.  pos modified if data is appended
+     */
+    wlan_11h_process_join(priv, &pos, &pAsso->CapInfo,
+                          pBSSDesc->PhyParamSet.DsParamSet.CurrentChan,
+                          &pBSSDesc->wlan_11h_bss_info);
+
+    cmd->Size = wlan_cpu_to_le16((u16) (pos - (u8 *) pAsso) + S_DS_GEN);
+
+    /* set the Capability info at last */
+    memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(pAsso->CapInfo));
+    TmpCap &= CAPINFO_MASK;
+    PRINTM(INFO, "ASSOC_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n",
+           TmpCap, CAPINFO_MASK);
+    TmpCap = wlan_cpu_to_le16(TmpCap);
+    memcpy(&pAsso->CapInfo, &TmpCap, sizeof(pAsso->CapInfo));
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function prepares command of ad_hoc_start.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *  @param pssid    A pointer to WLAN_802_11_SSID structure
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_ad_hoc_start(wlan_private * priv,
+                             HostCmd_DS_COMMAND * cmd, void *pssid)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_AD_HOC_START *adhs = &cmd->params.ads;
+    int ret = WLAN_STATUS_SUCCESS;
+    int cmdAppendSize = 0;
+    int i;
+    u16 TmpCap;
+    BSSDescriptor_t *pBSSDesc;
+    MrvlIEtypes_ChanListParamSet_t *pChanTlv;
+    MrvlIEtypes_RsnParamSet_t *pRsnTlv;
+    u8 *pos;
+    pos = (u8 *) adhs + sizeof(HostCmd_DS_802_11_AD_HOC_START);
+
+    ENTER();
+
+    if (!Adapter) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+    pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
+    Adapter->pAttemptedBSSDesc = pBSSDesc;
+
+    /*
+     * Fill in the parameters for 2 data structures:
+     *   1. HostCmd_DS_802_11_AD_HOC_START Command
+     *   2. pBSSDesc
+     *
+     * Driver will fill up SSID, BSSType,IBSS param, Physical Param,
+     *   probe delay, and Cap info.
+     *
+     * Firmware will fill up beacon period, Basic rates
+     *   and operational rates.
+     */
+
+    memset(adhs->SSID, 0, MRVDRV_MAX_SSID_LENGTH);
+
+    memcpy(adhs->SSID, ((WLAN_802_11_SSID *) pssid)->Ssid,
+           ((WLAN_802_11_SSID *) pssid)->SsidLength);
+
+    PRINTM(INFO, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+    memset(pBSSDesc->Ssid.Ssid, 0, MRVDRV_MAX_SSID_LENGTH);
+    memcpy(pBSSDesc->Ssid.Ssid,
+           ((WLAN_802_11_SSID *) pssid)->Ssid,
+           ((WLAN_802_11_SSID *) pssid)->SsidLength);
+
+    pBSSDesc->Ssid.SsidLength = ((WLAN_802_11_SSID *) pssid)->SsidLength;
+
+    /* set the BSS type */
+    adhs->BSSType = HostCmd_BSS_TYPE_IBSS;
+    pBSSDesc->InfrastructureMode = Wlan802_11IBSS;
+    adhs->BeaconPeriod = wlan_cpu_to_le16(Adapter->BeaconPeriod);
+    pBSSDesc->BeaconPeriod = Adapter->BeaconPeriod;
+
+    /* set Physical param set */
+#define DS_PARA_IE_ID   3
+#define DS_PARA_IE_LEN  1
+
+    adhs->PhyParamSet.DsParamSet.ElementId = DS_PARA_IE_ID;
+    adhs->PhyParamSet.DsParamSet.Len = DS_PARA_IE_LEN;
+    if (Adapter->adhoc_start_band == BAND_A)
+        Adapter->AdhocChannel = wlan_11h_get_adhoc_start_channel(priv);
+    Adapter->AdhocAutoSel = TRUE;
+    if (!get_cfp_by_band_and_channel
+        (Adapter->adhoc_start_band, (u16) Adapter->AdhocChannel,
+         Adapter->region_channel)) {
+        CHANNEL_FREQ_POWER *cfp;
+        cfp = get_cfp_by_band_and_channel(Adapter->adhoc_start_band,
+                                          FIRST_VALID_CHANNEL,
+                                          Adapter->region_channel);
+        if (cfp)
+            Adapter->AdhocChannel = cfp->Channel;
+    }
+
+    ASSERT(Adapter->AdhocChannel);
+
+    PRINTM(INFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n",
+           Adapter->AdhocChannel);
+
+    Adapter->CurBssParams.BSSDescriptor.Channel = Adapter->AdhocChannel;
+    Adapter->CurBssParams.band = Adapter->adhoc_start_band;
+
+    pBSSDesc->Channel = Adapter->AdhocChannel;
+    adhs->PhyParamSet.DsParamSet.CurrentChan = Adapter->AdhocChannel;
+
+    memcpy(&pBSSDesc->PhyParamSet,
+           &adhs->PhyParamSet, sizeof(IEEEtypes_PhyParamSet_t));
+
+    pBSSDesc->NetworkTypeInUse = Wlan802_11DS;
+
+    /* set IBSS param set */
+#define IBSS_PARA_IE_ID   6
+#define IBSS_PARA_IE_LEN  2
+
+    adhs->SsParamSet.IbssParamSet.ElementId = IBSS_PARA_IE_ID;
+    adhs->SsParamSet.IbssParamSet.Len = IBSS_PARA_IE_LEN;
+    adhs->SsParamSet.IbssParamSet.AtimWindow
+        = wlan_cpu_to_le16(Adapter->AtimWindow);
+    pBSSDesc->ATIMWindow = Adapter->AtimWindow;
+    memcpy(&pBSSDesc->SsParamSet,
+           &adhs->SsParamSet, sizeof(IEEEtypes_SsParamSet_t));
+
+    /* set Capability info */
+    adhs->Cap.Ess = 0;
+    adhs->Cap.Ibss = 1;
+    pBSSDesc->Cap.Ibss = 1;
+
+    /* set up privacy in pBSSDesc */
+    if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
+        || Adapter->AdhocAESEnabled || Adapter->SecInfo.WPAEnabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+        PRINTM(INFO, "ADHOC_S_CMD: WEPStatus set, Privacy to WEP\n");
+        pBSSDesc->Privacy = Wlan802_11PrivFilter8021xWEP;
+        adhs->Cap.Privacy = AD_HOC_CAP_PRIVACY_ON;
+    } else {
+        PRINTM(INFO, "ADHOC_S_CMD: WEPStatus NOT set, Setting "
+               "Privacy to ACCEPT ALL\n");
+        pBSSDesc->Privacy = Wlan802_11PrivFilterAcceptAll;
+    }
+
+    memset(adhs->DataRate, 0, sizeof(adhs->DataRate));
+
+    if (Adapter->adhoc_start_band == BAND_A) {
+        memcpy(adhs->DataRate, AdhocRates_A,
+               MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_A)));
+    } else if (Adapter->adhoc_start_band == BAND_G ||
+               Adapter->adhoc_grate_enabled == TRUE) {
+        memcpy(adhs->DataRate, AdhocRates_G,
+               MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_G)));
+        if (Adapter->
+            CurrentPacketFilter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON) {
+            ret =
+                wlan_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, 0,
+                                 HostCmd_OPTION_WAITFORRSP, 0,
+                                 &Adapter->CurrentPacketFilter);
+            if (ret) {
+                PRINTM(INFO, "ADHOC_S_CMD: G Protection config failed\n");
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+        }
+    } else if (Adapter->adhoc_start_band == BAND_B) {
+        memcpy(adhs->DataRate, AdhocRates_B,
+               MIN(sizeof(adhs->DataRate), sizeof(AdhocRates_B)));
+    }
+
+    /* Find the last non zero */
+    for (i = 0; i < sizeof(adhs->DataRate) && adhs->DataRate[i]; i++);
+
+    Adapter->CurBssParams.NumOfRates = i;
+
+    /* Copy the ad-hoc creating rates into Current BSS state structure */
+    memcpy(&Adapter->CurBssParams.DataRates,
+           &adhs->DataRate, Adapter->CurBssParams.NumOfRates);
+
+    PRINTM(INFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n",
+           adhs->DataRate[0], adhs->DataRate[1],
+           adhs->DataRate[2], adhs->DataRate[3]);
+
+    PRINTM(INFO, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+    if (Adapter->is_multiband) {
+        /* Append a channel TLV */
+        pChanTlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+        pChanTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+        pChanTlv->Header.Len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+        memset(pChanTlv->ChanScanParam, 0x00, sizeof(ChanScanParamSet_t));
+        pChanTlv->ChanScanParam[0].ChanNumber =
+            Adapter->CurBssParams.BSSDescriptor.Channel;
+
+        PRINTM(INFO, "ADHOC_S_CMD: TLV Chan = %d\n",
+               pChanTlv->ChanScanParam[0].ChanNumber);
+
+        pChanTlv->ChanScanParam[0].RadioType
+            = band_to_radio_type(Adapter->CurBssParams.band);
+
+        PRINTM(INFO, "ADHOC_S_CMD: TLV Band = %d\n",
+               pChanTlv->ChanScanParam[0].RadioType);
+        pos += sizeof(pChanTlv->Header) + sizeof(ChanScanParamSet_t);
+        cmdAppendSize +=
+            sizeof(pChanTlv->Header) + sizeof(ChanScanParamSet_t);
+    }
+
+    if (wlan_create_dnld_countryinfo_11d(priv)) {
+        PRINTM(INFO, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /*
+     * Call 11h start API to add any 11h flags/elements as TLV parameters
+     */
+    cmdAppendSize += wlan_11h_process_start(priv, &pos, &adhs->Cap,
+                                            Adapter->AdhocChannel,
+                                            &pBSSDesc->wlan_11h_bss_info);
+
+    if (Adapter->SecInfo.WPAEnabled) {
+        pRsnTlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+        pRsnTlv->Header.Type = (u16) Adapter->Wpa_ie[0];        /* WPA_IE or WPA2_IE */
+        pRsnTlv->Header.Type = pRsnTlv->Header.Type & 0x00FF;
+        pRsnTlv->Header.Type = wlan_cpu_to_le16(pRsnTlv->Header.Type);
+        pRsnTlv->Header.Len = (u16) Adapter->Wpa_ie[1];
+        pRsnTlv->Header.Len = pRsnTlv->Header.Len & 0x00FF;
+        if (pRsnTlv->Header.Len <= (sizeof(Adapter->Wpa_ie) - 2)) {
+            memcpy(pRsnTlv->RsnIE, &Adapter->Wpa_ie[2], pRsnTlv->Header.Len);
+        } else {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        HEXDUMP("ADHOC_JOIN: RSN IE", (u8 *) pRsnTlv,
+                sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len);
+        pos += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
+        cmdAppendSize += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
+        pRsnTlv->Header.Len = wlan_cpu_to_le16(pRsnTlv->Header.Len);
+    }
+
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_START)
+                                 + S_DS_GEN + cmdAppendSize);
+
+    memcpy(&TmpCap, &adhs->Cap, sizeof(u16));
+    TmpCap = wlan_cpu_to_le16(TmpCap);
+    memcpy(&adhs->Cap, &TmpCap, sizeof(u16));
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function prepares command of ad_hoc_stop.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_ad_hoc_stop(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_STOP)
+                                 + S_DS_GEN);
+
+    if (wlan_11h_is_active(priv)) {
+        wlan_11h_activate(priv, FALSE);
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function prepares command of ad_hoc_join.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to HostCmd_DS_COMMAND structure
+ *  @param pdata_buf Void cast of BSSDescriptor_t from the scan table to join
+ *
+ *  @return          WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_ad_hoc_join(wlan_private * priv,
+                            HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_AD_HOC_JOIN *pAdHocJoin = &cmd->params.adj;
+    BSSDescriptor_t *pBSSDesc = (BSSDescriptor_t *) pdata_buf;
+    int cmdAppendSize = 0;
+    int ret = WLAN_STATUS_SUCCESS;
+    WLAN_802_11_RATES rates;
+    int ratesSize;
+    u16 TmpCap;
+    u16 CurrentPacketFilter;
+    MrvlIEtypes_ChanListParamSet_t *pChanTlv;
+    MrvlIEtypes_RsnParamSet_t *pRsnTlv;
+    u8 *pos;
+    pos = (u8 *) pAdHocJoin + sizeof(HostCmd_DS_802_11_AD_HOC_JOIN);
+
+    ENTER();
+
+#define USE_G_PROTECTION	0x02
+    if (pBSSDesc->ERPFlags & USE_G_PROTECTION) {
+        CurrentPacketFilter =
+            Adapter->
+            CurrentPacketFilter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+        ret =
+            wlan_prepare_cmd(priv, HostCmd_CMD_MAC_CONTROL, 0,
+                             HostCmd_OPTION_WAITFORRSP, 0,
+                             &CurrentPacketFilter);
+        if (ret) {
+            PRINTM(INFO, "ADHOC_S_CMD: G Protection config failed\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    }
+    Adapter->pAttemptedBSSDesc = pBSSDesc;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+    pAdHocJoin->BssDescriptor.BSSType = HostCmd_BSS_TYPE_IBSS;
+
+    pAdHocJoin->BssDescriptor.BeaconPeriod
+        = wlan_cpu_to_le16(pBSSDesc->BeaconPeriod);
+
+    memcpy(&pAdHocJoin->BssDescriptor.BSSID, &pBSSDesc->MacAddress, ETH_ALEN);
+
+    memcpy(&pAdHocJoin->BssDescriptor.SSID,
+           &pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength);
+
+    memcpy(&pAdHocJoin->BssDescriptor.PhyParamSet,
+           &pBSSDesc->PhyParamSet, sizeof(IEEEtypes_PhyParamSet_t));
+
+    memcpy(&pAdHocJoin->BssDescriptor.SsParamSet,
+           &pBSSDesc->SsParamSet, sizeof(IEEEtypes_SsParamSet_t));
+
+    memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(IEEEtypes_CapInfo_t));
+
+    TmpCap &= CAPINFO_MASK;
+
+    PRINTM(INFO, "ADHOC_J_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n",
+           TmpCap, CAPINFO_MASK);
+    memcpy(&pAdHocJoin->BssDescriptor.Cap, &TmpCap,
+           sizeof(IEEEtypes_CapInfo_t));
+
+    /* information on BSSID descriptor passed to FW */
+    PRINTM(INFO,
+           "ADHOC_J_CMD: BSSID = %02x-%02x-%02x-%02x-%02x-%02x, SSID = %s\n",
+           pAdHocJoin->BssDescriptor.BSSID[0],
+           pAdHocJoin->BssDescriptor.BSSID[1],
+           pAdHocJoin->BssDescriptor.BSSID[2],
+           pAdHocJoin->BssDescriptor.BSSID[3],
+           pAdHocJoin->BssDescriptor.BSSID[4],
+           pAdHocJoin->BssDescriptor.BSSID[5],
+           pAdHocJoin->BssDescriptor.SSID);
+
+    /* Get the common rates supported between the driver and the BSS Desc */
+    if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Copy Data Rates from the Rates recorded in scan response */
+    memset(pAdHocJoin->BssDescriptor.DataRates, 0,
+           sizeof(pAdHocJoin->BssDescriptor.DataRates));
+    memcpy(pAdHocJoin->BssDescriptor.DataRates, rates, ratesSize);
+
+    /* Copy the adhoc join rates into Current BSS state structure */
+    Adapter->CurBssParams.NumOfRates = ratesSize;
+    memcpy(&Adapter->CurBssParams.DataRates, rates, ratesSize);
+
+    /* Copy the channel information */
+    Adapter->CurBssParams.BSSDescriptor.Channel = pBSSDesc->Channel;
+    Adapter->CurBssParams.band = pBSSDesc->bss_band;
+
+    if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
+        || Adapter->AdhocAESEnabled) {
+        pAdHocJoin->BssDescriptor.Cap.Privacy = AD_HOC_CAP_PRIVACY_ON;
+    }
+
+    if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) {
+        /* wake up first */
+        WLAN_802_11_POWER_MODE LocalPSMode;
+
+        LocalPSMode = Wlan802_11PowerModeCAM;
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_PS_MODE,
+                               HostCmd_ACT_GEN_SET, 0, 0, &LocalPSMode);
+
+        if (ret) {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    }
+
+    if (Adapter->is_multiband) {
+        /* Append a channel TLV */
+        pChanTlv = (MrvlIEtypes_ChanListParamSet_t *) pos;
+        pChanTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+        pChanTlv->Header.Len = wlan_cpu_to_le16(sizeof(ChanScanParamSet_t));
+
+        memset(pChanTlv->ChanScanParam, 0x00, sizeof(ChanScanParamSet_t));
+        pChanTlv->ChanScanParam[0].ChanNumber =
+            (pBSSDesc->PhyParamSet.DsParamSet.CurrentChan);
+        PRINTM(INFO, "ADHOC_J_CMD: TLV Chan = %d\n",
+               pChanTlv->ChanScanParam[0].ChanNumber);
+
+        pChanTlv->ChanScanParam[0].RadioType
+            = band_to_radio_type(pBSSDesc->bss_band);
+
+        PRINTM(INFO, "ADHOC_J_CMD: TLV Band = %d\n",
+               pChanTlv->ChanScanParam[0].RadioType);
+        pos += sizeof(pChanTlv->Header) + sizeof(ChanScanParamSet_t);
+        cmdAppendSize +=
+            sizeof(pChanTlv->Header) + sizeof(ChanScanParamSet_t);
+    }
+
+    if (wlan_parse_dnld_countryinfo_11d(priv)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /*
+     * Call 11h join API after capability bits are set so
+     *   adhoc/infra 11h behavior can be properly triggered.
+     *   pos modified if data is appended
+     */
+    cmdAppendSize += wlan_11h_process_join(priv, &pos,
+                                           &pAdHocJoin->BssDescriptor.Cap,
+                                           pBSSDesc->Channel,
+                                           &pBSSDesc->wlan_11h_bss_info);
+
+    if (Adapter->SecInfo.WPAEnabled) {
+        pRsnTlv = (MrvlIEtypes_RsnParamSet_t *) pos;
+        pRsnTlv->Header.Type = (u16) Adapter->Wpa_ie[0];        /* WPA_IE or WPA2_IE */
+        pRsnTlv->Header.Type = pRsnTlv->Header.Type & 0x00FF;
+        pRsnTlv->Header.Type = wlan_cpu_to_le16(pRsnTlv->Header.Type);
+        pRsnTlv->Header.Len = (u16) Adapter->Wpa_ie[1];
+        pRsnTlv->Header.Len = pRsnTlv->Header.Len & 0x00FF;
+        if (pRsnTlv->Header.Len <= (sizeof(Adapter->Wpa_ie) - 2)) {
+            memcpy(pRsnTlv->RsnIE, &Adapter->Wpa_ie[2], pRsnTlv->Header.Len);
+        } else {
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        HEXDUMP("ADHOC_JOIN: RSN IE", (u8 *) pRsnTlv,
+                sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len);
+        pos += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
+        cmdAppendSize += sizeof(pRsnTlv->Header) + pRsnTlv->Header.Len;
+        pRsnTlv->Header.Len = wlan_cpu_to_le16(pRsnTlv->Header.Len);
+    }
+
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_AD_HOC_JOIN)
+                                 + S_DS_GEN + cmdAppendSize);
+
+    memcpy(&TmpCap, &pAdHocJoin->BssDescriptor.Cap,
+           sizeof(IEEEtypes_CapInfo_t));
+    TmpCap = wlan_cpu_to_le16(TmpCap);
+
+    memcpy(&pAdHocJoin->BssDescriptor.Cap,
+           &TmpCap, sizeof(IEEEtypes_CapInfo_t));
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Association firmware command response handler
+ *
+ *   The response buffer for the association command has the following
+ *      memory layout.
+ *
+ *   For cases where an association response was not received (indicated
+ *      by the CapInfo and AId field):
+ *
+ *     .------------------------------------------------------------.
+ *     |  Header(4 * sizeof(u16)):  Standard command response hdr   |
+ *     .------------------------------------------------------------.
+ *     |  CapInfo/Error Return(u16):                                |
+ *     |           0xFFFF(-1): Internal error                       |
+ *     |           0xFFFE(-2): Authentication unhandled message     |
+ *     |           0xFFFD(-3): Authentication refused               |
+ *     |           0xFFFC(-4): Timeout waiting for AP response      |
+ *     .------------------------------------------------------------.
+ *     |  StatusCode(u16):                                          |
+ *     |        If CapInfo is -1:                                   |
+ *     |           An internal firmware failure prevented the       |
+ *     |           command from being processed.  The StatusCode    |
+ *     |           will be set to 1.                                |
+ *     |                                                            |
+ *     |        If CapInfo is -2:                                   |
+ *     |           An authentication frame was received but was     |
+ *     |           not handled by the firmware.  IEEE Status        |
+ *     |           code for the failure is returned.                |
+ *     |                                                            |
+ *     |        If CapInfo is -3:                                   |
+ *     |           An authentication frame was received and the     |
+ *     |           StatusCode is the IEEE Status reported in the    |
+ *     |           response.                                        |
+ *     |                                                            |
+ *     |        If CapInfo is -4:                                   |
+ *     |           (1) Association response timeout                 |
+ *     |           (2) Authentication response timeout              |
+ *     .------------------------------------------------------------.
+ *     |  AId(u16): 0xFFFF                                          |
+ *     .------------------------------------------------------------.
+ *
+ *
+ *   For cases where an association response was received, the IEEE 
+ *     standard association response frame is returned:
+ *
+ *     .------------------------------------------------------------.
+ *     |  Header(4 * sizeof(u16)):  Standard command response hdr   |
+ *     .------------------------------------------------------------.
+ *     |  CapInfo(u16): IEEE Capability                             |
+ *     .------------------------------------------------------------.
+ *     |  StatusCode(u16): IEEE Status Code                         |
+ *     .------------------------------------------------------------.
+ *     |  AId(u16): IEEE Association ID                             |
+ *     .------------------------------------------------------------.
+ *     |  IEEE IEs(variable): Any received IEs comprising the       |
+ *     |                      remaining portion of a received       |
+ *     |                      association response frame.           |
+ *     .------------------------------------------------------------.
+ *
+ *  For simplistic handling, the StatusCode field can be used to determine
+ *    an association success (0) or failure (non-zero).
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_associate(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    IEEEtypes_AssocRsp_t *pAssocRsp;
+    BSSDescriptor_t *pBSSDesc;
+    WLAN_802_11_RATES rates;
+    int ratesSize;
+
+    ENTER();
+
+    pAssocRsp = (IEEEtypes_AssocRsp_t *) & resp->params;
+
+    HEXDUMP("ASSOC_RESP:", (void *) &resp->params,
+            wlan_le16_to_cpu(resp->Size) - S_DS_GEN);
+
+    Adapter->assocRspSize = MIN(wlan_le16_to_cpu(resp->Size) - S_DS_GEN,
+                                sizeof(Adapter->assocRspBuffer));
+
+    memcpy(Adapter->assocRspBuffer, &resp->params, Adapter->assocRspSize);
+
+    if (pAssocRsp->StatusCode) {
+        priv->adapter->dbg.num_cmd_assoc_failure++;
+        PRINTM(CMND, "ASSOC_RESP: Association Failed, "
+               "status code = %d, error = %d\n",
+               pAssocRsp->StatusCode, *(short *) &pAssocRsp->Capability);
+
+        ret = WLAN_STATUS_FAILURE;
+
+        goto done;
+    }
+
+    /* Send a Media Connected event, according to the Spec */
+    Adapter->MediaConnectStatus = WlanMediaStateConnected;
+
+    /* Set the attempted BSSID Index to current */
+    pBSSDesc = Adapter->pAttemptedBSSDesc;
+
+    PRINTM(INFO, "ASSOC_RESP: %s\n", pBSSDesc->Ssid.Ssid);
+
+    /* Make a copy of current BSSID descriptor */
+    memcpy(&Adapter->CurBssParams.BSSDescriptor,
+           pBSSDesc, sizeof(BSSDescriptor_t));
+
+    /* update CurBssParams */
+    Adapter->CurBssParams.BSSDescriptor.Channel
+        = pBSSDesc->PhyParamSet.DsParamSet.CurrentChan;
+    Adapter->CurBssParams.band = pBSSDesc->bss_band;
+
+    if (setup_rates_from_bssdesc(Adapter, pBSSDesc, rates, &ratesSize)) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Copy the infra. association rates into Current BSS state structure */
+    Adapter->CurBssParams.NumOfRates = ratesSize;
+    memcpy(&Adapter->CurBssParams.DataRates, rates, ratesSize);
+
+    /* Adjust the timestamps in the scan table to be relative to the newly
+     *   associated AP's TSF
+     */
+    wlan_scan_update_tsf_timestamps(priv, pBSSDesc);
+
+    if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
+        Adapter->CurBssParams.wmm_enabled = TRUE;
+    } else {
+        Adapter->CurBssParams.wmm_enabled = FALSE;
+    }
+
+    if (Adapter->wmm.required && Adapter->CurBssParams.wmm_enabled) {
+        Adapter->wmm.enabled = TRUE;
+    } else {
+        Adapter->wmm.enabled = FALSE;
+    }
+
+    Adapter->CurBssParams.wmm_uapsd_enabled = FALSE;
+
+    if (Adapter->wmm.enabled == TRUE) {
+        Adapter->CurBssParams.wmm_uapsd_enabled
+            = pBSSDesc->wmmIE.QoSInfo.QosUAPSD;
+    }
+
+    PRINTM(INFO, "ASSOC_RESP: CurrentPacketFilter is %x\n",
+           Adapter->CurrentPacketFilter);
+
+    if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled)
+        Adapter->IsGTK_SET = FALSE;
+
+    Adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+    Adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+    memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
+    memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
+    Adapter->nextSNRNF = 0;
+    Adapter->numSNRNF = 0;
+
+    priv->adapter->dbg.num_cmd_assoc_success++;
+    PRINTM(INFO, "ASSOC_RESP: Associated \n");
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function handles the command response of deauthenticate
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_deauthenticate(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    Adapter->dbg.num_cmd_deauth++;
+    if (memcmp(resp->params.deauth.MacAddr,
+               &Adapter->CurBssParams.BSSDescriptor.MacAddress,
+               sizeof(resp->params.deauth.MacAddr)) == 0) {
+        wlan_reset_connect_state(priv);
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function handles the command response of ad_hoc_start and
+ *  ad_hoc_join
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_ad_hoc(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 Command = resp->Command;
+    u16 Result = resp->Result;
+    HostCmd_DS_802_11_AD_HOC_RESULT *pAdHocResult;
+    union iwreq_data wrqu;
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    pAdHocResult = &resp->params.result;
+
+    pBSSDesc = Adapter->pAttemptedBSSDesc;
+
+    /*
+     * Join result code 0 --> SUCCESS
+     */
+    if (Result) {
+        PRINTM(INFO, "ADHOC_RESP Failed\n");
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            wlan_reset_connect_state(priv);
+        }
+
+        memset(&Adapter->CurBssParams.BSSDescriptor,
+               0x00, sizeof(Adapter->CurBssParams.BSSDescriptor));
+
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /* Send a Media Connected event, according to the Spec */
+    Adapter->MediaConnectStatus = WlanMediaStateConnected;
+
+    if (Command == HostCmd_CMD_802_11_AD_HOC_START) {
+        PRINTM(INFO, "ADHOC_S_RESP  %s\n", pBSSDesc->Ssid.Ssid);
+
+        /* Update the created network descriptor with the new BSSID */
+        memcpy(pBSSDesc->MacAddress, pAdHocResult->BSSID, ETH_ALEN);
+
+        Adapter->AdhocState = ADHOC_STARTED;
+    } else {
+        /*
+         * Now the join cmd should be successful
+         * If BSSID has changed use SSID to compare instead of BSSID
+         */
+        PRINTM(INFO, "ADHOC_J_RESP  %s\n", pBSSDesc->Ssid.Ssid);
+
+        /* Make a copy of current BSSID descriptor, only needed for join since
+         *   the current descriptor is already being used for adhoc start
+         */
+        memcpy(&Adapter->CurBssParams.BSSDescriptor,
+               pBSSDesc, sizeof(BSSDescriptor_t));
+
+        Adapter->AdhocState = ADHOC_JOINED;
+    }
+
+    memset(&wrqu, 0, sizeof(wrqu));
+    memcpy(wrqu.ap_addr.sa_data,
+           &Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+    wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+    PRINTM(INFO, "ADHOC_RESP: Channel = %d\n", Adapter->AdhocChannel);
+    PRINTM(INFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[0],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[1],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[2],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[3],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[4],
+           Adapter->CurBssParams.BSSDescriptor.MacAddress[5]);
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief This function handles the command response of ad_hoc_stop
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_ad_hoc_stop(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    ENTER();
+
+    wlan_reset_connect_state(priv);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+#ifdef REASSOCIATION
+/**
+ *  @brief This function handles re-association. it is triggered
+ *  by re-assoc timer.
+ *
+ *  @param data    A pointer to wlan_thread structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+int
+wlan_reassociation_thread(void *data)
+{
+    wlan_thread *thread = data;
+    wlan_private *priv = thread->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    wait_queue_t wait;
+    int i;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    wlan_activate_thread(thread);
+    init_waitqueue_entry(&wait, current);
+
+    current->flags |= PF_NOFREEZE;
+
+    for (;;) {
+        add_wait_queue(&thread->waitQ, &wait);
+        OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
+
+        PRINTM(INFO, "Reassoc: Thread sleeping...\n");
+
+        schedule();
+
+        OS_SET_THREAD_STATE(TASK_RUNNING);
+        remove_wait_queue(&thread->waitQ, &wait);
+
+        if (Adapter->SurpriseRemoved) {
+            break;
+        }
+
+        if (kthread_should_stop()) {
+            break;
+        }
+
+        PRINTM(INFO, "Reassoc: Thread waking up...\n");
+
+        if (Adapter->InfrastructureMode != Wlan802_11Infrastructure ||
+            Adapter->HardwareStatus != WlanHardwareStatusReady) {
+            PRINTM(MSG, "Reassoc: mode or hardware status is not correct\n");
+            continue;
+        }
+
+        /* The semaphore is used to avoid reassociation thread and 
+           wlan_set_scan/wlan_set_essid interrupting each other.
+           Reassociation should be disabled completely by application if 
+           wlan_set_user_scan_ioctl/wlan_set_wap is used.
+         */
+        if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+            PRINTM(ERROR, "Acquire semaphore error, reassociation thread\n");
+            goto settimer;
+        }
+
+        if (Adapter->MediaConnectStatus != WlanMediaStateDisconnected) {
+            OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+            PRINTM(MSG, "Reassoc: Adapter->MediaConnectStatus is wrong\n");
+            continue;
+        }
+
+        PRINTM(INFO, "Reassoc: Required ESSID: %s\n",
+               Adapter->PreviousSSID.Ssid);
+
+        PRINTM(INFO, "Reassoc: Performing Active Scan @ %lu\n",
+               os_time_get());
+        wlan_cmd_specific_scan_ssid(priv, &Adapter->PreviousSSID);
+        if (Adapter->SurpriseRemoved)
+            break;
+        i = wlan_find_ssid_in_list(Adapter,
+                                   &Adapter->PreviousSSID,
+                                   Adapter->PreviousBSSID,
+                                   Adapter->InfrastructureMode);
+
+        if (i < 0) {
+            /* If the SSID could not be found, try just the SSID */
+            i = wlan_find_ssid_in_list(Adapter,
+                                       &Adapter->PreviousSSID,
+                                       NULL, Adapter->InfrastructureMode);
+        }
+
+        if (i >= 0) {
+            if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
+                ret = wlan_prepare_cmd(priv,
+                                       HostCmd_CMD_802_11_SET_WEP,
+                                       HostCmd_ACT_ADD,
+                                       HostCmd_OPTION_WAITFORRSP, 0, NULL);
+                if (ret)
+                    PRINTM(INFO, "Ressoc: Fail to set WEP KEY\n");
+            }
+            wlan_associate(priv, &Adapter->ScanTable[i]);
+        }
+
+        OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+
+      settimer:
+        if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+            PRINTM(INFO, "Reassoc: No AP found or assoc failed."
+                   "Restarting re-assoc Timer @ %lu\n", os_time_get());
+
+            Adapter->ReassocTimerIsSet = TRUE;
+            wlan_mod_timer(&Adapter->MrvDrvTimer, MRVDRV_TIMER_10S);
+        }
+    }
+
+    wlan_deactivate_thread(thread);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function triggers re-association by waking up
+ *  re-assoc thread.
+ *  
+ *  @param FunctionContext    A pointer to FunctionContext
+ *  @return 	   n/a
+ */
+void
+wlan_reassoc_timer_func(void *FunctionContext)
+{
+    wlan_private *priv = (wlan_private *) FunctionContext;
+    wlan_adapter *Adapter = priv->adapter;
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    PRINTM(INFO, "MrvDrvReassocTimer fired.\n");
+    Adapter->ReassocTimerIsSet = FALSE;
+    if (Adapter->PSState != PS_STATE_FULL_POWER) {
+        /* wait until Exit_PS command returns */
+        Adapter->ReassocTimerIsSet = TRUE;
+        wlan_mod_timer(&Adapter->MrvDrvTimer, MRVDRV_TIMER_1S);
+        PRINTM(INFO, "MrvDrvTimerFunction(PSState=%d) waiting"
+               "for Exit_PS done\n", Adapter->PSState);
+        LEAVE();
+        return;
+    }
+
+    PRINTM(INFO, "Waking Up the Reassoc Thread\n");
+
+    wake_up_interruptible(&priv->ReassocThread.waitQ);
+
+    LEAVE();
+    return;
+}
+#endif /* REASSOCIATION */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_join.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_join.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_join.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_join.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,94 @@
+/** @file wlan_join.h
+ *
+ *  @brief Interface for the wlan infrastructure and adhoc join routines
+ *
+ *  Driver interface functions and type declarations for the join module
+ *    implemented in wlan_join.c.  Process all start/join requests for
+ *    both adhoc and infrastructure networks
+ *    
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *     
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    01/11/06: Initial revision. Match new scan code, relocate related functions
+
+************************************************************/
+
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+//! Size of buffer allocated to store the association response from firmware
+#define MRVDRV_ASSOC_RSP_BUF_SIZE  500
+
+//! Size of buffer allocated to store IEs passed to firmware in the assoc req
+#define MRVDRV_GENIE_BUF_SIZE      256
+
+//! Size of buffer allocated to store TLVs passed to firmware in the assoc req
+#define MRVDRV_ASSOC_TLV_BUF_SIZE  256
+
+extern int wlan_cmd_802_11_authenticate(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * cmd,
+                                        void *pdata_buf);
+extern int wlan_cmd_802_11_ad_hoc_join(wlan_private * priv,
+                                       HostCmd_DS_COMMAND * cmd,
+                                       void *pdata_buf);
+extern int wlan_cmd_802_11_ad_hoc_stop(wlan_private * priv,
+                                       HostCmd_DS_COMMAND * cmd);
+extern int wlan_cmd_802_11_ad_hoc_start(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * cmd,
+                                        void *pssid);
+extern int wlan_cmd_802_11_deauthenticate(wlan_private * priv,
+                                          HostCmd_DS_COMMAND * cmd,
+                                          void *pdata_buf);
+extern int wlan_cmd_802_11_associate(wlan_private * priv,
+                                     HostCmd_DS_COMMAND * cmd,
+                                     void *pdata_buf);
+extern int wlan_ret_802_11_authenticate(wlan_private * priv,
+                                        HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_ad_hoc(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_ad_hoc_stop(wlan_private * priv,
+                                       HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_deauthenticate(wlan_private * priv,
+                                          HostCmd_DS_COMMAND * resp);
+extern int wlan_ret_802_11_associate(wlan_private * priv,
+                                     HostCmd_DS_COMMAND * resp);
+
+extern int wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
+extern int wlan_associate_to_table_idx(wlan_private * priv, int tableIdx);
+
+extern int wlanidle_on(wlan_private * priv);
+extern int wlanidle_off(wlan_private * priv);
+
+extern int wlan_do_adhocstop_ioctl(wlan_private * priv);
+extern int wlan_reassociation_thread(void *data);
+
+extern int wlan_start_adhoc(wlan_private * priv,
+                            WLAN_802_11_SSID * AdhocSSID);
+extern int wlan_join_adhoc(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
+extern int wlan_disconnect(wlan_private * priv);
+
+extern int wlan_do_adhocstop_ioctl(wlan_private * priv);
+extern int wlan_get_assoc_rsp_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_set_mrvl_tlv_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+#ifdef __KERNEL__
+extern int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+                        struct sockaddr *awrq, char *extra);
+#endif
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_linux.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_linux.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_linux.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_linux.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,464 @@
+/** @file wlan_linux.h
+ *  @brief This file contains Linux OS related definitions and declarations
+ *     
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	05/30/07: Initial creation
+********************************************************/
+
+#ifndef _WLAN_LINUX_H
+#define _WLAN_LINUX_H
+
+/** True */
+#ifndef	TRUE
+#define TRUE			1
+#endif
+/** False */
+#ifndef	FALSE
+#define	FALSE			0
+#endif
+
+/** Bit definitions */
+#define BIT(x)	(1 << (x))
+
+#ifndef __KERNEL__
+/** Character, 1 byte */
+typedef char s8;
+/** Unsigned character, 1 byte */
+typedef unsigned char u8;
+
+/** Short integer */
+typedef signed short s16;
+/** Unsigned short integer */
+typedef unsigned short u16;
+
+/** Long integer */
+typedef signed long s32;
+/** Unsigned long ineteger */
+typedef unsigned long u32;
+
+/** Long long integer */
+typedef signed long long s64;
+/** Unsigned long long integer */
+typedef unsigned long long u64;
+
+/** Unsigned long integer */
+typedef u32 dma_addr_t;
+/** Unsigned long integer */
+typedef u32 dma64_addr_t;
+#endif
+
+/* Dma addresses are 32-bits wide.  */
+#ifndef __ATTRIB_ALIGN__
+#define __ATTRIB_ALIGN__ __attribute__((aligned(4)))
+#endif
+
+#ifndef __ATTRIB_PACK__
+#define __ATTRIB_PACK__ __attribute__ ((packed))
+#endif
+
+/** Debug Macro definition*/
+#ifdef	DEBUG_LEVEL1
+
+extern u32 drvdbg;
+extern u32 ifdbg;
+
+/* Debug message control bit definition for drvdbg */
+#define	DBG_MSG		BIT(0)
+#define DBG_FATAL	BIT(1)
+#define DBG_ERROR	BIT(2)
+#define DBG_DATA	BIT(3)
+#define DBG_CMND	BIT(4)
+#define DBG_EVENT	BIT(5)
+#define DBG_INTR	BIT(6)
+
+#define DBG_DAT_D	BIT(16)
+#define DBG_CMD_D	BIT(17)
+#define DBG_FW_D	BIT(18)
+
+#define DBG_ENTRY	BIT(28)
+#define DBG_WARN	BIT(29)
+#define DBG_INFO	BIT(30)
+
+/* Debug message control bit definition for ifdbg */
+#define DBG_IF_D	BIT(0)
+
+#ifdef	DEBUG_LEVEL2
+#define	PRINTM_INFO(msg...)  {if (drvdbg & DBG_INFO) printk(KERN_DEBUG msg);}
+#define	PRINTM_WARN(msg...)  {if (drvdbg & DBG_WARN) printk(KERN_DEBUG msg);}
+#define	PRINTM_ENTRY(msg...) {if (drvdbg & DBG_ENTRY) printk(KERN_DEBUG msg);}
+#else
+#define	PRINTM_INFO(msg...)  do {} while (0)
+#define	PRINTM_WARN(msg...)  do {} while (0)
+#define	PRINTM_ENTRY(msg...) do {} while (0)
+#endif /* DEBUG_LEVEL2 */
+
+#define	PRINTM_FW_D(msg...)  {if (drvdbg & DBG_FW_D) printk(KERN_DEBUG msg);}
+#define	PRINTM_CMD_D(msg...) {if (drvdbg & DBG_CMD_D) printk(KERN_DEBUG msg);}
+#define	PRINTM_DAT_D(msg...) {if (drvdbg & DBG_DAT_D) printk(KERN_DEBUG msg);}
+
+#define	PRINTM_INTR(msg...)  {if (drvdbg & DBG_INTR) printk(KERN_DEBUG msg);}
+#define	PRINTM_EVENT(msg...) {if (drvdbg & DBG_EVENT) printk(msg);}
+#define	PRINTM_CMND(msg...)  {if (drvdbg & DBG_CMND) printk(KERN_DEBUG msg);}
+#define	PRINTM_DATA(msg...)  {if (drvdbg & DBG_DATA) printk(KERN_DEBUG msg);}
+#define	PRINTM_ERROR(msg...) {if (drvdbg & DBG_ERROR) printk(KERN_DEBUG msg);}
+#define	PRINTM_FATAL(msg...) {if (drvdbg & DBG_FATAL) printk(KERN_DEBUG msg);}
+#define	PRINTM_MSG(msg...)   {if (drvdbg & DBG_MSG) printk(KERN_ALERT msg);}
+
+#define	PRINTM_IF_D(msg...)  {if (ifdbg & DBG_IF_D) printk(KERN_DEBUG msg);}
+
+#define	PRINTM(level,msg...) PRINTM_##level(msg)
+
+#else
+
+#define	PRINTM(level,msg...) do {} while (0)
+
+#endif /* DEBUG_LEVEL1 */
+
+/** Wait until a condition becomes true */
+#define ASSERT(cond)						\
+do {								\
+	if (!(cond))						\
+		PRINTM(INFO, "ASSERT: %s, %s:%i\n",		\
+		       __FUNCTION__, __FILE__, __LINE__);	\
+} while(0)
+
+/** Log enrty point for debugging */
+#define	ENTER()			PRINTM(ENTRY, "Enter: %s, %s:%i\n", __FUNCTION__, \
+							__FILE__, __LINE__)
+/** Log exit point for debugging */
+#define	LEAVE()			PRINTM(ENTRY, "Leave: %s, %s:%i\n", __FUNCTION__, \
+							__FILE__, __LINE__)
+
+#if defined(DEBUG_LEVEL1) && defined(__KERNEL__)
+#define DBG_DUMP_BUF_LEN 	64
+#define MAX_DUMP_PER_LINE	16
+#define MAX_DATA_DUMP_LEN	48
+
+static inline void
+hexdump(char *prompt, u8 * buf, int len)
+{
+    int i;
+    char dbgdumpbuf[DBG_DUMP_BUF_LEN];
+    char *ptr = dbgdumpbuf;
+
+    printk(KERN_DEBUG "%s:\n", prompt);
+    for (i = 1; i <= len; i++) {
+        ptr += sprintf(ptr, "%02x ", *buf);
+        buf++;
+        if (i % MAX_DUMP_PER_LINE == 0) {
+            *ptr = 0;
+            printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+            ptr = dbgdumpbuf;
+        }
+    }
+    if (len % MAX_DUMP_PER_LINE) {
+        *ptr = 0;
+        printk(KERN_DEBUG "%s\n", dbgdumpbuf);
+    }
+}
+
+#define DBG_HEXDUMP_CMD_D(x,y,z)    {if (drvdbg & DBG_CMD_D) hexdump(x,y,z);}
+#define DBG_HEXDUMP_DAT_D(x,y,z)    {if (drvdbg & DBG_DAT_D) hexdump(x,y,z);}
+#define DBG_HEXDUMP_IF_D(x,y,z)     {if (ifdbg & DBG_IF_D) hexdump(x,y,z);}
+#define DBG_HEXDUMP_FW_D(x,y,z)     {if (drvdbg & DBG_FW_D) hexdump(x,y,z);}
+#define	DBG_HEXDUMP(level,x,y,z)    DBG_HEXDUMP_##level(x,y,z)
+
+#else
+/** Do nothing since debugging is not turned on */
+#define DBG_HEXDUMP(level,x,y,z)    do {} while (0)
+#endif
+
+#if defined(DEBUG_LEVEL2) && defined(__KERNEL__)
+#define HEXDUMP(x,y,z)              {if (drvdbg & DBG_INFO) hexdump(x,y,z);}
+#else
+/** Do nothing since debugging is not turned on */
+#define HEXDUMP(x,y,z)              do {} while (0)
+#endif
+
+/*
+ * Typedefs
+ */
+
+/** Long */
+typedef long LONG;
+/** Unsigned long long */
+typedef unsigned long long ULONGLONG;
+/** WLAN object ID as unsigned long */
+typedef u32 WLAN_OID;
+
+/** Char */
+typedef char CHAR;
+/** Pointer to a char */
+typedef char *PCHAR;
+/** Pointer to an unsigned char */
+typedef u8 *PUCHAR;
+/** Pointer to an unsigned short */
+typedef u16 *PUSHORT;
+/** Pointer to a long */
+typedef long *PLONG;
+/** Pointer to a long */
+typedef PLONG LONG_PTR;
+/** Pointer to an unsigned long */
+typedef u32 *ULONG_PTR;
+/** Pointer to an unsigned long */
+typedef u32 *Pu32;
+/** Unsigned int */
+typedef unsigned int UINT;
+/** Pointer to an unsigned int */
+typedef UINT *PUINT;
+/** Void */
+typedef void VOID;
+/** Void pointer */
+typedef VOID *PVOID;
+/** Wlan status as int */
+typedef int WLAN_STATUS;
+/** Unsigned char */
+typedef u8 BOOLEAN;
+/** Pointer to an unsigned char */
+typedef BOOLEAN *PBOOLEAN;
+/** Pointer to a driver object as a void pointer */
+typedef PVOID PDRIVER_OBJECT;
+/** Pointer to a unicoded string as pointer to an unsigned char */
+typedef PUCHAR PUNICODE_STRING;
+/** Long long */
+typedef long long LONGLONG;
+/** Pointer to a long long */
+typedef LONGLONG *PLONGLONG;
+/** Pointer to an unsigned long long */
+typedef unsigned long long *PULONGLONG;
+/** An ANSI string as pointer to an unsigned char */
+typedef PUCHAR ANSI_STRING;
+/** Pointer to an ANSI string as pointer to a pointer to an unsigned char */
+typedef ANSI_STRING *PANSI_STRING;
+/** Unsigned short */
+typedef unsigned short WCHAR;
+/** Pointer to an unsigned short */
+typedef WCHAR *PWCHAR;
+/** Pointer to an unsigned short */
+typedef WCHAR *LPWCH;
+/** Pointer to an unsigned short */
+typedef WCHAR *PWCH;
+/** Pointer to an unsigned short */
+typedef WCHAR *NWPSTR;
+/** Pointer to an unsigned short */
+typedef WCHAR *LPWSTR;
+/** Pointer to an unsigned short */
+typedef WCHAR *PWSTR;
+/** Semaphore structure */
+typedef struct semaphore SEMAPHORE;
+
+#ifdef __KERNEL__
+typedef irqreturn_t IRQ_RET_TYPE;
+#define IRQ_RET		return IRQ_HANDLED
+
+/*
+ * OS macro definitions
+ */
+
+#define os_time_get()	jiffies
+
+extern unsigned long driver_flags;
+#define OS_INT_DISABLE(x,y)	spin_lock_irqsave(&(x->adapter->driver_lock), y)
+#define	OS_INT_RESTORE(x,y)	spin_unlock_irqrestore(&(x->adapter->driver_lock), y); \
+			x->adapter->driver_lock = SPIN_LOCK_UNLOCKED
+
+#define UpdateTransStart(dev) { \
+	dev->trans_start = jiffies; \
+}
+
+#define OS_SET_THREAD_STATE(x)		set_current_state(x)
+
+#define MODULE_GET	try_module_get(THIS_MODULE)
+#define MODULE_PUT	module_put(THIS_MODULE)
+
+#define OS_INIT_SEMAPHORE(x)    	init_MUTEX(x)
+#define OS_ACQ_SEMAPHORE_BLOCK(x)	down_interruptible(x)
+#define OS_ACQ_SEMAPHORE_NOBLOCK(x)	down_trylock(x)
+#define OS_REL_SEMAPHORE(x) 		up(x)
+
+/* Definitions below are needed for other OS like threadx */
+#define	TX_DISABLE
+#define TX_RESTORE
+#define	ConfigureThreadPriority()
+#define OS_INTERRUPT_SAVE_AREA
+#define OS_FREE_LOCK(x)
+#define TX_EVENT_FLAGS_SET(x, y, z)
+
+#define os_wait_interruptible_timeout(waitq, cond, timeout) \
+	wait_event_interruptible_timeout(waitq, cond, timeout)
+
+static inline void
+os_sched_timeout(u32 millisec)
+{
+    set_current_state(TASK_INTERRUPTIBLE);
+
+    schedule_timeout((millisec * HZ) / 1000);
+}
+
+static inline u32
+get_utimeofday(void)
+{
+    struct timeval t;
+    u32 ut;
+
+    do_gettimeofday(&t);
+    ut = (u32) t.tv_sec * 1000000 + ((u32) t.tv_usec);
+    return ut;
+}
+
+/*
+ * OS timer specific
+ */
+
+typedef struct __WLAN_DRV_TIMER
+{
+    struct timer_list tl;
+    void (*timer_function) (void *context);
+    void *function_context;
+    UINT time_period;
+    BOOLEAN timer_is_periodic;
+    BOOLEAN timer_is_canceled;
+} __ATTRIB_PACK__ WLAN_DRV_TIMER, *PWLAN_DRV_TIMER;
+
+static inline void
+wlan_timer_handler(unsigned long fcontext)
+{
+    PWLAN_DRV_TIMER timer = (PWLAN_DRV_TIMER) fcontext;
+
+    timer->timer_function(timer->function_context);
+
+    if (timer->timer_is_periodic == TRUE) {
+        mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000));
+    }
+}
+
+static inline void
+wlan_initialize_timer(PWLAN_DRV_TIMER timer,
+                      void (*TimerFunction) (void *context),
+                      void *FunctionContext)
+{
+    // first, setup the timer to trigger the wlan_timer_handler proxy
+    init_timer(&timer->tl);
+    timer->tl.function = wlan_timer_handler;
+    timer->tl.data = (u32) timer;
+
+    // then tell the proxy which function to call and what to pass it       
+    timer->timer_function = TimerFunction;
+    timer->function_context = FunctionContext;
+    timer->timer_is_canceled = FALSE;
+}
+
+static inline void
+wlan_set_timer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
+{
+    timer->time_period = MillisecondPeriod;
+    timer->timer_is_periodic = FALSE;
+    timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000;
+    add_timer(&timer->tl);
+    timer->timer_is_canceled = FALSE;
+}
+
+static inline void
+wlan_mod_timer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
+{
+    timer->time_period = MillisecondPeriod;
+    timer->timer_is_periodic = FALSE;
+    mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000);
+    timer->timer_is_canceled = FALSE;
+}
+
+static inline void
+wlan_set_periodic_timer(PWLAN_DRV_TIMER timer, UINT MillisecondPeriod)
+{
+    timer->time_period = MillisecondPeriod;
+    timer->timer_is_periodic = TRUE;
+    timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000;
+    add_timer(&timer->tl);
+    timer->timer_is_canceled = FALSE;
+}
+
+#define	FreeTimer(x)	do {} while (0)
+
+static inline void
+wlan_cancel_timer(WLAN_DRV_TIMER * timer)
+{
+    del_timer(&timer->tl);
+    timer->timer_is_canceled = TRUE;
+}
+
+/*
+ * OS Thread Specific
+ */
+
+#include	<linux/kthread.h>
+
+typedef struct
+{
+    struct task_struct *task;
+    wait_queue_head_t waitQ;
+    pid_t pid;
+    void *priv;
+} wlan_thread;
+
+static inline void
+wlan_activate_thread(wlan_thread * thr)
+{
+        /** Record the thread pid */
+    thr->pid = current->pid;
+
+        /** Initialize the wait queue */
+    init_waitqueue_head(&thr->waitQ);
+}
+
+static inline void
+wlan_deactivate_thread(wlan_thread * thr)
+{
+    ENTER();
+
+    /* Reset the pid */
+    thr->pid = 0;
+    LEAVE();
+}
+
+static inline void
+wlan_create_thread(int (*wlanfunc) (void *), wlan_thread * thr, char *name)
+{
+    thr->task = kthread_run(wlanfunc, thr, "%s", name);
+}
+
+static inline int
+wlan_terminate_thread(wlan_thread * thr)
+{
+    ENTER();
+
+    /* Check if the thread is active or not */
+    if (!thr->pid) {
+        PRINTM(INFO, "Thread does not exist\n");
+        return -1;
+    }
+    kthread_stop(thr->task);
+
+    LEAVE();
+    return 0;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _WLAN_LINUX_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_main.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_main.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_main.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_main.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1267 @@
+/** @file wlan_main.c
+  *  
+  * @brief This file contains the major functions in WLAN
+  * driver. It includes init, exit, open, close and main
+  * thread etc..
+  * 
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/**
+  * @mainpage M-WLAN Linux Driver
+  *
+  * @section overview_sec Overview
+  *
+  * The M-WLAN is a Linux reference driver for Marvell
+  * 802.11 (a/b/g) WLAN chipset.
+  * 
+  * @section copyright_sec Copyright
+  *
+  * Copyright © Marvell International Ltd. and/or its affiliates, 2003-2007
+  *
+  */
+/********************************************************
+Change log:
+    09/30/05: Add Doxygen format comments
+    12/09/05: Add TX_QUEUE support  
+    01/05/06: Add kernel 2.6.x support  
+    01/11/06: Conditionalize new scan/join functions.
+    01/12/06: Add TxLockFlag for UAPSD power save mode 
+              and Proprietary Periodic sleep support
+********************************************************/
+
+#include    "wlan_headers.h"
+#include	"wlan_sdio.h"
+
+const char driver_version[] =
+    "sd8688-%s-" DRIVER_RELEASE_VERSION "-(" "FP" FPNUM ")"
+#ifdef	DEBUG_LEVEL2
+    "-dbg"
+#endif
+    " ";
+
+/********************************************************
+        Local Variables
+********************************************************/
+
+/** 100mW */
+#define WLAN_TX_PWR_DEFAULT     20
+/** 100mW */
+#define WLAN_TX_PWR_US_DEFAULT      20
+/** 50mW */
+#define WLAN_TX_PWR_JP_DEFAULT      16
+/** 100mW */
+#define WLAN_TX_PWR_FR_100MW        20
+/** 100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT    20
+
+/* Format { Channel, Frequency (MHz), MaxTxPower } */
+/* Band: 'B/G', Region: USA FCC/Canada IC */
+static CHANNEL_FREQ_POWER channel_freq_power_US_BG[] = {
+    {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+    {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+    {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+    {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+    {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+    {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+    {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+    {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+    {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+    {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* Band: 'B/G', Region: Europe ETSI */
+static CHANNEL_FREQ_POWER channel_freq_power_EU_BG[] = {
+    {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+    {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+    {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+    {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+    {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+    {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+    {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+    {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+    {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+    {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+    {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+    {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* Band: 'B/G', Region: Spain */
+static CHANNEL_FREQ_POWER channel_freq_power_SPN_BG[] = {
+    {10, 2457, WLAN_TX_PWR_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_DEFAULT}
+};
+
+/* Band: 'B/G', Region: France */
+static CHANNEL_FREQ_POWER channel_freq_power_FR_BG[] = {
+    {10, 2457, WLAN_TX_PWR_FR_100MW},
+    {11, 2462, WLAN_TX_PWR_FR_100MW},
+    {12, 2467, WLAN_TX_PWR_FR_100MW},
+    {13, 2472, WLAN_TX_PWR_FR_100MW}
+};
+
+/* Band: 'B/G', Region: Japan */
+static CHANNEL_FREQ_POWER channel_freq_power_JPN41_BG[] = {
+    {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+    {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+    {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+    {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+    {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+    {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+    {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+    {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+    {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+    {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+    {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+    {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+    {13, 2472, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/* Band: 'B/G', Region: Japan */
+static CHANNEL_FREQ_POWER channel_freq_power_JPN40_BG[] = {
+    {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/* Band: 'A', Region: USA FCC, Canada IC, Spain, France */
+static CHANNEL_FREQ_POWER channel_freq_power_A[] = {
+    {36, 5180, WLAN_TX_PWR_US_DEFAULT},
+    {40, 5200, WLAN_TX_PWR_US_DEFAULT},
+    {44, 5220, WLAN_TX_PWR_US_DEFAULT},
+    {48, 5240, WLAN_TX_PWR_US_DEFAULT},
+    {52, 5260, WLAN_TX_PWR_US_DEFAULT},
+    {56, 5280, WLAN_TX_PWR_US_DEFAULT},
+    {60, 5300, WLAN_TX_PWR_US_DEFAULT},
+    {64, 5320, WLAN_TX_PWR_US_DEFAULT},
+#if defined(FCC_DFS_APPROVAL) && defined(ENABLE_802_11H)
+    /* FCC_DFS_APPROVAL place holder -- remove when appropriate */
+    {100, 5500, WLAN_TX_PWR_US_DEFAULT},
+    {104, 5520, WLAN_TX_PWR_US_DEFAULT},
+    {108, 5540, WLAN_TX_PWR_US_DEFAULT},
+    {112, 5560, WLAN_TX_PWR_US_DEFAULT},
+    {116, 5580, WLAN_TX_PWR_US_DEFAULT},
+    {120, 5600, WLAN_TX_PWR_US_DEFAULT},
+    {124, 5620, WLAN_TX_PWR_US_DEFAULT},
+    {128, 5640, WLAN_TX_PWR_US_DEFAULT},
+    {132, 5660, WLAN_TX_PWR_US_DEFAULT},
+    {136, 5680, WLAN_TX_PWR_US_DEFAULT},
+    {140, 5700, WLAN_TX_PWR_US_DEFAULT},
+#endif
+    {149, 5745, WLAN_TX_PWR_US_DEFAULT},
+    {153, 5765, WLAN_TX_PWR_US_DEFAULT},
+    {157, 5785, WLAN_TX_PWR_US_DEFAULT},
+    {161, 5805, WLAN_TX_PWR_US_DEFAULT},
+    {165, 5825, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* Band: 'A', Region: Europe ETSI */
+static CHANNEL_FREQ_POWER channel_freq_power_EU_A[] = {
+    {36, 5180, WLAN_TX_PWR_EMEA_DEFAULT},
+    {40, 5200, WLAN_TX_PWR_EMEA_DEFAULT},
+    {44, 5220, WLAN_TX_PWR_EMEA_DEFAULT},
+    {48, 5240, WLAN_TX_PWR_EMEA_DEFAULT},
+    {52, 5260, WLAN_TX_PWR_EMEA_DEFAULT},
+    {56, 5280, WLAN_TX_PWR_EMEA_DEFAULT},
+    {60, 5300, WLAN_TX_PWR_EMEA_DEFAULT},
+    {64, 5320, WLAN_TX_PWR_EMEA_DEFAULT},
+    {100, 5500, WLAN_TX_PWR_EMEA_DEFAULT},
+    {104, 5520, WLAN_TX_PWR_EMEA_DEFAULT},
+    {108, 5540, WLAN_TX_PWR_EMEA_DEFAULT},
+    {112, 5560, WLAN_TX_PWR_EMEA_DEFAULT},
+    {116, 5580, WLAN_TX_PWR_EMEA_DEFAULT},
+    {120, 5600, WLAN_TX_PWR_EMEA_DEFAULT},
+    {124, 5620, WLAN_TX_PWR_EMEA_DEFAULT},
+    {128, 5640, WLAN_TX_PWR_EMEA_DEFAULT},
+    {132, 5660, WLAN_TX_PWR_EMEA_DEFAULT},
+    {136, 5680, WLAN_TX_PWR_EMEA_DEFAULT},
+    {140, 5700, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* Band: 'A', Region: Japan */
+static CHANNEL_FREQ_POWER channel_freq_power_JPN_A[] = {
+    {8, 5040, WLAN_TX_PWR_JP_DEFAULT},
+    {12, 5060, WLAN_TX_PWR_JP_DEFAULT},
+    {16, 5080, WLAN_TX_PWR_JP_DEFAULT},
+    {34, 5170, WLAN_TX_PWR_JP_DEFAULT},
+    {38, 5190, WLAN_TX_PWR_JP_DEFAULT},
+    {42, 5210, WLAN_TX_PWR_JP_DEFAULT},
+    {46, 5230, WLAN_TX_PWR_JP_DEFAULT},
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+typedef struct _region_cfp_table
+{
+    /** Region */
+    u8 region;
+    /** Frequency/Power */
+    CHANNEL_FREQ_POWER *cfp_BG;
+    /** No BG flag */
+    int cfp_no_BG;
+    /** Frequency/Power for band A */
+    CHANNEL_FREQ_POWER *cfp_A;
+    /** No A flag */
+    int cfp_no_A;
+} region_cfp_table_t;
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static region_cfp_table_t region_cfp_table[] = {
+    {0x10,                      /*US FCC */
+     channel_freq_power_US_BG,
+     sizeof(channel_freq_power_US_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_A,
+     sizeof(channel_freq_power_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x20,                      /*CANADA IC */
+     channel_freq_power_US_BG,
+     sizeof(channel_freq_power_US_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_A,
+     sizeof(channel_freq_power_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x30, /*EU*/ channel_freq_power_EU_BG,
+     sizeof(channel_freq_power_EU_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_EU_A,
+     sizeof(channel_freq_power_EU_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+     sizeof(channel_freq_power_SPN_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_A,
+     sizeof(channel_freq_power_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+     sizeof(channel_freq_power_FR_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_A,
+     sizeof(channel_freq_power_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x40, /*JAPAN*/ channel_freq_power_JPN40_BG,
+     sizeof(channel_freq_power_JPN40_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_JPN_A,
+     sizeof(channel_freq_power_JPN_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+    {0x41, /*JAPAN*/ channel_freq_power_JPN41_BG,
+     sizeof(channel_freq_power_JPN41_BG) / sizeof(CHANNEL_FREQ_POWER),
+     channel_freq_power_JPN_A,
+     sizeof(channel_freq_power_JPN_A) / sizeof(CHANNEL_FREQ_POWER),
+     }
+    ,
+/*Add new region here */
+};
+
+/********************************************************
+        Global Variables
+********************************************************/
+
+/**
+ * the rates supported by the card
+ */
+u8 WlanDataRates[WLAN_SUPPORTED_RATES] =
+    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+    0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ * the rates supported in B mode
+ */
+u8 SupportedRates_B[B_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x0b, 0x16, 0, 0, 0, 0 };
+
+/**
+ * the rates supported in G mode
+ */
+u8 SupportedRates_G[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24,
+    0x30, 0x48, 0x60, 0x6c, 0
+};
+
+/**
+ * the rates supported in A mode
+ */
+u8 SupportedRates_A[A_SUPPORTED_RATES] =
+    { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * the rates supported in A mode for ad-hoc
+ */
+u8 AdhocRates_A[A_SUPPORTED_RATES] =
+    { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+/**
+ * the rates supported for ad-hoc G mode
+ */
+u8 AdhocRates_G[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc B mode
+ */
+u8 AdhocRates_B[4] = { 0x82, 0x84, 0x8b, 0x96 };
+
+/**
+ * the global variable of a pointer to wlan_private
+ * structure variable
+ */
+wlan_private *wlanpriv = NULL;
+
+u32 DSFreqList[15] = {
+    0, 2412000, 2417000, 2422000, 2427000, 2432000, 2437000, 2442000,
+    2447000, 2452000, 2457000, 2462000, 2467000, 2472000, 2484000
+};
+
+/**
+ * the table to keep region code
+ */
+u16 RegionCodeToIndex[MRVDRV_MAX_REGION_CODE] =
+    { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40, 0x41 };
+
+/********************************************************
+        Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function opens the network device
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_open(struct net_device *dev)
+{
+    wlan_private *priv = (wlan_private *) dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    // On some systems the device open handler will be called before HW ready.
+    // Use the following flag check and wait function to work around the issue.
+    {
+        int i = 0;
+
+        while ((adapter->HardwareStatus != WlanHardwareStatusReady) &&
+               (i < MAX_WAIT_DEVICE_READY_COUNT)) {
+            i++;
+            os_sched_timeout(100);
+        }
+        if (i >= MAX_WAIT_DEVICE_READY_COUNT) {
+            PRINTM(FATAL, "HW not ready, wlan_open() return failure\n");
+            LEAVE();
+            return WLAN_STATUS_FAILURE;
+        }
+    }
+
+    if (MODULE_GET == 0)
+        return WLAN_STATUS_FAILURE;
+
+    priv->open = TRUE;
+
+    if ((adapter->MediaConnectStatus == WlanMediaStateConnected)
+        && (adapter->InfrastructureMode != Wlan802_11IBSS
+            || adapter->AdhocLinkSensed == TRUE))
+        os_carrier_on(priv);
+    else
+        os_carrier_off(priv);
+
+    os_start_queue(priv);
+    wmm_start_queue(priv);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function closes the network device
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_close(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+
+    ENTER();
+
+    if (priv->adapter)
+        wlan_clean_txrx(priv);
+
+    MODULE_PUT;
+
+    priv->open = FALSE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles packet transmission
+ *  
+ *  @param skb     A pointer to sk_buff structure
+ *  @param dev     A pointer to net_device structure
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    int ret;
+    wlan_private *priv = dev->priv;
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    PRINTM(DATA, "Data <= kernel\n");
+
+    if (wlan_tx_packet(priv, skb)) {
+        /* Transmit failed */
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function handles the timeout of packet
+ *  transmission
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        n/a
+ */
+static void
+wlan_tx_timeout(struct net_device *dev)
+{
+    wlan_private *priv = (wlan_private *) dev->priv;
+
+    ENTER();
+
+    PRINTM(DATA, "Tx timeout\n");
+    UpdateTransStart(dev);
+
+    priv->adapter->dbg.num_tx_timeout++;
+
+    priv->adapter->IntCounter++;
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function returns the network statistics
+ *  
+ *  @param dev     A pointer to wlan_private structure
+ *  @return        A pointer to net_device_stats structure
+ */
+static struct net_device_stats *
+wlan_get_stats(struct net_device *dev)
+{
+    wlan_private *priv = (wlan_private *) dev->priv;
+
+    return &priv->stats;
+}
+
+/** 
+ *  @brief This function sets the MAC address to firmware.
+ *  
+ *  @param dev     A pointer to wlan_private structure
+ *  @param addr    MAC address to set
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = (wlan_private *) dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct sockaddr *pHwAddr = (struct sockaddr *) addr;
+
+    ENTER();
+
+    memset(Adapter->CurrentAddr, 0, ETH_ALEN);
+
+    /* dev->dev_addr is 8 bytes */
+    HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+    HEXDUMP("addr:", pHwAddr->sa_data, ETH_ALEN);
+    memcpy(Adapter->CurrentAddr, pHwAddr->sa_data, ETH_ALEN);
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (ret) {
+        PRINTM(INFO, "set mac address failed.\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    HEXDUMP("Adapter->MacAddr:", Adapter->CurrentAddr, ETH_ALEN);
+    memcpy(dev->dev_addr, Adapter->CurrentAddr, ETH_ALEN);
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function sets multicast addresses to firmware
+ *  
+ *  @param dev     A pointer to net_device structure
+ *  @return        n/a
+ */
+static void
+wlan_set_multicast_list(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int OldPacketFilter;
+
+    ENTER();
+
+    OldPacketFilter = Adapter->CurrentPacketFilter;
+
+    if (dev->flags & IFF_PROMISC) {
+        PRINTM(INFO, "Enable Promiscuous mode\n");
+        Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+        Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+    } else {
+        /* Multicast */
+        Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+
+        if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+            MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+            PRINTM(INFO, "Enabling All Multicast!\n");
+            Adapter->CurrentPacketFilter |=
+                HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+        } else {
+            Adapter->CurrentPacketFilter &=
+                ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+
+            if (!dev->mc_count) {
+                PRINTM(INFO, "No multicast addresses - "
+                       "disabling multicast!\n");
+
+            } else {
+                int i;
+
+                Adapter->NumOfMulticastMACAddr =
+                    wlan_copy_mcast_addr(Adapter, dev);
+
+                PRINTM(INFO, "Multicast addresses: %d\n", dev->mc_count);
+
+                for (i = 0; i < dev->mc_count; i++) {
+                    PRINTM(INFO, "Multicast address %d:"
+                           "%x %x %x %x %x %x\n", i,
+                           Adapter->MulticastList[i][0],
+                           Adapter->MulticastList[i][1],
+                           Adapter->MulticastList[i][2],
+                           Adapter->MulticastList[i][3],
+                           Adapter->MulticastList[i][4],
+                           Adapter->MulticastList[i][5]);
+                }
+                /* set multicast addresses to firmware */
+                wlan_prepare_cmd(priv, HostCmd_CMD_MAC_MULTICAST_ADR,
+                                 HostCmd_ACT_GEN_SET, 0, 0, NULL);
+            }
+        }
+    }
+
+    if (Adapter->CurrentPacketFilter != OldPacketFilter) {
+        wlan_prepare_cmd(priv,
+                         HostCmd_CMD_MAC_CONTROL,
+                         0, 0, 0, &Adapter->CurrentPacketFilter);
+    }
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function hanldes the major job in WLAN driver.
+ *  it handles the event generated by firmware, rx data received
+ *  from firmware and tx data sent from kernel.
+ *  
+ *  @param data    A pointer to wlan_thread structure
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_service_main_thread(void *data)
+{
+    wlan_thread *thread = data;
+    wlan_private *priv = thread->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    wait_queue_t wait;
+    u8 ireg = 0;
+    unsigned long driver_flags;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    wlan_activate_thread(thread);
+
+    init_waitqueue_entry(&wait, current);
+
+    current->flags |= PF_NOFREEZE;
+
+    wlan_meas_init(priv);
+
+    PRINTM(INFO, "11H: init 11H\n");
+    wlan_11h_init(priv);
+
+    wmm_init(priv);
+
+    for (;;) {
+#define MAX_MAIN_THREAD_LOOPS (10000)
+        if (++Adapter->main_thread_loops > MAX_MAIN_THREAD_LOOPS) {
+            panic("main-thread dead loop detected: %u\n"
+                  "IntCnt=%d\n"
+                  "Adapter->HisRegCpy=%#x\n"
+                  "CurCmd=%p CmdPending=%s\n"
+                  "Connect=%s\n"
+                  "CurTxSkb=%p dnld_sent=%d\n"
+                  "IsDeepSleep=%d\n"
+                  "PSMode=%d PSState=%d\n"
+                  "WakeupDevReq=%d\n"
+                  "HS_Activated=%d\n"
+                  "WakeupTries=%d\n", Adapter->main_thread_loops,
+                  Adapter->IntCounter,
+                  Adapter->HisRegCpy,
+                  Adapter->CurCmd,
+                  list_empty(&Adapter->CmdPendingQ) ? "N" : "Y",
+                  (Adapter->MediaConnectStatus ==
+                   WlanMediaStateConnected) ? "Y" : "N",
+                  Adapter->CurrentTxSkb, priv->wlan_dev.dnld_sent,
+                  Adapter->IsDeepSleep, Adapter->PSMode, Adapter->PSState,
+                  Adapter->bWakeupDevRequired, Adapter->HS_Activated,
+                  Adapter->WakeupTries);
+        }
+
+        add_wait_queue(&thread->waitQ, &wait);
+        OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
+
+        TX_DISABLE;
+
+        if ((Adapter->WakeupTries) ||
+            (Adapter->PSState == PS_STATE_SLEEP
+             && !Adapter->bWakeupDevRequired) ||
+            (!Adapter->IntCounter &&
+             Adapter->PSState == PS_STATE_PRE_SLEEP) ||
+            (!Adapter->IntCounter
+             && (priv->wlan_dev.dnld_sent || Adapter->TxLockFlag
+                 || wmm_lists_empty(priv) || wmm_is_queue_stopped(priv))
+             && (priv->wlan_dev.dnld_sent || !Adapter->CurrentTxSkb)
+             && (priv->wlan_dev.dnld_sent || Adapter->CurCmd ||
+                 list_empty(&Adapter->CmdPendingQ))
+            )
+            ) {
+            PRINTM(INFO, "main-thread sleeping... "
+                   "HS_Act=%s WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n",
+                   (Adapter->HS_Activated) ? "Y" : "N",
+                   (Adapter->bWakeupDevRequired) ? "Y" : "N",
+                   (Adapter->MediaConnectStatus) ? "Y" : "N",
+                   Adapter->PSMode, Adapter->PSState);
+
+            TX_RESTORE;
+            Adapter->main_thread_loops = 0;
+            schedule();
+            PRINTM(INFO, "main-thread waking up: IntCnt=%d "
+                   "CurCmd=%s CmdPending=%s\n"
+                   "                       Connect=%s "
+                   "CurTxSkb=%s dnld_sent=%d\n",
+                   Adapter->IntCounter,
+                   (Adapter->CurCmd) ? "Y" : "N",
+                   list_empty(&Adapter->CmdPendingQ) ? "N" : "Y",
+                   (Adapter->MediaConnectStatus) ? "Y" : "N",
+                   (Adapter->CurrentTxSkb) ? "Y" : "N",
+                   priv->wlan_dev.dnld_sent);
+        } else {
+            TX_RESTORE;
+        }
+
+        OS_SET_THREAD_STATE(TASK_RUNNING);
+        remove_wait_queue(&thread->waitQ, &wait);
+
+        if (kthread_should_stop() || Adapter->SurpriseRemoved) {
+            PRINTM(INFO, "main-thread: break from main thread: "
+                   "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
+            break;
+        }
+
+        if (Adapter->IntCounter) {
+            OS_INT_DISABLE(priv, driver_flags);
+            Adapter->IntCounter = 0;
+            OS_INT_RESTORE(priv, driver_flags);
+
+		/*
+            if (sbi_get_int_status(priv, &ireg)) {
+                PRINTM(ERROR,
+                       "main-thread: reading HOST_INT_STATUS_REG failed\n");
+                continue;
+            }
+            OS_INT_DISABLE(priv, driver_flags);
+            Adapter->HisRegCpy |= ireg;
+            OS_INT_RESTORE(priv, driver_flags);
+            PRINTM(INTR, "INT: status = 0x%x\n", Adapter->HisRegCpy);
+	    */
+        } else if (Adapter->bWakeupDevRequired) {
+            Adapter->WakeupTries++;
+            PRINTM(CMND,
+                   "Wakeup device... WakeupReq=%s Conn=%s PS_Mode=%d PS_State=%d\n",
+                   (Adapter->bWakeupDevRequired) ? "Y" : "N",
+                   (priv->adapter->MediaConnectStatus) ? "Y" : "N",
+                   priv->adapter->PSMode, priv->adapter->PSState);
+
+            /* Wake up device */
+            if (sbi_exit_deep_sleep(priv))
+                PRINTM(MSG, "main-thread: wakeup dev failed\n");
+            continue;
+        }
+
+        /* Command response? */
+        if (Adapter->HisRegCpy & HIS_CmdUpLdRdy) {
+            OS_INT_DISABLE(priv, driver_flags);
+            Adapter->HisRegCpy &= ~HIS_CmdUpLdRdy;
+            OS_INT_RESTORE(priv, driver_flags);
+
+            wlan_process_cmdresp(priv);
+        }
+
+        /* Any Card Event */
+        if (Adapter->HisRegCpy & HIS_CardEvent) {
+            OS_INT_DISABLE(priv, driver_flags);
+            Adapter->HisRegCpy &= ~HIS_CardEvent;
+            OS_INT_RESTORE(priv, driver_flags);
+
+            wlan_process_event(priv);
+        }
+
+        /* Check if we need to confirm Sleep Request received previously */
+        if (Adapter->PSState == PS_STATE_PRE_SLEEP) {
+            if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) {
+                ASSERT(Adapter->MediaConnectStatus ==
+                       WlanMediaStateConnected);
+                wlan_ps_cond_check(priv, (u16) Adapter->PSMode);
+            }
+        }
+
+        /* The PS state is changed during processing of 
+         * Sleep Request event above 
+         */
+        if ((Adapter->PSState == PS_STATE_SLEEP)
+            || (Adapter->PSState == PS_STATE_PRE_SLEEP)) {
+            continue;
+        }
+
+        if (Adapter->IsDeepSleep)
+            continue;
+
+        /* The HS_Activated flag is changed during processing of 
+           HS_Activate command resp */
+        /* We cannot send command or data if HS_Activated and 
+           WakeupDevRequired are TRUE */
+        if (Adapter->HS_Activated && Adapter->bWakeupDevRequired) {
+            PRINTM(INFO, "main-thread: cannot send command or data, "
+                   "HS_Activated=%d\n", Adapter->HS_Activated);
+            continue;
+        }
+
+        /* Execute the next command */
+        if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) {
+            wlan_exec_next_cmd(priv);
+        }
+
+        if (!priv->wlan_dev.dnld_sent
+            && !wmm_lists_empty(priv) && !wmm_is_queue_stopped(priv)) {
+            if ((Adapter->PSState == PS_STATE_FULL_POWER)
+                || (Adapter->sleep_period.period == 0)
+                || (Adapter->TxLockFlag == FALSE)) {
+                wmm_process_tx(priv);
+            }
+        }
+
+    }
+
+    wlan_deactivate_thread(thread);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the wlan_priv and initialize the device. 
+ *  
+ *  @param card    A pointer to card
+ *  @return        A pointer to wlan_private structure
+ */
+static wlan_private *
+wlan_add_card(void *card)
+{
+    struct net_device *dev = NULL;
+    wlan_private *priv = NULL;
+
+    ENTER();
+
+    /* Allocate an Ethernet device and register it */
+    if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+        PRINTM(MSG, "Init ethernet device failed!\n");
+        return NULL;
+    }
+
+    priv = dev->priv;
+
+    /* allocate buffer for wlan_adapter */
+    if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+        PRINTM(MSG, "Allocate buffer for wlan_adapter failed!\n");
+        goto err_kmalloc;
+    }
+
+    /* init wlan_adapter */
+    memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+    priv->wlan_dev.netdev = dev;
+    priv->wlan_dev.card = card;
+    ((struct sdio_mmc_card *) card)->priv = priv;
+    wlanpriv = priv;
+
+    //SET_MODULE_OWNER(dev);
+
+    /* Setup the OS Interface to our functions */
+    dev->open = wlan_open;
+    dev->hard_start_xmit = wlan_hard_start_xmit;
+    dev->stop = wlan_close;
+    dev->do_ioctl = wlan_do_ioctl;
+    dev->set_mac_address = wlan_set_mac_address;
+
+    dev->tx_timeout = wlan_tx_timeout;
+    dev->get_stats = wlan_get_stats;
+    dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+    dev->hard_header_len += sizeof(TxPD);
+    dev->hard_header_len += SDIO_HEADER_LEN;
+
+#ifdef  WIRELESS_EXT
+#if WIRELESS_EXT < 21
+    dev->get_wireless_stats = wlan_get_wireless_stats;
+#endif
+    dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;
+#endif
+#define NETIF_F_DYNALLOC 16
+    dev->features |= NETIF_F_DYNALLOC;
+    dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+    dev->set_multicast_list = wlan_set_multicast_list;
+
+    /* init SW */
+    if (wlan_init_sw(priv)) {
+        PRINTM(FATAL, "Software Init Failed\n");
+        goto err_kmalloc;
+    }
+
+    PRINTM(INFO, "Starting kthread...\n");
+    priv->MainThread.priv = priv;
+    wlan_create_thread(wlan_service_main_thread,
+                       &priv->MainThread, "wlan_main_service");
+
+    ConfigureThreadPriority();
+
+#ifdef REASSOCIATION
+    priv->ReassocThread.priv = priv;
+    wlan_create_thread(wlan_reassociation_thread,
+                       &priv->ReassocThread, "wlan_reassoc_service");
+#endif /* REASSOCIATION */
+
+    while ((priv->MainThread.pid == 0)
+#ifdef REASSOCIATION
+           || (priv->ReassocThread.pid == 0)
+#endif
+        ) {
+        os_sched_timeout(2);
+    }
+
+    /*
+     * Register the device. Fillup the private data structure with
+     * relevant information from the card and request for the required
+     * IRQ. 
+     */
+
+    if (sbi_register_dev(priv) < 0) {
+        PRINTM(FATAL, "Failed to register wlan device!\n");
+        goto err_registerdev;
+    }
+
+    SET_NETDEV_DEV(dev, priv->hotplug_device);
+
+    /* init FW and HW */
+    if (wlan_init_fw(priv)) {
+        PRINTM(FATAL, "Firmware Init Failed\n");
+        goto err_init_fw;
+    }
+
+    if (register_netdev(dev)) {
+        printk(KERN_ERR "Cannot register network device!\n");
+        goto err_init_fw;
+    }
+    PRINTM(WARN, "%s: Marvell Wlan 802.11 Adapter "
+           "revision 0x%02X at IRQ %i\n", dev->name,
+           priv->adapter->chip_rev, dev->irq);
+
+#ifdef CONFIG_PROC_FS
+    wlan_proc_entry(priv, dev);
+#ifdef PROC_DEBUG
+    wlan_debug_entry(priv, dev);
+#endif
+#endif /* CPNFIG_PROC_FS */
+
+    LEAVE();
+    return priv;
+
+  err_init_fw:
+    sbi_unregister_dev(priv);
+
+  err_registerdev:
+    priv->adapter->SurpriseRemoved = TRUE;
+    if (priv->MainThread.pid) {
+        /* Stop the thread servicing the interrupts */
+        wake_up_interruptible(&priv->MainThread.waitQ);
+    }
+#ifdef REASSOCIATION
+    if (priv->ReassocThread.pid) {
+        wake_up_interruptible(&priv->ReassocThread.waitQ);
+    }
+#endif /* REASSOCIATION */
+
+    //waiting for main thread quit
+    while (priv->MainThread.pid
+#ifdef REASSOCIATION
+           || priv->ReassocThread.pid
+#endif
+        ) {
+        os_sched_timeout(2);
+    }
+  err_kmalloc:
+    wlan_free_adapter(priv);
+    priv->wlan_dev.netdev = NULL;
+    free_netdev(dev);
+    ((struct sdio_mmc_card *) card)->priv = NULL;
+    wlanpriv = NULL;
+
+    LEAVE();
+    return NULL;
+}
+
+/** 
+ *  @brief This function removes the card.
+ *  
+ *  @param card    A pointer to card
+ *  @return        WLAN_STATUS_SUCCESS
+ */
+static int
+wlan_remove_card(void *card)
+{
+    wlan_private *priv = wlanpriv;
+    wlan_adapter *Adapter = NULL;
+    struct net_device *dev;
+    union iwreq_data wrqu;
+    ulong flags;
+    ENTER();
+
+    if (!priv || !(Adapter = priv->adapter)) {
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+    Adapter->SurpriseRemoved = TRUE;
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        wlan_cancel_timer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+    if (Adapter->CurCmd) {
+        PRINTM(INFO, "Wake up current cmdwait_q\n");
+        Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE;
+        wlan_insert_cmd_to_free_q(priv, Adapter->CurCmd);
+        spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+        Adapter->CurCmd = NULL;
+        spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+    }
+    if (priv->MainThread.pid) {
+        /* Stop the thread servicing the interrupts */
+        wake_up_interruptible(&priv->MainThread.waitQ);
+    }
+#ifdef REASSOCIATION
+    if (priv->ReassocThread.pid) {
+        wake_up_interruptible(&priv->ReassocThread.waitQ);
+    }
+#endif /* REASSOCIATION */
+
+    /* waiting for thread quit */
+    while (priv->MainThread.pid
+#ifdef REASSOCIATION
+           || priv->ReassocThread.pid
+#endif
+        ) {
+        os_sched_timeout(1);
+    }
+
+    dev = priv->wlan_dev.netdev;
+
+    if (Adapter->IsDeepSleep == TRUE) {
+        Adapter->IsDeepSleep = FALSE;
+        wake_up_interruptible(&Adapter->ds_awake_q);
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        Adapter->MediaConnectStatus = WlanMediaStateDisconnected;
+        memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+        wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+        wlan_clean_txrx(priv);
+    }
+#ifdef CONFIG_PROC_FS
+#ifdef PROC_DEBUG
+    wlan_debug_remove(priv);
+#endif
+    wlan_proc_remove(priv);
+#endif
+
+    PRINTM(INFO, "unregester dev\n");
+    sbi_unregister_dev(priv);
+
+    PRINTM(INFO, "Free Adapter\n");
+    wlan_free_adapter(priv);
+
+    /* Last reference is our one */
+    PRINTM(INFO, "refcnt = %d\n", atomic_read(&dev->refcnt));
+
+    PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name,
+           (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style");
+
+    unregister_netdev(dev);
+
+    PRINTM(INFO, "Unregister finish\n");
+
+    priv->wlan_dev.netdev = NULL;
+    free_netdev(dev);
+    wlanpriv = NULL;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+        Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function finds the CFP in 
+ *  region_cfp_table based on region and band parameter.
+ *  
+ *  @param region  The region code
+ *  @param band    The band
+ *  @param cfp_no  A pointer to CFP number
+ *  @return        A pointer to CFP
+ */
+CHANNEL_FREQ_POWER *
+wlan_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+{
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < sizeof(region_cfp_table) / sizeof(region_cfp_table_t);
+         i++) {
+        PRINTM(INFO, "region_cfp_table[i].region=%d\n",
+               region_cfp_table[i].region);
+        if (region_cfp_table[i].region == region) {
+            if (band & (BAND_B | BAND_G)) {
+                *cfp_no = region_cfp_table[i].cfp_no_BG;
+                LEAVE();
+                return region_cfp_table[i].cfp_BG;
+            } else {
+                if (band & BAND_A) {
+                    *cfp_no = region_cfp_table[i].cfp_no_A;
+                    LEAVE();
+                    return region_cfp_table[i].cfp_A;
+                } else {
+                    PRINTM(INFO, "Error Band[%x]\n", band);
+                    LEAVE();
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    LEAVE();
+    return NULL;
+}
+
+/** 
+ *  @brief This function sets region table. 
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param region  The region code
+ *  @param band    The band
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_set_regiontable(wlan_private * priv, u8 region, u8 band)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i = 0;
+
+    CHANNEL_FREQ_POWER *cfp;
+    int cfp_no;
+
+    ENTER();
+
+    memset(Adapter->region_channel, 0, sizeof(Adapter->region_channel));
+
+    if (band & (BAND_B | BAND_G)) {
+        cfp = wlan_get_region_cfp_table(region, BAND_G | BAND_B, &cfp_no);
+        if (cfp != NULL) {
+            Adapter->region_channel[i].NrCFP = cfp_no;
+            Adapter->region_channel[i].CFP = cfp;
+        } else {
+            PRINTM(INFO, "wrong region code %#x in Band B-G\n", region);
+            return WLAN_STATUS_FAILURE;
+        }
+        Adapter->region_channel[i].Valid = TRUE;
+        Adapter->region_channel[i].Region = region;
+        Adapter->region_channel[i].Band = (band & BAND_G) ? BAND_G : BAND_B;
+        i++;
+    }
+    if (band & BAND_A) {
+        cfp = wlan_get_region_cfp_table(region, BAND_A, &cfp_no);
+        if (cfp != NULL) {
+            Adapter->region_channel[i].NrCFP = cfp_no;
+            Adapter->region_channel[i].CFP = cfp;
+        } else {
+            PRINTM(INFO, "wrong region code %#x in Band A\n", region);
+            return WLAN_STATUS_FAILURE;
+        }
+        Adapter->region_channel[i].Valid = TRUE;
+        Adapter->region_channel[i].Region = region;
+        Adapter->region_channel[i].Band = BAND_A;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function handles the interrupt. it will change PS
+ *  state if applicable. it will wake up main_thread to handle
+ *  the interrupt event as well.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return        n/a
+ */
+void
+wlan_interrupt(wlan_private * priv)
+{
+
+    priv->adapter->IntCounter++;
+
+    PRINTM(INTR, "*\n");
+
+    priv->adapter->WakeupTries = 0;
+	/* masked by feng, for there is no such support for setting bus freq */
+    //if (priv->adapter->bWakeupDevRequired)
+     //   sd_set_busclock((psd_device) priv->wlan_dev.card, 0);   /* default clock frequency */
+
+    if (priv->adapter->PSState == PS_STATE_SLEEP) {
+        priv->adapter->PSState = PS_STATE_AWAKE;
+    }
+
+    //wake_up_interruptible(&priv->MainThread.waitQ);
+}
+
+/** 
+ *  @brief This function initializes module.
+ *  
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_init_module(void)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (sbi_register(wlan_add_card, wlan_remove_card, NULL) == NULL) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function cleans module
+ *  
+ *  @return        n/a
+ */
+static void
+wlan_cleanup_module(void)
+{
+    wlan_private *priv = wlanpriv;
+    wlan_adapter *Adapter = NULL;
+
+    ENTER();
+
+    if (!priv || !priv->adapter)
+        goto exit;
+
+    Adapter = priv->adapter;
+
+    Adapter->IsAutoDeepSleepEnabled = FALSE;
+    if (Adapter->IsDeepSleep == TRUE) {
+        sbi_exit_deep_sleep(priv);
+        if (Adapter->IsDeepSleep == TRUE) {
+            if (os_wait_interruptible_timeout(Adapter->ds_awake_q,
+                                              !Adapter->IsDeepSleep,
+                                              MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT)
+                == 0) {
+                PRINTM(MSG, "ds_awake_q: timer expired\n");
+            }
+        }
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        wlan_disconnect(priv);
+
+    /* Disable interrupts on the card */
+    sbi_disable_host_int(priv);
+
+  exit:
+    sbi_unregister();
+
+    LEAVE();
+}
+
+module_init(wlan_init_module);
+module_exit(wlan_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_meas.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_meas.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_meas.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_meas.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,700 @@
+/**
+ * @file wlan_meas.c
+ *
+ *  @brief Implementation of measurement interface code with the app/firmware
+ *
+ *  Driver implementation for sending and retrieving measurement requests
+ *    and responses. 
+ *  
+ *  Current use is limited to 802.11h.
+ *
+ *  Requires use of the following preprocessor define:
+ *    - ENABLE_MEAS
+ *
+ *  @sa wlan_meas.h
+ *  
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+
+/*****************************************************************************/
+/*  Change Log:
+** 
+**      9/30/05: Initial revision            
+**
+**
+*/
+/*****************************************************************************/
+
+/*
+** Include(s)
+*/
+#include "wlan_headers.h"
+
+/*
+** Macros
+*/
+
+/*
+** Constants
+*/
+
+//! Default measurement duration when not provided by the application
+#define WLAN_MEAS_DEFAULT_MEAS_DURATION    1000U        /* TUs */
+
+#ifdef DEBUG_LEVEL2
+//! String descriptions of the different measurement enums.  Debug display
+static const char *measTypeStr[WLAN_MEAS_NUM_TYPES] = {
+    "basic",
+#if WLAN_MEAS_EXTRA_11H_TYPES
+    "cca",
+    "rpi",
+#endif
+#if WLAN_MEAS_EXTRA_11K_TYPES
+    /* 11k additions */
+    "chnld",
+    "nzhst",
+    "beacn",
+    "frame",
+    "hidnd",
+    "msenh",
+    "stast"
+#endif
+};
+
+/** 
+*** wlan_meas_get_meas_type_str
+**
+**  @brief Retrieve the measurement string representation of a measType enum
+**
+**  Used for debug display only
+**
+**  @param measType Measurement type enumeration input for string lookup
+** 
+**  @return         Constant string representing measurement type
+*/
+static const char *
+wlan_meas_get_meas_type_str(MeasType_t measType)
+{
+    if (measType <= WLAN_MEAS_11H_MAX_TYPE) {
+        return measTypeStr[measType];
+    }
+
+    return "Invld";
+}
+#endif
+
+/**
+*** wlan_meas_dump_meas_req
+**
+**  @brief Debug print display of the input measurement request
+**
+**  @param pMeasReq  Pointer to the measurement request to dispaly
+**
+**  @return          void
+*/
+static void
+wlan_meas_dump_meas_req(const HostCmd_DS_MEASUREMENT_REQUEST * pMeasReq)
+{
+    PRINTM(INFO, "Meas: Req: ------------------------------\n");
+
+    PRINTM(INFO, "Meas: Req: macAddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+           pMeasReq->macAddr[0],
+           pMeasReq->macAddr[1],
+           pMeasReq->macAddr[2],
+           pMeasReq->macAddr[3], pMeasReq->macAddr[4], pMeasReq->macAddr[5]);
+
+    PRINTM(INFO, "Meas: Req:  dlgTkn: %d\n", pMeasReq->dialogToken);
+    PRINTM(INFO, "Meas: Req:    mode: dm[%c] rpt[%c] req[%c]\n",
+           pMeasReq->reqMode.durationMandatory ? 'X' : ' ',
+           pMeasReq->reqMode.report ? 'X' : ' ',
+           pMeasReq->reqMode.request ? 'X' : ' ');
+    PRINTM(INFO, "Meas: Req:        : en[%c] par[%c]\n",
+           pMeasReq->reqMode.enable ? 'X' : ' ',
+           pMeasReq->reqMode.parallel ? 'X' : ' ');
+    PRINTM(INFO, "Meas: Req: measTyp: %s\n",
+           wlan_meas_get_meas_type_str(pMeasReq->measType));
+
+    switch (pMeasReq->measType) {
+    case WLAN_MEAS_BASIC:
+#if WLAN_MEAS_EXTRA_11H_TYPES
+        /* Not supported in firmware */
+    case WLAN_MEAS_CCA:
+    case WLAN_MEAS_RPI:
+#endif
+        /* Lazy cheat, fields of bas, cca, rpi union match on the request */
+        PRINTM(INFO, "Meas: Req: chan: %u\n", pMeasReq->req.basic.channel);
+        PRINTM(INFO, "Meas: Req: strt: %llu\n",
+               wlan_le64_to_cpu(pMeasReq->req.basic.startTime));
+        PRINTM(INFO, "Meas: Req:  dur: %u\n",
+               wlan_le16_to_cpu(pMeasReq->req.basic.duration));
+        break;
+    default:
+        PRINTM(INFO, "Meas: Req: <unhandled>\n");
+        break;
+    }
+
+    PRINTM(INFO, "Meas: Req: ------------------------------\n");
+}
+
+/**
+*** wlan_meas_dump_meas_rpt
+**
+**  @brief Debug print display of the input measurement report
+**
+**  @param pMeasRpt  Pointer to measurement report to display
+**
+**  @return          void
+*/
+static void
+wlan_meas_dump_meas_rpt(const HostCmd_DS_MEASUREMENT_REPORT * pMeasRpt)
+{
+    PRINTM(INFO, "Meas: Rpt: ------------------------------\n");
+    PRINTM(INFO, "Meas: Rpt: macAddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
+           pMeasRpt->macAddr[0],
+           pMeasRpt->macAddr[1],
+           pMeasRpt->macAddr[2],
+           pMeasRpt->macAddr[3], pMeasRpt->macAddr[4], pMeasRpt->macAddr[5]);
+
+    PRINTM(INFO, "Meas: Rpt:  dlgTkn: %d\n", pMeasRpt->dialogToken);
+
+    PRINTM(INFO, "Meas: Rpt: rptMode: (%x): Rfs[%c] ICp[%c] Lt[%c]\n",
+           *(u8 *) & pMeasRpt->rptMode,
+           pMeasRpt->rptMode.refused ? 'X' : ' ',
+           pMeasRpt->rptMode.incapable ? 'X' : ' ',
+           pMeasRpt->rptMode.late ? 'X' : ' ');
+
+    PRINTM(INFO, "Meas: Rpt: measTyp: %s\n",
+           wlan_meas_get_meas_type_str(pMeasRpt->measType));
+
+    switch (pMeasRpt->measType) {
+    case WLAN_MEAS_BASIC:
+        PRINTM(INFO, "Meas: Rpt: chan: %u\n", pMeasRpt->rpt.basic.channel);
+        PRINTM(INFO, "Meas: Rpt: strt: %llu\n",
+               wlan_le64_to_cpu(pMeasRpt->rpt.basic.startTime));
+        PRINTM(INFO, "Meas: Rpt:  dur: %u\n",
+               wlan_le16_to_cpu(pMeasRpt->rpt.basic.duration));
+        PRINTM(INFO, "Meas: Rpt:  bas: (%x): unmsd[%c], radar[%c]\n",
+               *(u8 *) & (pMeasRpt->rpt.basic.map),
+               pMeasRpt->rpt.basic.map.unmeasured ? 'X' : ' ',
+               pMeasRpt->rpt.basic.map.radar ? 'X' : ' ');
+        PRINTM(INFO, "Meas: Rpt:  bas: unidSig[%c] ofdm[%c] bss[%c]\n",
+               pMeasRpt->rpt.basic.map.unidentifiedSig ? 'X' : ' ',
+               pMeasRpt->rpt.basic.map.OFDM_Preamble ? 'X' : ' ',
+               pMeasRpt->rpt.basic.map.BSS ? 'X' : ' ');
+        break;
+#if WLAN_MEAS_EXTRA_11H_TYPES
+        /* Not supported in firmware */
+    case WLAN_MEAS_CCA:
+        PRINTM(INFO, "Meas: Rpt: chan: %u\n", pMeasRpt->rpt.cca.channel);
+        PRINTM(INFO, "Meas: Rpt: strt: %llu\n",
+               wlan_le64_to_cpu(pMeasRpt->rpt.cca.startTime));
+        PRINTM(INFO, "Meas: Rpt:  dur: %u\n",
+               wlan_le16_to_cpu(pMeasRpt->rpt.cca.duration));
+        PRINTM(INFO, "Meas: Rpt:  cca: busy fraction = %u\n",
+               pMeasRpt->rpt.cca.busyFraction);
+        break;
+    case WLAN_MEAS_RPI:
+        PRINTM(INFO, "Meas: Rpt: chan: %u\n", pMeasRpt->rpt.rpi.channel);
+        PRINTM(INFO, "Meas: Rpt: strt: %llu\n",
+               wlan_le64_to_cpu(pMeasRpt->rpt.rpi.startTime));
+        PRINTM(INFO, "Meas: Rpt:  dur: %u\n",
+               wlan_le16_to_cpu(pMeasRpt->rpt.rpi.duration));
+        PRINTM(INFO, "Meas: Rpt:  rpi: 0:%u, 1:%u, 2:%u, 3:%u\n",
+               pMeasRpt->rpt.rpi.density[0],
+               pMeasRpt->rpt.rpi.density[1],
+               pMeasRpt->rpt.rpi.density[2], pMeasRpt->rpt.rpi.density[3]);
+        PRINTM(INFO, "Meas: Rpt:  rpi: 4:%u, 5:%u, 6:%u, 7:%u\n",
+               pMeasRpt->rpt.rpi.density[4],
+               pMeasRpt->rpt.rpi.density[5],
+               pMeasRpt->rpt.rpi.density[6], pMeasRpt->rpt.rpi.density[7]);
+        break;
+#endif
+#if WLAN_MEAS_EXTRA_11K_TYPES
+        /* Future 11k measurement addditions */
+    case WLAN_MEAS_CHAN_LOAD:
+    case WLAN_MEAS_NOISE_HIST:
+    case WLAN_MEAS_BEACON:
+    case WLAN_MEAS_FRAME:
+    case WLAN_MEAS_HIDDEN_NODE:
+    case WLAN_MEAS_MEDIUM_SENS_HIST:
+    case WLAN_MEAS_STA_STATS:
+#endif
+    default:
+        PRINTM(INFO, "Meas: Rpt: <unhandled>\n");
+        break;
+    }
+
+    PRINTM(INFO, "Meas: Rpt: ------------------------------\n");
+}
+
+/**
+*** wlan_meas_cmdresp_get_report
+**
+**  @brief Retrieve a measurement report from the firmware
+** 
+**  Callback from command processing when a measurement report is received
+**    from the firmware.  Perform the following when a report is received:
+**
+**   -# Debug display the report if compiled with the appropriate flags
+**   -# If we are pending on a specific measurement report token, and it 
+**      matches the received report's token, store the report and wake up
+**      any pending threads
+**
+**  @param priv Private driver information structure
+**  @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+**              passing a HostCmd_DS_MEASUREMENT_REPORT structure.    
+**
+**  @return     WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+*/
+static int
+wlan_meas_cmdresp_get_report(wlan_private * priv,
+                             const HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    const HostCmd_DS_MEASUREMENT_REPORT *pMeasRpt = &resp->params.meas_rpt;
+
+    ENTER();
+
+    PRINTM(INFO, "Meas: Rpt: %#x-%u, Seq=%u, Ret=%u\n",
+           resp->Command, resp->Size, resp->SeqNum, resp->Result);
+
+    /* 
+     ** Debug display the measurement report
+     */
+    wlan_meas_dump_meas_rpt(pMeasRpt);
+
+    /*
+     ** Check if we are pending on a measurement report and it matches 
+     **  the dialog token of the received report:
+     */
+    if (Adapter->stateMeas.meas_rpt_pend_on
+        && Adapter->stateMeas.meas_rpt_pend_on == pMeasRpt->dialogToken) {
+        PRINTM(INFO, "Meas: Rpt: RCV'd Pend on meas #%d\n",
+               Adapter->stateMeas.meas_rpt_pend_on);
+
+        /*
+         ** Clear the pending report indicator
+         */
+        Adapter->stateMeas.meas_rpt_pend_on = 0;
+
+        /*
+         ** Copy the received report into the measurement state for retrieval
+         */
+        memcpy(&Adapter->stateMeas.meas_rpt_returned, pMeasRpt,
+               sizeof(Adapter->stateMeas.meas_rpt_returned));
+
+        /*
+         ** Wake up any threads pending on the wait queue
+         */
+        wake_up_interruptible(&Adapter->stateMeas.meas_rpt_waitQ);
+    }
+
+    LEAVE();
+
+    return 0;
+}
+
+/**
+*** wlan_meas_cmd_request
+**
+**  @brief Prepare CMD_MEASURMENT_REPORT firmware command
+**
+**  @param priv     Private driver information structure
+**  @param pCmdPtr  Output parameter: Pointer to the command being prepared 
+**                  for the firmware
+**  @param pInfoBuf HostCmd_DS_MEASUREMENT_REQUEST passed as void data block
+**
+**  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+*/
+static int
+wlan_meas_cmd_request(wlan_private * priv,
+                      HostCmd_DS_COMMAND * pCmdPtr, const void *pInfoBuf)
+{
+    const HostCmd_DS_MEASUREMENT_REQUEST *pMeasReq = pInfoBuf;
+
+    ENTER();
+
+    pCmdPtr->Command = HostCmd_CMD_MEASUREMENT_REQUEST;
+    pCmdPtr->Size = sizeof(HostCmd_DS_MEASUREMENT_REQUEST) + S_DS_GEN;
+
+    memcpy(&pCmdPtr->params.meas_req, pMeasReq,
+           sizeof(pCmdPtr->params.meas_req));
+
+    PRINTM(INFO, "Meas: Req: %#x-%u, Seq=%u, Ret=%u\n",
+           pCmdPtr->Command, pCmdPtr->Size, pCmdPtr->SeqNum, pCmdPtr->Result);
+
+    wlan_meas_dump_meas_req(pMeasReq);
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+*** wlan_meas_cmd_get_report
+**
+**  @brief  Retrieve a measurement report from the firmware
+**
+**  The firmware will send a EVENT_MEAS_REPORT_RDY event when it 
+**    completes or receives a measurement report.  The event response
+**    handler will then start a HostCmd_CMD_MEASUREMENT_REPORT firmware command
+**    which gets completed for transmission to the firmware in this routine.
+**
+**  @param priv    Private driver information structure
+**  @param pCmdPtr Output parameter: Pointer to the command being prepared 
+**                 for the firmware
+**
+**  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+*/
+static int
+wlan_meas_cmd_get_report(wlan_private * priv, HostCmd_DS_COMMAND * pCmdPtr)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    pCmdPtr->Command = HostCmd_CMD_MEASUREMENT_REPORT;
+    pCmdPtr->Size = sizeof(HostCmd_DS_MEASUREMENT_REPORT) + S_DS_GEN;
+
+    memset(&pCmdPtr->params.meas_rpt, 0x00, sizeof(pCmdPtr->params.meas_rpt));
+
+    /*
+     ** Set the meas_rpt.macAddr to our mac address to get a meas report,
+     **   setting the mac to another STA address instructs the firmware
+     **   to transmit this measurement report frame instead
+     */
+    memcpy(pCmdPtr->params.meas_rpt.macAddr, Adapter->CurrentAddr,
+           sizeof(pCmdPtr->params.meas_rpt.macAddr));
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+*** wlan_meas_init
+**
+**  @brief Initialize any needed structures for the measurement code
+**
+**  @param priv  Private driver information structure
+**
+**  @return      void
+*/
+void
+wlan_meas_init(wlan_private * priv)
+{
+    init_waitqueue_head(&priv->adapter->stateMeas.meas_rpt_waitQ);
+}
+
+/** 
+*** wlan_meas_util_send_req
+** 
+**  @brief Send the input measurement request to the firmware.
+**
+**  If the dialog token in the measurement request is set to 0, the function
+**    will use an local static auto-incremented token in the measurement
+**    request.  This ensures the dialog token is always set.
+**
+**  If wait_for_resp_timeout is set, the function will block its return on 
+**     a timeout or returned measurement report that matches the request's
+**     dialog token. 
+**
+**  @param priv                  Private driver information structure
+**  @param pMeasReq              Pointer to the measurement request to send
+**  @param wait_for_resp_timeout Timeout value of the measurement request
+**                               in ms.
+**  @param pMeasRpt              Output parameter: Pointer for the resulting
+**                               measurement report
+**
+**  @return
+**    - 0 for success
+**    - -ETIMEDOUT if the measurement report does not return before
+**      the timeout expires
+**    - Error return from wlan_prepare_cmd routine otherwise
+*/
+int
+wlan_meas_util_send_req(wlan_private * priv,
+                        HostCmd_DS_MEASUREMENT_REQUEST * pMeasReq,
+                        int wait_for_resp_timeout,
+                        HostCmd_DS_MEASUREMENT_REPORT * pMeasRpt)
+{
+    static u8 autoDialogTok = 0;
+    wlan_meas_state_t *pMeasState = &priv->adapter->stateMeas;
+    int ret;
+    uint calcTimeout;
+
+    ENTER();
+
+    /*
+     **  If dialogTok was set to 0 or not provided, autoset
+     */
+    pMeasReq->dialogToken = (pMeasReq->dialogToken ?
+                             pMeasReq->dialogToken : ++autoDialogTok);
+
+    /*
+     ** Check for rollover of the dialog token.  Avoid using 0 as a token.
+     */
+    pMeasReq->dialogToken = (pMeasReq->dialogToken ?
+                             pMeasReq->dialogToken : 1);
+
+    /*
+     ** If the request is to pend waiting for the result, set the dialog token
+     **   of this measurement request in the state structure.  The measurement
+     **   report handling routines can then check the incoming measurement
+     **   reports for a match with this dialog token.  
+     */
+    if (wait_for_resp_timeout) {
+        pMeasState->meas_rpt_pend_on = pMeasReq->dialogToken;
+        PRINTM(INFO, "Meas: Req: START Pend on meas #%d\n",
+               pMeasReq->dialogToken);
+    }
+
+    /*
+     ** Send the measurement request to the firmware
+     */
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REQUEST,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, 0, (void *) pMeasReq);
+
+    /*
+     ** If the measurement request was sent successfully, and the function
+     **   must wait for the report, suspend execution until the meas_rpt_pend_on
+     **   variable in the state structure has been reset to 0 by the report
+     **   handling routines.
+     */
+    if (ret == 0 && wait_for_resp_timeout) {
+        /* Add ~25% overhead to the timeout for firmware overhead */
+        calcTimeout = wait_for_resp_timeout + (wait_for_resp_timeout >> 2);
+
+        PRINTM(INFO, "Meas: Req: TIMEOUT set to %d ms\n", calcTimeout);
+
+        /* 10 ticks extra for the driver overhead - helps with small meas */
+        calcTimeout = (calcTimeout * HZ) / 1000 + 10;
+
+        PRINTM(INFO, "Meas: Req: TIMEOUT set to %d ticks\n", calcTimeout);
+
+        os_wait_interruptible_timeout(pMeasState->meas_rpt_waitQ,
+                                      pMeasState->meas_rpt_pend_on == 0,
+                                      calcTimeout);
+
+        if (pMeasState->meas_rpt_pend_on) {
+            PRINTM(INFO, "Meas: Req: TIMEOUT Pend on meas #%d\n",
+                   pMeasReq->dialogToken);
+            ret = -ETIMEDOUT;
+        } else {
+            PRINTM(INFO, "Meas: Req: DONE Pend on meas #%d\n",
+                   pMeasReq->dialogToken);
+            memcpy(pMeasRpt, &pMeasState->meas_rpt_returned,
+                   sizeof(HostCmd_DS_MEASUREMENT_REPORT));
+        }
+    }
+
+    /*
+     ** The measurement request failed or we are not waiting for a response.
+     **   In either case, the rpt_pend_on variable should be zero.
+     */
+    pMeasState->meas_rpt_pend_on = 0;
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+*** wlan_meas_cmd_process
+**
+**  @brief  Prepare the HostCmd_DS_Command structure for a measurement command.
+**
+**  Use the Command field to determine if the command being set up is for
+**     11h and call one of the local command handlers accordingly for:
+**
+**        - HostCmd_CMD_MEASUREMENT_REQUEST
+**        - HostCmd_CMD_MEASUREMENT_REPORT
+**
+**  @param priv     Private driver information structure
+**  @param pCmdPtr  Output parameter: Pointer to the command being prepared 
+**                  for the firmware
+**  @param pInfoBuf Void buffer passthrough with data necessary for a
+**                  specific command type
+**
+**  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+**
+**  @sa wlan_meas_cmd_request
+**  @sa wlan_meas_cmd_get_report
+*/
+int
+wlan_meas_cmd_process(wlan_private * priv,
+                      HostCmd_DS_COMMAND * pCmdPtr, const void *pInfoBuf)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    switch (pCmdPtr->Command) {
+    case HostCmd_CMD_MEASUREMENT_REQUEST:
+        ret = wlan_meas_cmd_request(priv, pCmdPtr, pInfoBuf);
+        break;
+    case HostCmd_CMD_MEASUREMENT_REPORT:
+        ret = wlan_meas_cmd_get_report(priv, pCmdPtr);
+        break;
+    default:
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    pCmdPtr->Command = wlan_cpu_to_le16(pCmdPtr->Command);
+    pCmdPtr->Size = wlan_cpu_to_le16(pCmdPtr->Size);
+
+    return ret;
+}
+
+/**
+*** wlan_meas_cmdresp_process
+**
+**  @brief Handle the command response from the firmware for a measurement 
+**         command
+**
+**  Use the Command field to determine if the command response being
+**    is for meas.  Call the local command response handler accordingly for:
+**
+**        - HostCmd_CMD_802_MEASUREMENT_REQUEST
+**        - HostCmd_CMD_802_MEASUREMENT_REPORT
+**
+**  @param priv Private driver information structure
+**  @param resp HostCmd_DS_COMMAND struct returned from the firmware command
+**
+**  @return     WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+*/
+int
+wlan_meas_cmdresp_process(wlan_private * priv,
+                          const HostCmd_DS_COMMAND * resp)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    switch (resp->Command) {
+    case HostCmd_CMD_MEASUREMENT_REQUEST:
+        PRINTM(INFO, "Meas: Req Resp: Sz=%u, Seq=%u, Ret=%u\n",
+               resp->Size, resp->SeqNum, resp->Result);
+
+        break;
+    case HostCmd_CMD_MEASUREMENT_REPORT:
+        ret = wlan_meas_cmdresp_get_report(priv, resp);
+        break;
+    default:
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    return ret;
+}
+
+/**
+*** wlan_meas_ioctl_send_req
+**
+**  @brief Send a measurment request to the firmware from the application
+**
+**  Process an IOCTL from the application for a measurement request.  The
+**    application thread will be blocked while the measurement completes or
+**    times out.
+**
+**  If the measurement is a success, the measurement report will be copied
+**    back to the user space.
+**
+**  @param priv Private driver information structure
+**  @param wrq  Input/Output parameter: OS IOCTL passed structure containing:
+**                 - HostCmd_DS_MEASUREMENT_REQUEST on input
+**                 - HostCmd_DS_MEASUREMENT_REQUEST on output 
+**
+**  @return
+**    - 0 for success
+**    - -EFAULT if memory copy from user space failes
+**    - Error return from wlan_meas_util_send_req routine otherwise
+*/
+int
+wlan_meas_ioctl_send_req(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_MEASUREMENT_REQUEST measReq;
+    HostCmd_DS_MEASUREMENT_REPORT measRpt;
+    int wait_for_resp_timeout = 0;
+    int ret = 0;
+    u8 zeroMac[] = { 0, 0, 0, 0, 0, 0 };
+
+    ENTER();
+
+    memset(&measReq, 0x00, sizeof(measReq));
+    memset(&measRpt, 0x00, sizeof(measRpt));
+
+    if (copy_from_user(&measReq, wrq->u.data.pointer, sizeof(measReq)) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "Meas: ioctl_send_req: copy from user failed\n");
+        return -EFAULT;
+    }
+
+    /*
+     ** If measDuration was set to 0, set to default
+     */
+    if (measReq.req.basic.duration == 0) {
+        measReq.req.basic.duration = WLAN_MEAS_DEFAULT_MEAS_DURATION;
+    }
+    measReq.req.basic.duration = wlan_cpu_to_le16(measReq.req.basic.duration);
+
+    /*
+     ** Provide a timeout time for the measurement based on the duration.
+     */
+    wait_for_resp_timeout = measReq.req.basic.duration;
+
+    /*
+     ** If the measChannel was set to 0 or not provided, re-sync the 
+     **   Channel field in Adapter struct for use in the request
+     */
+    if (measReq.req.basic.channel == 0) {
+        wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+                         HostCmd_OPT_802_11_RF_CHANNEL_GET,
+                         HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+        measReq.req.basic.channel
+            = Adapter->CurBssParams.BSSDescriptor.Channel;
+    }
+
+    if (memcmp(measReq.macAddr, zeroMac, sizeof(zeroMac)) == 0) {
+        /*
+         ** Set the measReq.macAddr to our mac address if it was not provided
+         */
+        memcpy(measReq.macAddr, Adapter->CurrentAddr,
+               sizeof(measReq.macAddr));
+    }
+
+    /*
+     ** Finish setup of the measurement request and send to the firmware
+     */
+    ret = wlan_meas_util_send_req(priv, &measReq,
+                                  wait_for_resp_timeout, &measRpt);
+
+    if (ret == 0) {
+        /*
+         ** The request was sent successfully and the report received and stored
+         **   in the measurement state before execution returned from
+         **   the wlan_send_meas_req function.
+         */
+        wrq->u.data.length = sizeof(measRpt);
+        if (copy_to_user(wrq->u.data.pointer, &measRpt, wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_meas.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_meas.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_meas.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_meas.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,93 @@
+/**
+ *  @file wlan_meas.h
+ *
+ *  @brief Interface for the measurement module implemented in wlan_meas.c
+ *
+ *  Driver interface functions and type declarations for the measurement module
+ *    implemented in wlan_meas.c
+ *  
+ *  @sa wlan_meas.c
+ *
+ *  (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+
+/*****************************************************************************/
+/*  Change Log:
+** 
+**      9/30/05: Initial revision            
+**
+**
+*/
+/*****************************************************************************/
+
+#ifndef _WLAN_MEAS_H
+#define _WLAN_MEAS_H
+
+#include  "wlan_fw.h"
+
+#ifdef __KERNEL__               /* state is only used in the driver, exempt from app code */
+/**
+*** @brief Driver measurement state held in wlan_priv structure
+**  
+**  Used to record a measurement request that the driver is pending on 
+**    the result (received measurement report).
+*/
+typedef struct
+{
+    /**
+    *** Dialog token of a pending measurement request/report.  Used to
+    ***   block execution while waiting for the specific dialog token
+    **/
+    u8 meas_rpt_pend_on;
+
+    /**
+    *** Measurement report received from the firmware that we were pending on
+    **/
+    HostCmd_DS_MEASUREMENT_REPORT meas_rpt_returned;
+
+    /**
+    *** OS wait queue used to suspend the requesting thread
+    **/
+    wait_queue_head_t meas_rpt_waitQ;
+
+} wlan_meas_state_t;
+
+/* Initialize the measurement code on startup */
+extern void wlan_meas_init(wlan_private * priv);
+
+/* Send a given measurement request to the firmware, report back the result */
+extern int
+wlan_meas_util_send_req(wlan_private * priv,
+                        HostCmd_DS_MEASUREMENT_REQUEST * pMeasReq,
+                        int wait_for_resp_timeout,
+                        HostCmd_DS_MEASUREMENT_REPORT * pMeasRpt);
+
+/* Setup a measurement command before it is sent to the firmware */
+extern int wlan_meas_cmd_process(wlan_private * priv,
+                                 HostCmd_DS_COMMAND * pCmdPtr,
+                                 const void *pInfoBuf);
+
+/* Handle a given measurement command response from the firmware */
+extern int wlan_meas_cmdresp_process(wlan_private * priv,
+                                     const HostCmd_DS_COMMAND * resp);
+
+/* Process an application ioctl for sending a measurement request */
+extern int wlan_meas_ioctl_send_req(wlan_private * priv, struct iwreq *wrq);
+
+#endif /* WLANCONFIG */
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_proc.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_proc.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_proc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_proc.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,223 @@
+/** @file wlan_proc.c
+  * @brief This file contains functions for proc fin proc file.
+  * 
+  * (c) Copyright © 2003-2006, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/04/05: Add Doxygen format comments
+	01/05/06: Add kernel 2.6.x support	
+	
+********************************************************/
+#include 	"wlan_headers.h"
+
+#ifdef CONFIG_PROC_FS
+/********************************************************
+		Local Variables
+********************************************************/
+
+static char *szModes[] = {
+    "Ad-hoc",
+    "Managed",
+    "Auto",
+    "Unknown"
+};
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief proc read function
+ *
+ *  @param page	   pointer to buffer
+ *  @param start   read data starting position
+ *  @param offset  offset
+ *  @param count   counter 
+ *  @param eof     end of file flag
+ *  @param data    data to output
+ *  @return 	   number of output data
+ */
+static int
+wlan_proc_read(char *page, char **start, off_t offset,
+               int count, int *eof, void *data)
+{
+    int i;
+    char *p = page;
+    struct net_device *netdev = data;
+    struct dev_mc_list *mcptr = netdev->mc_list;
+    char fmt[64];
+    wlan_private *priv = netdev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+
+    if (offset != 0) {
+        *eof = 1;
+        goto exit;
+    }
+
+    get_version(Adapter, fmt, sizeof(fmt) - 1);
+
+    p += sprintf(p, "driver_name = " "\"wlan\"\n");
+    p += sprintf(p, "driver_version = %s", fmt);
+    p += sprintf(p, "\nInterfaceName=\"%s\"\n", netdev->name);
+    p += sprintf(p, "Mode=\"%s\"\n", szModes[Adapter->InfrastructureMode]);
+    p += sprintf(p, "State=\"%s\"\n",
+                 ((Adapter->MediaConnectStatus ==
+                   WlanMediaStateDisconnected) ? "Disconnected" :
+                  "Connected"));
+    p += sprintf(p, "MACAddress=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+                 netdev->dev_addr[0], netdev->dev_addr[1],
+                 netdev->dev_addr[2], netdev->dev_addr[3],
+                 netdev->dev_addr[4], netdev->dev_addr[5]);
+
+    p += sprintf(p, "MCCount=\"%d\"\n", netdev->mc_count);
+    p += sprintf(p, "ESSID=\"%s\"\n",
+                 (u8 *) Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
+    p += sprintf(p, "Channel=\"%d\"\n",
+                 Adapter->CurBssParams.BSSDescriptor.Channel);
+    p += sprintf(p, "region_code = \"%02x\"\n", (u32) Adapter->RegionCode);
+
+    /*
+     * Put out the multicast list 
+     */
+    for (i = 0; i < netdev->mc_count; i++) {
+        p += sprintf(p,
+                     "MCAddr[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+                     i,
+                     mcptr->dmi_addr[0], mcptr->dmi_addr[1],
+                     mcptr->dmi_addr[2], mcptr->dmi_addr[3],
+                     mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
+
+        mcptr = mcptr->next;
+    }
+    p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+    p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+    p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+    p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+    p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+    p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+    p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+    p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+    p += sprintf(p, "carrier %s\n",
+                 ((netif_carrier_ok(priv->wlan_dev.netdev)) ? "on" : "off"));
+    p += sprintf(p, "tx queue %s\n",
+                 ((netif_queue_stopped(priv->wlan_dev.netdev)) ? "stopped" :
+                  "started"));
+
+    spin_lock_irqsave(&Adapter->QueueSpinLock, flags);
+    if (Adapter->CurCmd) {
+        HostCmd_DS_COMMAND *CmdPtr =
+            (HostCmd_DS_COMMAND *) Adapter->CurCmd->BufVirtualAddr;
+        p += sprintf(p, "CurCmd ID = 0x%x, 0x%x\n",
+                     wlan_cpu_to_le16(CmdPtr->Command),
+                     wlan_cpu_to_le16(*(u16 *) ((u8 *) CmdPtr + S_DS_GEN)));
+    } else {
+        p += sprintf(p, "CurCmd NULL\n");
+    }
+    spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags);
+
+  exit:
+    return (p - page);
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief create wlan proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @param dev     pointer net_device
+ *  @return 	   N/A
+ */
+void
+wlan_proc_entry(wlan_private * priv, struct net_device *dev)
+{
+
+    struct proc_dir_entry *r;
+
+    PRINTM(INFO, "Creating Proc Interface\n");
+    if (!priv->proc_mwlan) {
+        priv->proc_mwlan = proc_mkdir("mwlan", init_net.proc_net);
+        if (!priv->proc_mwlan)
+            return;
+        priv->proc_entry = proc_mkdir(dev->name, priv->proc_mwlan);
+
+        if (priv->proc_entry) {
+            r = create_proc_read_entry("info", 0, priv->proc_entry,
+                                       wlan_proc_read, dev);
+        }
+    }
+}
+
+/** 
+ *  @brief remove proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @return 	   N/A
+ */
+void
+wlan_proc_remove(wlan_private * priv)
+{
+    if (priv->proc_mwlan) {
+        if (priv->proc_entry) {
+            remove_proc_entry("info", priv->proc_entry);
+        }
+        remove_proc_entry(priv->wlan_dev.netdev->name, priv->proc_mwlan);
+        remove_proc_entry("mwlan", init_net.proc_net);
+    }
+}
+
+/** 
+ *  @brief convert string to number
+ *
+ *  @param s   	   pointer to numbered string
+ *  @return 	   converted number from string s
+ */
+int
+string_to_number(char *s)
+{
+    int r = 0;
+    int base = 0;
+
+    if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0))
+        base = 16;
+    else
+        base = 10;
+    if (base == 16)
+        s += 2;
+    for (s = s; *s != 0; s++) {
+        if ((*s >= 48) && (*s <= 57))
+            r = (r * base) + (*s - 48);
+        else if ((*s >= 65) && (*s <= 70))
+            r = (r * base) + (*s - 55);
+        else if ((*s >= 97) && (*s <= 102))
+            r = (r * base) + (*s - 87);
+        else
+            break;
+    }
+
+    return r;
+}
+
+#endif
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_rx.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_rx.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_rx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_rx.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,315 @@
+/** @file wlan_rx.c
+  * @brief This file contains the handling of RX in wlan
+  * driver.
+  * 
+  * (c) Copyright © 2003-2006, Marvell International Ltd.  
+  *   
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	09/28/05: Add Doxygen format comments
+	12/09/05: ADD Sliding window SNR/NF Average Calculation support
+	
+********************************************************/
+
+#include	"wlan_headers.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+typedef struct
+{
+    /** Ethernet header destination address */
+    u8 dest_addr[ETH_ALEN];
+    /** Ethernet header source address */
+    u8 src_addr[ETH_ALEN];
+    /** Ethernet header length */
+    u16 h803_len;
+
+} __ATTRIB_PACK__ Eth803Hdr_t;
+
+typedef struct
+{
+    /** LLC DSAP */
+    u8 llc_dsap;
+    /** LLC SSAP */
+    u8 llc_ssap;
+    /** LLC CTRL */
+    u8 llc_ctrl;
+    /** SNAP OUI */
+    u8 snap_oui[3];
+    /** SNAP type */
+    u16 snap_type;
+
+} __ATTRIB_PACK__ Rfc1042Hdr_t;
+
+typedef struct
+{
+    /** Etherner header */
+    Eth803Hdr_t eth803_hdr;
+    /** RFC 1042 header */
+    Rfc1042Hdr_t rfc1042_hdr;
+
+} __ATTRIB_PACK__ RxPacketHdr_t;
+
+typedef struct
+{
+    /** Ethernet II header destination address */
+    u8 dest_addr[ETH_ALEN];
+    /** Ethernet II header source address */
+    u8 src_addr[ETH_ALEN];
+    /** Ethernet II header length */
+    u16 ethertype;
+
+} __ATTRIB_PACK__ EthII_Hdr_t;
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function computes the AvgSNR .
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   AvgSNR
+ */
+static u8
+wlan_get_data_avg_snr(wlan_private * priv)
+{
+    u8 i;
+    u16 temp = 0;
+    wlan_adapter *Adapter = priv->adapter;
+    if (Adapter->numSNRNF == 0)
+        return 0;
+    for (i = 0; i < Adapter->numSNRNF; i++)
+        temp += Adapter->rawSNR[i];
+    return (u8) (temp / Adapter->numSNRNF);
+
+}
+
+/** 
+ *  @brief This function computes the AvgNF
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   AvgNF
+ */
+static u8
+wlan_get_data_avg_nf(wlan_private * priv)
+{
+    u8 i;
+    u16 temp = 0;
+    wlan_adapter *Adapter = priv->adapter;
+    if (Adapter->numSNRNF == 0)
+        return 0;
+    for (i = 0; i < Adapter->numSNRNF; i++)
+        temp += Adapter->rawNF[i];
+    return (u8) (temp / Adapter->numSNRNF);
+
+}
+
+/** 
+ *  @brief This function save the raw SNR/NF to our internel buffer
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param pRxPD   A pointer to RxPD structure of received packet
+ *  @return 	   n/a
+ */
+static void
+wlan_save_data_snr_nf(wlan_private * priv, RxPD * pRxPD)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    if (Adapter->numSNRNF < Adapter->data_avg_factor)
+        Adapter->numSNRNF++;
+    Adapter->rawSNR[Adapter->nextSNRNF] = pRxPD->SNR;
+    Adapter->rawNF[Adapter->nextSNRNF] = pRxPD->NF;
+    Adapter->nextSNRNF++;
+    if (Adapter->nextSNRNF >= Adapter->data_avg_factor)
+        Adapter->nextSNRNF = 0;
+    return;
+}
+
+/** 
+ *  @brief This function computes the RSSI in received packet.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param pRxPD   A pointer to RxPD structure of received packet
+ *  @return 	   n/a
+ */
+static void
+wlan_compute_rssi(wlan_private * priv, RxPD * pRxPD)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "RxPD: SNR = %d, NF = %d\n", pRxPD->SNR, pRxPD->NF);
+
+    Adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = pRxPD->SNR;
+    Adapter->NF[TYPE_RXPD][TYPE_NOAVG] = pRxPD->NF;
+    wlan_save_data_snr_nf(priv, pRxPD);
+
+    Adapter->RxPDAge = os_time_get();
+    Adapter->RxPDRate = pRxPD->RxRate;
+
+    Adapter->SNR[TYPE_RXPD][TYPE_AVG] =
+        wlan_get_data_avg_snr(priv) * AVG_SCALE;
+    Adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_get_data_avg_nf(priv) * AVG_SCALE;
+    PRINTM(INFO, "SNR-avg = %d, NF-avg = %d\n",
+           Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+           Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+    Adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+                 Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+
+    Adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+        CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                 Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+    LEAVE();
+}
+
+/********************************************************
+		Global functions
+********************************************************/
+
+/**
+ *  @brief This function processes received packet and forwards it
+ *  to kernel/upper layer
+ *  
+ *  @param priv    A pointer to wlan_private
+ *  @param skb     A pointer to skb which includes the received packet
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_process_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    RxPacketHdr_t *pRxPkt;
+    RxPD *pRxPD;
+
+    int hdrChop;
+    EthII_Hdr_t *pEthHdr;
+    u32 u32SkbLen = skb->len;
+
+    const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+    ENTER();
+
+    pRxPD = (RxPD *) skb->data;
+    pRxPkt = (RxPacketHdr_t *) ((u8 *) pRxPD + pRxPD->PktOffset);
+
+    DBG_HEXDUMP(DAT_D, "Rx", skb->data, MIN(skb->len, MAX_DATA_DUMP_LEN));
+
+    endian_convert_RxPD(pRxPD);
+
+#define RX_PKT_TYPE_DEBUG  0xEF
+#define DBG_TYPE_SMALL  2
+#define SIZE_OF_DBG_STRUCT 4
+    if (pRxPD->RxPacketType == RX_PKT_TYPE_DEBUG) {
+        u8 dbgType;
+        dbgType = *(u8 *) & pRxPkt->eth803_hdr;
+        if (dbgType == DBG_TYPE_SMALL) {
+            PRINTM(FW_D, "\n");
+            DBG_HEXDUMP(FW_D, "FWDBG",
+                        (char *) ((u8 *) & pRxPkt->eth803_hdr +
+                                  SIZE_OF_DBG_STRUCT), pRxPD->PktLen);
+            PRINTM(FW_D, "FWDBG::\n");
+        }
+        kfree_skb(skb);
+        goto done;
+    }
+
+    if (skb->len < (ETH_HLEN + 8 + pRxPD->PktOffset)) {
+        PRINTM(ERROR, "RX Error: FRAME RECEIVED WITH BAD LENGTH\n");
+        priv->stats.rx_length_errors++;
+        ret = WLAN_STATUS_SUCCESS;
+        kfree_skb(skb);
+        goto done;
+    }
+
+    PRINTM(INFO, "RX Data: skb->len - pRxPD->PktOffset = %d - %d = %d\n",
+           skb->len, pRxPD->PktOffset, skb->len - pRxPD->PktOffset);
+
+    HEXDUMP("RX Data: Dest", pRxPkt->eth803_hdr.dest_addr,
+            sizeof(pRxPkt->eth803_hdr.dest_addr));
+    HEXDUMP("RX Data: Src", pRxPkt->eth803_hdr.src_addr,
+            sizeof(pRxPkt->eth803_hdr.src_addr));
+
+    if (memcmp(&pRxPkt->rfc1042_hdr,
+               rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+        /* 
+         *  Replace the 803 header and rfc1042 header (llc/snap) with an 
+         *    EthernetII header, keep the src/dst and snap_type (ethertype)
+         *
+         *  The firmware only passes up SNAP frames converting
+         *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+         *
+         *  To create the Ethernet II, just move the src, dst address right
+         *    before the snap_type.
+         */
+        pEthHdr = (EthII_Hdr_t *)
+            ((u8 *) & pRxPkt->eth803_hdr
+             + sizeof(pRxPkt->eth803_hdr) + sizeof(pRxPkt->rfc1042_hdr)
+             - sizeof(pRxPkt->eth803_hdr.dest_addr)
+             - sizeof(pRxPkt->eth803_hdr.src_addr)
+             - sizeof(pRxPkt->rfc1042_hdr.snap_type));
+
+        memcpy(pEthHdr->src_addr, pRxPkt->eth803_hdr.src_addr,
+               sizeof(pEthHdr->src_addr));
+        memcpy(pEthHdr->dest_addr, pRxPkt->eth803_hdr.dest_addr,
+               sizeof(pEthHdr->dest_addr));
+
+        /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
+         *   that was removed 
+         */
+        hdrChop = (u8 *) pEthHdr - (u8 *) pRxPD;
+    } else {
+        HEXDUMP("RX Data: LLC/SNAP",
+                (u8 *) & pRxPkt->rfc1042_hdr, sizeof(pRxPkt->rfc1042_hdr));
+
+        /* Chop off the RxPD */
+        hdrChop = (u8 *) & pRxPkt->eth803_hdr - (u8 *) pRxPD;
+    }
+
+    /* Chop off the leading header bytes so the skb points to the start of 
+     *   either the reconstructed EthII frame or the 802.2/llc/snap frame
+     */
+    skb_pull(skb, hdrChop);
+
+    u32SkbLen = skb->len;
+    wlan_compute_rssi(priv, pRxPD);
+
+    if (os_upload_rx_packet(priv, skb)) {
+        PRINTM(ERROR, "RX Error: os_upload_rx_packet" " returns failure\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    priv->stats.rx_bytes += u32SkbLen;
+    priv->stats.rx_packets++;
+
+    PRINTM(DATA, "Data => kernel\n");
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    LEAVE();
+
+    return (ret);
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_scan.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_scan.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_scan.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_scan.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,3542 @@
+/** @file wlan_scan.c
+ *
+ *  @brief Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ *  IOCTL handlers as well as command preperation and response routines
+ *   for sending scan commands to the firmware.
+ *
+ *  (c) Copyright © 2003-2007, Marvell International Ltd.  
+ *   
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change Log:
+    01/11/06: Initial revision. New scan code, relocate related functions
+    01/19/06: Update specific scan routines to discard old results for adhoc
+    01/31/06: Add support for selectively enabling the FW Scan channel filter
+
+************************************************************/
+
+#include    "wlan_headers.h"
+
+/********************************************************
+    Local Constants
+********************************************************/
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
+                             + MRVDRV_MAX_SSID_LENGTH   \
+                             + IW_EV_UINT_LEN           \
+                             + IW_EV_FREQ_LEN           \
+                             + IW_EV_QUAL_LEN           \
+                             + MRVDRV_MAX_SSID_LENGTH   \
+                             + IW_EV_PARAM_LEN          \
+                             + 40)      /* 40 for WPAIE */
+
+//! Memory needed to store a max sized Channel List TLV for a firmware scan
+#define CHAN_TLV_MAX_SIZE  (sizeof(MrvlIEtypesHeader_t)                  \
+                            + (MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN     \
+                               * sizeof(ChanScanParamSet_t)))
+
+//! Memory needed to store a max number/size WildCard SSID TLV for a firmware scan
+#define WILDCARD_SSID_TLV_MAX_SIZE  \
+		(MRVDRV_MAX_SSID_LIST_LENGTH  * (sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + MRVDRV_MAX_SSID_LENGTH))
+
+//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config)        \
+                            + sizeof(MrvlIEtypes_NumProbes_t)   \
+                            + CHAN_TLV_MAX_SIZE                 \
+                            + WILDCARD_SSID_TLV_MAX_SIZE)
+
+//! The maximum number of channels the firmware can scan per command
+#define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
+
+/**
+ * @brief Number of channels to scan per firmware scan command issuance.
+ *
+ *  Number restricted to prevent hitting the limit on the amount of scan data
+ *  returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD   4
+
+//! Macro to enable/disable SSID checking before storing a scan table
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.Ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) TRUE
+#endif
+
+/********************************************************
+    Local Variables and Types
+********************************************************/
+
+/**
+ * @brief Interally used to send a configured scan cmd between driver routines
+ */
+typedef union
+{
+    wlan_scan_cmd_config config;        //!< Scan configuration (variable length)
+    u8 configAllocBuf[MAX_SCAN_CFG_ALLOC];      //!< Max allocated block
+} wlan_scan_cmd_config_tlv;
+
+/**
+ *  @brief Check if a scanned network compatible with the driver settings
+ *
+ *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
+ * enabled enabled  enabled   AES     mode   Privacy  WPA  WPA2  Compatible
+ *    0       0        0       0      NONE      0      0    0   yes No security
+ *    0       1        0       0       x        1x     1    x   yes WPA
+ *    0       0        1       0       x        1x     x    1   yes WPA2
+ *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
+ *
+ *    1       0        0       0      NONE      1      0    0   yes Static WEP
+ *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
+ *
+ *
+ *  @param Adapter A pointer to wlan_adapter
+ *  @param index   Index in ScanTable to check against current driver settings
+ *  @param mode    Network mode: Infrastructure or IBSS
+ *
+ *  @return        Index in ScanTable, or error code if negative
+ */
+static int
+wlan_is_network_compatible(wlan_adapter * Adapter, int index, int mode)
+{
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    pBSSDesc = &Adapter->ScanTable[index];
+
+    /* Don't check for compatibility if roaming */
+    if ((Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        && (Adapter->InfrastructureMode == Wlan802_11Infrastructure)
+        && (pBSSDesc->InfrastructureMode == Wlan802_11Infrastructure)) {
+        LEAVE();
+        return index;
+    }
+
+    if (Adapter->wps.SessionEnable == TRUE) {
+        PRINTM(INFO, "Return success directly in WPS period\n");
+        LEAVE();
+        return index;
+    }
+
+    if (pBSSDesc->InfrastructureMode == mode) {
+        if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+            && !Adapter->SecInfo.WPAEnabled
+            && !Adapter->SecInfo.WPA2Enabled
+            && ((!pBSSDesc->pWpaIE) ||
+                ((*(pBSSDesc->pWpaIE)).VendHdr.ElementId != WPA_IE))
+            && ((!pBSSDesc->pRsnIE) ||
+                ((*(pBSSDesc->pRsnIE)).IeeeHdr.ElementId != RSN_IE))
+            && !Adapter->AdhocAESEnabled &&
+            Adapter->SecInfo.EncryptionMode == CIPHER_NONE &&
+            !pBSSDesc->Privacy) {
+            /* no security */
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && !Adapter->AdhocAESEnabled && pBSSDesc->Privacy) {
+            /* static WEP enabled */
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && ((pBSSDesc->pWpaIE) &&
+                       ((*(pBSSDesc->pWpaIE)).VendHdr.ElementId == WPA_IE))
+                   && !Adapter->AdhocAESEnabled
+                   /* Privacy bit may NOT be set in some APs like LinkSys WRT54G
+                      && pBSSDesc->Privacy */
+            ) {
+            /* WPA enabled */
+            PRINTM(INFO,
+                   "wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
+                   "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+                   "privacy=%#x\n", index,
+                   (pBSSDesc->pWpaIE) ? (*(pBSSDesc->pWpaIE)).VendHdr.
+                   ElementId : 0,
+                   (pBSSDesc->pRsnIE) ? (*(pBSSDesc->pRsnIE)).IeeeHdr.
+                   ElementId : 0,
+                   (Adapter->SecInfo.WEPStatus ==
+                    Wlan802_11WEPEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
+                   Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && Adapter->SecInfo.WPA2Enabled
+                   && ((pBSSDesc->pRsnIE) &&
+                       ((*(pBSSDesc->pRsnIE)).IeeeHdr.ElementId == RSN_IE))
+                   && !Adapter->AdhocAESEnabled
+                   /* Privacy bit may NOT be set in some APs like LinkSys WRT54G
+                      && pBSSDesc->Privacy */
+            ) {
+            /* WPA2 enabled */
+            PRINTM(INFO,
+                   "wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+                   "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
+                   "privacy=%#x\n", index,
+                   (pBSSDesc->pWpaIE) ? (*(pBSSDesc->pWpaIE)).VendHdr.
+                   ElementId : 0,
+                   (pBSSDesc->pRsnIE) ? (*(pBSSDesc->pRsnIE)).IeeeHdr.
+                   ElementId : 0,
+                   (Adapter->SecInfo.WEPStatus ==
+                    Wlan802_11WEPEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
+                   (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
+                   Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && ((!pBSSDesc->pWpaIE) ||
+                       ((*(pBSSDesc->pWpaIE)).VendHdr.ElementId != WPA_IE))
+                   && ((!pBSSDesc->pRsnIE) ||
+                       ((*(pBSSDesc->pRsnIE)).IeeeHdr.ElementId != RSN_IE))
+                   && Adapter->AdhocAESEnabled &&
+                   Adapter->SecInfo.EncryptionMode == CIPHER_NONE &&
+                   pBSSDesc->Privacy) {
+            /* Ad-hoc AES enabled */
+            LEAVE();
+            return index;
+        } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled
+                   && !Adapter->SecInfo.WPAEnabled
+                   && !Adapter->SecInfo.WPA2Enabled
+                   && ((!pBSSDesc->pWpaIE) ||
+                       ((*(pBSSDesc->pWpaIE)).VendHdr.ElementId != WPA_IE))
+                   && ((!pBSSDesc->pRsnIE) ||
+                       ((*(pBSSDesc->pRsnIE)).IeeeHdr.ElementId != RSN_IE))
+                   && !Adapter->AdhocAESEnabled &&
+                   Adapter->SecInfo.EncryptionMode != CIPHER_NONE &&
+                   pBSSDesc->Privacy) {
+            /* dynamic WEP enabled */
+            PRINTM(INFO, "wlan_is_network_compatible() dynamic WEP: index=%d "
+                   "wpa_ie=%#x wpa2_ie=%#x EncMode=%#x privacy=%#x\n",
+                   index,
+                   (pBSSDesc->pWpaIE) ? (*(pBSSDesc->pWpaIE)).VendHdr.
+                   ElementId : 0,
+                   (pBSSDesc->pRsnIE) ? (*(pBSSDesc->pRsnIE)).IeeeHdr.
+                   ElementId : 0, Adapter->SecInfo.EncryptionMode,
+                   pBSSDesc->Privacy);
+            LEAVE();
+            return index;
+        }
+
+        /* security doesn't match */
+        PRINTM(INFO,
+               "wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+               "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
+               index,
+               (pBSSDesc->pWpaIE) ? (*(pBSSDesc->pWpaIE)).VendHdr.
+               ElementId : 0,
+               (pBSSDesc->pRsnIE) ? (*(pBSSDesc->pRsnIE)).IeeeHdr.
+               ElementId : 0,
+               (Adapter->SecInfo.WEPStatus ==
+                Wlan802_11WEPEnabled) ? "e" : "d",
+               (Adapter->SecInfo.WPAEnabled) ? "e" : "d",
+               (Adapter->SecInfo.WPA2Enabled) ? "e" : "d",
+               Adapter->SecInfo.EncryptionMode, pBSSDesc->Privacy);
+        LEAVE();
+        return -ECONNREFUSED;
+    }
+
+    /* mode doesn't match */
+    LEAVE();
+    return -ENETUNREACH;
+}
+
+/**
+ *  @brief This function validates a SSID as being able to be printed
+ *
+ *  @param pSsid   SSID structure to validate
+ *
+ *  @return        TRUE or FALSE
+ */
+static BOOLEAN
+ssid_valid(WLAN_802_11_SSID * pSsid)
+{
+    int ssidIdx;
+
+    for (ssidIdx = 0; ssidIdx < pSsid->SsidLength; ssidIdx++) {
+        if (!isprint(pSsid->Ssid[ssidIdx])) {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+/**
+ *  @brief Post process the scan table after a new scan command has completed
+ *
+ *  Inspect each entry of the scan table and try to find an entry that
+ *    matches our current associated/joined network from the scan.  If
+ *    one is found, update the stored copy of the BSSDescriptor for our
+ *    current network.
+ *
+ *  Debug dump the current scan table contents if compiled accordingly.
+ *
+ *  @param priv   A pointer to wlan_private structure
+ *
+ *  @return       void
+ */
+static void
+wlan_scan_process_results(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    int foundCurrent;
+
+    foundCurrent = FALSE;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        Adapter->CurBssParams.BSSDescriptor.pWpaIE = NULL;
+        Adapter->CurBssParams.BSSDescriptor.wpaOffset = 0;
+        Adapter->CurBssParams.BSSDescriptor.pRsnIE = NULL;
+        Adapter->CurBssParams.BSSDescriptor.rsnOffset = 0;
+        Adapter->CurBssParams.BSSDescriptor.pWpsIE = NULL;
+        Adapter->CurBssParams.BSSDescriptor.wpsOffset = 0;
+        Adapter->CurBssParams.BSSDescriptor.pBeaconBuf = NULL;
+        Adapter->CurBssParams.BSSDescriptor.beaconBufSize = 0;
+        Adapter->CurBssParams.BSSDescriptor.beaconBufSizeMax = 0;
+        i = wlan_find_ssid_in_list(Adapter,
+                                   &Adapter->CurBssParams.BSSDescriptor.Ssid,
+                                   Adapter->CurBssParams.BSSDescriptor.
+                                   MacAddress, Adapter->InfrastructureMode);
+
+        if (i >= 0) {
+            PRINTM(INFO, "Found current ssid/bssid in list @ index #%d\n", i);
+            /* Make a copy of current BSSID descriptor */
+            memcpy(&Adapter->CurBssParams.BSSDescriptor,
+                   &Adapter->ScanTable[i],
+                   sizeof(Adapter->CurBssParams.BSSDescriptor));
+        }
+    }
+
+    for (i = 0; i < Adapter->NumInScanTable; i++) {
+        PRINTM(INFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+               "RSSI[%03d], SSID[%s]\n",
+               i,
+               Adapter->ScanTable[i].MacAddress[0],
+               Adapter->ScanTable[i].MacAddress[1],
+               Adapter->ScanTable[i].MacAddress[2],
+               Adapter->ScanTable[i].MacAddress[3],
+               Adapter->ScanTable[i].MacAddress[4],
+               Adapter->ScanTable[i].MacAddress[5],
+               (s32) Adapter->ScanTable[i].Rssi,
+               Adapter->ScanTable[i].Ssid.Ssid);
+    }
+}
+
+/**
+ *  @brief Create a channel list for the driver to scan based on region info
+ *
+ *  Use the driver region/band information to construct a comprehensive list
+ *    of channels to scan.  This routine is used for any scan that is not
+ *    provided a specific channel list to scan.
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param scanChanList  Output parameter: Resulting channel list to scan
+ *  @param filteredScan  Flag indicating whether or not a BSSID or SSID filter
+ *                       is being sent in the command to firmware.  Used to 
+ *                       increase the number of channels sent in a scan
+ *                       command and to disable the firmware channel scan
+ *                       filter.
+ *
+ *  @return              void
+ */
+static void
+wlan_scan_create_channel_list(wlan_private * priv,
+                              ChanScanParamSet_t * scanChanList,
+                              BOOLEAN filteredScan)
+{
+
+    wlan_adapter *Adapter = priv->adapter;
+    REGION_CHANNEL *scanRegion;
+    CHANNEL_FREQ_POWER *cfp;
+    int rgnIdx;
+    int chanIdx;
+    int nextChan;
+    u8 scanType;
+
+    chanIdx = 0;
+
+    /* Set the default scan type to the user specified type, will later
+     *   be changed to passive on a per channel basis if restricted by
+     *   regulatory requirements (11d or 11h)
+     */
+    scanType = Adapter->ScanType;
+
+    for (rgnIdx = 0; rgnIdx < NELEMENTS(Adapter->region_channel); rgnIdx++) {
+        if (wlan_get_state_11d(priv) == ENABLE_11D &&
+            Adapter->MediaConnectStatus != WlanMediaStateConnected) {
+            /* Scan all the supported chan for the first scan */
+            if (!Adapter->universal_channel[rgnIdx].Valid)
+                continue;
+            scanRegion = &Adapter->universal_channel[rgnIdx];
+
+            /* clear the parsed_region_chan for the first scan */
+            memset(&Adapter->parsed_region_chan, 0x00,
+                   sizeof(Adapter->parsed_region_chan));
+        } else {
+            if (!Adapter->region_channel[rgnIdx].Valid)
+                continue;
+            scanRegion = &Adapter->region_channel[rgnIdx];
+        }
+
+        for (nextChan = 0;
+             nextChan < scanRegion->NrCFP; nextChan++, chanIdx++) {
+
+            cfp = scanRegion->CFP + nextChan;
+
+            if (wlan_get_state_11d(priv) == ENABLE_11D) {
+                scanType =
+                    wlan_get_scan_type_11d(cfp->Channel,
+                                           &Adapter->parsed_region_chan);
+            }
+
+            switch (scanRegion->Band) {
+            case BAND_A:
+                scanChanList[chanIdx].RadioType = HostCmd_SCAN_RADIO_TYPE_A;
+                if (wlan_11h_radar_detect_required(priv, cfp->Channel)) {
+                    scanType = HostCmd_SCAN_TYPE_PASSIVE;
+                }
+                break;
+            case BAND_B:
+            case BAND_G:
+            default:
+                scanChanList[chanIdx].RadioType = HostCmd_SCAN_RADIO_TYPE_BG;
+                break;
+            }
+
+            if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
+                scanChanList[chanIdx].MaxScanTime =
+                    wlan_cpu_to_le16(Adapter->PassiveScanTime);
+                scanChanList[chanIdx].ChanScanMode.PassiveScan = TRUE;
+            } else {
+                scanChanList[chanIdx].MaxScanTime =
+                    wlan_cpu_to_le16(Adapter->ActiveScanTime);
+                scanChanList[chanIdx].ChanScanMode.PassiveScan = FALSE;
+            }
+
+            scanChanList[chanIdx].ChanNumber = cfp->Channel;
+
+            if (filteredScan) {
+                scanChanList[chanIdx].MaxScanTime =
+                    wlan_cpu_to_le16(Adapter->SpecificScanTime);
+                scanChanList[chanIdx].ChanScanMode.DisableChanFilt = TRUE;
+            }
+        }
+    }
+}
+
+/**
+ *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+ *
+ *  Application layer or other functions can invoke wlan_scan_networks
+ *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ *    This structure is used as the basis of one or many wlan_scan_cmd_config
+ *    commands that are sent to the command processing module and sent to
+ *    firmware.
+ *
+ *  Create a wlan_scan_cmd_config based on the following user supplied
+ *    parameters (if present):
+ *             - SSID filter
+ *             - BSSID filter
+ *             - Number of Probes to be sent
+ *             - Channel list
+ *
+ *  If the SSID or BSSID filter is not present, disable/clear the filter.
+ *  If the number of probes is not set, use the adapter default setting
+ *  Qualify the channel
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param pUserScanIn      NULL or pointer to scan configuration parameters
+ *  @param pScanCfgOut      Output parameter: Resulting scan configuration
+ *  @param ppChanTlvOut     Output parameter: Pointer to the start of the
+ *                          channel TLV portion of the output scan config
+ *  @param pScanChanList    Output parameter: Pointer to the resulting channel
+ *                          list to scan
+ *  @param pMaxChanPerScan  Output parameter: Number of channels to scan for
+ *                          each issuance of the firmware scan command
+ *  @param pFilteredScan    Output parameter: Flag indicating whether or not
+ *                          a BSSID or SSID filter is being sent in the
+ *                          command to firmware.  Used to increase the number
+ *                          of channels sent in a scan command and to 
+ *                          disable the firmware channel scan filter.
+ *  @param pScanCurrentOnly Output parameter: Flag indicating whether or not
+ *                          we are only scanning our current active channel
+ *
+ *  @return                 void
+ */
+static void
+wlan_scan_setup_scan_config(wlan_private * priv,
+                            const wlan_ioctl_user_scan_cfg * pUserScanIn,
+                            wlan_scan_cmd_config * pScanCfgOut,
+                            MrvlIEtypes_ChanListParamSet_t ** ppChanTlvOut,
+                            ChanScanParamSet_t * pScanChanList,
+                            int *pMaxChanPerScan,
+                            BOOLEAN * pFilteredScan,
+                            BOOLEAN * pScanCurrentOnly)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    const u8 zeroMac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+    MrvlIEtypes_NumProbes_t *pNumProbesTlv;
+    u8 *pTlvPos;
+    u16 numProbes;
+    u16 ssidLen;
+    int chanIdx;
+    int scanType;
+    int scanDur;
+    int channel;
+    int radioType;
+    int ssidIdx;
+    BOOLEAN ssidFilter;
+
+    MrvlIEtypes_WildCardSsIdParamSet_t *pWildCardSsidTlv;
+
+    /* The tlvBufferLen is calculated for each scan command.  The TLVs added
+     *   in this routine will be preserved since the routine that sends
+     *   the command will append channelTLVs at *ppChanTlvOut.  The difference
+     *   between the *ppChanTlvOut and the tlvBuffer start will be used
+     *   to calculate the size of anything we add in this routine.
+     */
+    pScanCfgOut->tlvBufferLen = 0;
+
+    /* Running tlv pointer.  Assigned to ppChanTlvOut at end of function
+     *  so later routines know where channels can be added to the command buf
+     */
+    pTlvPos = pScanCfgOut->tlvBuffer;
+
+    /* Initialize the scan as un-filtered; the flag is later set to
+     *   TRUE below if a SSID or BSSID filter is sent in the command
+     */
+    *pFilteredScan = FALSE;
+
+    /* Initialize the scan as not being only on the current channel.  If
+     *   the channel list is customized, only contains one channel, and
+     *   is the active channel, this is set true and data flow is not halted.
+     */
+    *pScanCurrentOnly = FALSE;
+
+    if (pUserScanIn) {
+
+        /* Default the ssidFilter flag to TRUE, set false under certain 
+         *   wildcard conditions and qualified by the existence of an SSID 
+         *   list before marking the scan as filtered
+         */
+        ssidFilter = TRUE;
+
+        /* Set the bss type scan filter, use Adapter setting if unset */
+        pScanCfgOut->bssType = (pUserScanIn->bssType ? pUserScanIn->bssType :
+                                Adapter->ScanMode);
+
+        /* Set the number of probes to send, use Adapter setting if unset */
+        numProbes = (pUserScanIn->numProbes ? pUserScanIn->numProbes :
+                     Adapter->ScanProbes);
+
+        /*
+         * Set the BSSID filter to the incoming configuration,
+         *   if non-zero.  If not set, it will remain disabled (all zeros).
+         */
+        memcpy(pScanCfgOut->specificBSSID,
+               pUserScanIn->specificBSSID,
+               sizeof(pScanCfgOut->specificBSSID));
+
+        for (ssidIdx = 0; ((ssidIdx < NELEMENTS(pUserScanIn->ssidList))
+                           && (*pUserScanIn->ssidList[ssidIdx].ssid
+                               || pUserScanIn->ssidList[ssidIdx].maxLen));
+             ssidIdx++) {
+
+            ssidLen = strlen(pUserScanIn->ssidList[ssidIdx].ssid) + 1;
+
+            pWildCardSsidTlv = (MrvlIEtypes_WildCardSsIdParamSet_t *) pTlvPos;
+            pWildCardSsidTlv->Header.Type
+                = wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+            pWildCardSsidTlv->Header.Len
+                = ssidLen + sizeof(pWildCardSsidTlv->MaxSsidLength);
+            pWildCardSsidTlv->MaxSsidLength
+                = pUserScanIn->ssidList[ssidIdx].maxLen;
+
+            memcpy(pWildCardSsidTlv->SsId,
+                   pUserScanIn->ssidList[ssidIdx].ssid, ssidLen);
+
+            pTlvPos += (sizeof(pWildCardSsidTlv->Header)
+                        + pWildCardSsidTlv->Header.Len);
+
+            pWildCardSsidTlv->Header.Len
+                = wlan_cpu_to_le16(pWildCardSsidTlv->Header.Len);
+
+            PRINTM(INFO, "Scan: ssidList[%d]: %s, %d\n",
+                   ssidIdx,
+                   pWildCardSsidTlv->SsId, pWildCardSsidTlv->MaxSsidLength);
+
+            /* Empty wildcard ssid with a maxlen will match many or potentially
+             *   all SSIDs (maxlen == 32), therefore do not treat the scan
+             *   as filtered.
+             */
+            if ((ssidLen == 0) && pWildCardSsidTlv->MaxSsidLength) {
+                ssidFilter = FALSE;
+            }
+        }
+
+        /*
+         *  The default number of channels sent in the command is low to
+         *    ensure the response buffer from the firmware does not truncate
+         *    scan results.  That is not an issue with an SSID or BSSID
+         *    filter applied to the scan results in the firmware.
+         */
+        if ((ssidIdx && ssidFilter)
+            || memcmp(pScanCfgOut->specificBSSID, &zeroMac, sizeof(zeroMac))) {
+            *pFilteredScan = TRUE;
+        }
+
+    } else {
+        pScanCfgOut->bssType = Adapter->ScanMode;
+        numProbes = Adapter->ScanProbes;
+    }
+
+    /*
+     *  If a specific BSSID or SSID is used, the number of channels in the 
+     *  scan command will be increased to the absolute maximum.
+     */
+    if (*pFilteredScan)
+        *pMaxChanPerScan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+    else
+        *pMaxChanPerScan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+    /* If the input config or adapter has the number of Probes set, add tlv */
+    if (numProbes) {
+
+        PRINTM(INFO, "Scan: numProbes = %d\n", numProbes);
+
+        pNumProbesTlv = (MrvlIEtypes_NumProbes_t *) pTlvPos;
+        pNumProbesTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
+        pNumProbesTlv->Header.Len = sizeof(pNumProbesTlv->NumProbes);
+        pNumProbesTlv->NumProbes = wlan_cpu_to_le16(numProbes);
+
+        pTlvPos += sizeof(pNumProbesTlv->Header) + pNumProbesTlv->Header.Len;
+
+        pNumProbesTlv->Header.Len =
+            wlan_cpu_to_le16(pNumProbesTlv->Header.Len);
+    }
+
+    /*
+     * Set the output for the channel TLV to the address in the tlv buffer
+     *   past any TLVs that were added in this fuction (SSID, numProbes).
+     *   Channel TLVs will be added past this for each scan command, preserving
+     *   the TLVs that were previously added.
+     */
+    *ppChanTlvOut = (MrvlIEtypes_ChanListParamSet_t *) pTlvPos;
+
+    if (pUserScanIn && pUserScanIn->chanList[0].chanNumber) {
+
+        PRINTM(INFO, "Scan: Using supplied channel list\n");
+
+        for (chanIdx = 0;
+             chanIdx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+             && pUserScanIn->chanList[chanIdx].chanNumber; chanIdx++) {
+
+            channel = pUserScanIn->chanList[chanIdx].chanNumber;
+            (pScanChanList + chanIdx)->ChanNumber = channel;
+
+            radioType = pUserScanIn->chanList[chanIdx].radioType;
+            (pScanChanList + chanIdx)->RadioType = radioType;
+
+            scanType = pUserScanIn->chanList[chanIdx].scanType;
+
+            /* Prevent active scanning on a radar controlled channel */
+            if (radioType == HostCmd_SCAN_RADIO_TYPE_A) {
+                if (wlan_11h_radar_detect_required(priv, channel)) {
+                    scanType = HostCmd_SCAN_TYPE_PASSIVE;
+                }
+            }
+            if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
+                (pScanChanList + chanIdx)->ChanScanMode.PassiveScan = TRUE;
+            } else {
+                (pScanChanList + chanIdx)->ChanScanMode.PassiveScan = FALSE;
+            }
+
+            if (pUserScanIn->chanList[chanIdx].scanTime) {
+                scanDur = pUserScanIn->chanList[chanIdx].scanTime;
+            } else {
+                if (scanType == HostCmd_SCAN_TYPE_PASSIVE) {
+                    scanDur = Adapter->PassiveScanTime;
+                } else if (*pFilteredScan) {
+                    scanDur = Adapter->SpecificScanTime;
+                } else {
+                    scanDur = Adapter->ActiveScanTime;
+                }
+            }
+
+            (pScanChanList + chanIdx)->MinScanTime =
+                wlan_cpu_to_le16(scanDur);
+            (pScanChanList + chanIdx)->MaxScanTime =
+                wlan_cpu_to_le16(scanDur);
+        }
+
+        /* Check if we are only scanning the current channel */
+        if ((chanIdx == 1)
+            && (pUserScanIn->chanList[0].chanNumber
+                == priv->adapter->CurBssParams.BSSDescriptor.Channel)) {
+            *pScanCurrentOnly = TRUE;
+            PRINTM(INFO, "Scan: Scanning current channel only");
+        }
+
+    } else {
+        PRINTM(INFO, "Scan: Creating full region channel list\n");
+        wlan_scan_create_channel_list(priv, pScanChanList, *pFilteredScan);
+    }
+}
+
+/**
+ *  @brief Construct and send multiple scan config commands to the firmware
+ *
+ *  Previous routines have created a wlan_scan_cmd_config with any requested
+ *   TLVs.  This function splits the channel TLV into maxChanPerScan lists
+ *   and sends the portion of the channel TLV along with the other TLVs
+ *   to the wlan_cmd routines for execution in the firmware.
+ *
+ *  @param priv            A pointer to wlan_private structure
+ *  @param maxChanPerScan  Maximum number channels to be included in each
+ *                         scan command sent to firmware
+ *  @param filteredScan    Flag indicating whether or not a BSSID or SSID
+ *                         filter is being used for the firmware command
+ *                         scan command sent to firmware
+ *  @param pScanCfgOut     Scan configuration used for this scan.
+ *  @param pChanTlvOut     Pointer in the pScanCfgOut where the channel TLV
+ *                         should start.  This is past any other TLVs that
+ *                         must be sent down in each firmware command.
+ *  @param pScanChanList   List of channels to scan in maxChanPerScan segments
+ *
+ *  @return                WLAN_STATUS_SUCCESS or error return otherwise
+ */
+static int
+wlan_scan_channel_list(wlan_private * priv,
+                       int maxChanPerScan,
+                       BOOLEAN filteredScan,
+                       wlan_scan_cmd_config * pScanCfgOut,
+                       MrvlIEtypes_ChanListParamSet_t * pChanTlvOut,
+                       ChanScanParamSet_t * pScanChanList)
+{
+    ChanScanParamSet_t *pTmpChan;
+    ChanScanParamSet_t *pStartChan;
+    u8 scanBand;
+    int doneEarly;
+    int tlvIdx;
+    int totalscantime;
+    int ret;
+
+    ENTER();
+
+    if (pScanCfgOut == 0 || pChanTlvOut == 0 || pScanChanList == 0) {
+        PRINTM(INFO, "Scan: Null detect: %p, %p, %p\n",
+               pScanCfgOut, pChanTlvOut, pScanChanList);
+        return WLAN_STATUS_FAILURE;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    pChanTlvOut->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
+
+    /* Set the temp channel struct pointer to the start of the desired list */
+    pTmpChan = pScanChanList;
+
+    /* Loop through the desired channel list, sending a new firmware scan
+     *   commands for each maxChanPerScan channels (or for 1,6,11 individually
+     *   if configured accordingly)
+     */
+    while (pTmpChan->ChanNumber) {
+
+        tlvIdx = 0;
+        totalscantime = 0;
+        pChanTlvOut->Header.Len = 0;
+        scanBand = pTmpChan->RadioType;
+        pStartChan = pTmpChan;
+        doneEarly = FALSE;
+
+        /* Construct the Channel TLV for the scan command.  Continue to
+         *  insert channel TLVs until:
+         *    - the tlvIdx hits the maximum configured per scan command
+         *    - the next channel to insert is 0 (end of desired channel list)
+         *    - doneEarly is set (controlling individual scanning of 1,6,11)
+         */
+        while (tlvIdx < maxChanPerScan && pTmpChan->ChanNumber && !doneEarly) {
+
+            PRINTM(INFO, "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n",
+                   pTmpChan->ChanNumber,
+                   pTmpChan->RadioType,
+                   pTmpChan->ChanScanMode.PassiveScan,
+                   pTmpChan->ChanScanMode.DisableChanFilt,
+                   pTmpChan->MaxScanTime);
+
+            /* Copy the current channel TLV to the command being prepared */
+            memcpy(pChanTlvOut->ChanScanParam + tlvIdx,
+                   pTmpChan, sizeof(pChanTlvOut->ChanScanParam));
+
+            /* Increment the TLV header length by the size appended */
+            pChanTlvOut->Header.Len += sizeof(pChanTlvOut->ChanScanParam);
+
+            /*
+             *  The tlv buffer length is set to the number of bytes of the
+             *    between the channel tlv pointer and the start of the
+             *    tlv buffer.  This compensates for any TLVs that were appended
+             *    before the channel list.
+             */
+            pScanCfgOut->tlvBufferLen = ((u8 *) pChanTlvOut
+                                         - pScanCfgOut->tlvBuffer);
+
+            /*  Add the size of the channel tlv header and the data length */
+            pScanCfgOut->tlvBufferLen += (sizeof(pChanTlvOut->Header)
+                                          + pChanTlvOut->Header.Len);
+
+            /* Increment the index to the channel tlv we are constructing */
+            tlvIdx++;
+
+            /* Count the total scan time per command */
+            totalscantime += pTmpChan->MaxScanTime;
+
+            doneEarly = FALSE;
+
+            /* Stop the loop if the *current* channel is in the 1,6,11 set
+             *   and we are not filtering on a BSSID or SSID.
+             */
+            if (!filteredScan && (pTmpChan->ChanNumber == 1
+                                  || pTmpChan->ChanNumber == 6
+                                  || pTmpChan->ChanNumber == 11)) {
+                doneEarly = TRUE;
+            }
+
+            /* Increment the tmp pointer to the next channel to be scanned */
+            pTmpChan++;
+
+            /* Stop the loop if the *next* channel is in the 1,6,11 set.
+             *  This will cause it to be the only channel scanned on the next
+             *  interation
+             */
+            if (!filteredScan && (pTmpChan->ChanNumber == 1
+                                  || pTmpChan->ChanNumber == 6
+                                  || pTmpChan->ChanNumber == 11)) {
+                doneEarly = TRUE;
+            }
+        }
+
+        /* The total scan time should be less than scan command timeout value */
+        if (totalscantime > MRVDRV_MAX_TOTAL_SCAN_TIME) {
+            PRINTM(MSG,
+                   "Total scan time %d ms is over limit (%d ms), scan skipped\n",
+                   totalscantime, MRVDRV_MAX_TOTAL_SCAN_TIME);
+            ret = WLAN_STATUS_FAILURE;
+            break;
+        }
+
+        pChanTlvOut->Header.Len = wlan_cpu_to_le16(pChanTlvOut->Header.Len);
+
+        priv->adapter->pScanChannels = pStartChan;
+
+        /* Send the scan command to the firmware with the specified cfg */
+        ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SCAN, 0,
+                               HostCmd_OPTION_WAITFORRSP, 0, pScanCfgOut);
+
+        if (ret)
+            break;
+    }
+
+    LEAVE();
+
+    if (ret) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Internal function used to start a scan based on an input config
+ *
+ *  Use the input user scan configuration information when provided in
+ *    order to send the appropriate scan commands to firmware to populate or
+ *    update the internal driver scan table
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param pUserScanIn   Pointer to the input configuration for the requested
+ *                       scan.
+ *
+ *  @return              WLAN_STATUS_SUCCESS or < 0 if error
+ */
+static int
+wlan_scan_networks(wlan_private * priv,
+                   const wlan_ioctl_user_scan_cfg * pUserScanIn)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypes_ChanListParamSet_t *pChanTlvOut;
+
+    ChanScanParamSet_t scanChanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+    wlan_scan_cmd_config_tlv *scanCfgOut = NULL;
+    BOOLEAN keepPreviousScan;
+    BOOLEAN filteredScan;
+    BOOLEAN scanCurrentChanOnly;
+    int maxChanPerScan;
+    int ret;
+
+    ENTER();
+
+    scanCfgOut =
+        (wlan_scan_cmd_config_tlv *) kmalloc(sizeof(wlan_scan_cmd_config_tlv),
+                                             GFP_KERNEL);
+    if (!scanCfgOut) {
+        PRINTM(ERROR, "Memory allocation for scancfgOut failed!\n");
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memset(scanChanList, 0x00, sizeof(scanChanList));
+    memset(scanCfgOut, 0x00, sizeof(wlan_scan_cmd_config_tlv));
+
+    keepPreviousScan = FALSE;
+
+    wlan_scan_setup_scan_config(priv,
+                                pUserScanIn,
+                                &scanCfgOut->config,
+                                &pChanTlvOut,
+                                scanChanList,
+                                &maxChanPerScan,
+                                &filteredScan, &scanCurrentChanOnly);
+
+    if (pUserScanIn) {
+        keepPreviousScan = pUserScanIn->keepPreviousScan;
+    }
+
+    if (keepPreviousScan == FALSE) {
+        memset(Adapter->ScanTable, 0x00,
+               sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+        Adapter->NumInScanTable = 0;
+        Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
+    }
+
+    /* Keep the data path active if we are only scanning our current channel */
+    if (!scanCurrentChanOnly) {
+        PRINTM(INFO, "Scan: WMM Queue stop\n");
+        priv->wlan_dev.netdev->watchdog_timeo = MRVDRV_SCAN_WATCHDOG_TIMEOUT;
+        /* If WMM queues are in use, only stop the internal data queues */
+        wmm_stop_queue(priv);
+    }
+
+    ret = wlan_scan_channel_list(priv,
+                                 maxChanPerScan,
+                                 filteredScan,
+                                 &scanCfgOut->config,
+                                 pChanTlvOut, scanChanList);
+
+    /*  Process the resulting scan table:
+     *    - Remove any bad ssids
+     *    - Update our current BSS information from scan data
+     */
+    if (!ret)
+        wlan_scan_process_results(priv);
+
+    PRINTM(INFO, "Scan: WMM Queue start\n");
+
+    priv->wlan_dev.netdev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        wmm_start_queue(priv);
+    }
+    os_carrier_on(priv);
+    os_start_queue(priv);
+    kfree(scanCfgOut);
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Create a brief scan resp to relay basic BSS info to the app layer
+ *
+ *  When the beacon/probe response has not been buffered, use the saved BSS
+ *    information available to provide a minimum response for the application
+ *    ioctl retrieval routines.  Include:
+ *        - Timestamp
+ *        - Beacon Period
+ *        - Capabilities (including WMM Element if available)
+ *        - SSID
+ *
+ *  @param ppBuffer  Output parameter: Buffer used to create basic scan rsp
+ *  @param pBSSDesc  Pointer to a BSS entry in the scan table to create
+ *                   scan response from for delivery to the application layer
+ *
+ *  @return          void
+ */
+static void
+wlan_scan_create_brief_table_entry(u8 ** ppBuffer, BSSDescriptor_t * pBSSDesc)
+{
+    u8 *pTmpBuf = *ppBuffer;
+    u8 tmpSSIDHdr[2];
+    u8 ieLen = 0;
+
+    if (copy_to_user(pTmpBuf, pBSSDesc->TimeStamp,
+                     sizeof(pBSSDesc->TimeStamp))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(pBSSDesc->TimeStamp);
+
+    if (copy_to_user(pTmpBuf, &pBSSDesc->BeaconPeriod,
+                     sizeof(pBSSDesc->BeaconPeriod))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(pBSSDesc->BeaconPeriod);
+
+    if (copy_to_user(pTmpBuf, &pBSSDesc->Cap, sizeof(pBSSDesc->Cap))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(pBSSDesc->Cap);
+
+    tmpSSIDHdr[0] = 0;          /* Element ID for SSID is zero */
+    tmpSSIDHdr[1] = pBSSDesc->Ssid.SsidLength;
+    if (copy_to_user(pTmpBuf, tmpSSIDHdr, sizeof(tmpSSIDHdr))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += sizeof(tmpSSIDHdr);
+
+    if (copy_to_user(pTmpBuf, pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return;
+    }
+    pTmpBuf += pBSSDesc->Ssid.SsidLength;
+
+    if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
+        ieLen = sizeof(IEEEtypes_Header_t) + pBSSDesc->wmmIE.VendHdr.Len;
+        if (copy_to_user(pTmpBuf, &pBSSDesc->wmmIE, ieLen)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return;
+        }
+
+        pTmpBuf += ieLen;
+    }
+
+    if (pBSSDesc->pWpaIE) {
+        if ((*(pBSSDesc->pWpaIE)).VendHdr.ElementId == WPA_IE) {
+            ieLen =
+                sizeof(IEEEtypes_Header_t) +
+                (*(pBSSDesc->pWpaIE)).VendHdr.Len;
+            if (copy_to_user(pTmpBuf, pBSSDesc->pWpaIE, ieLen)) {
+                PRINTM(INFO, "Copy to user failed\n");
+                return;
+            }
+        }
+
+        pTmpBuf += ieLen;
+    }
+
+    if (pBSSDesc->pRsnIE) {
+        if ((*(pBSSDesc->pRsnIE)).IeeeHdr.ElementId == RSN_IE) {
+            ieLen =
+                sizeof(IEEEtypes_Header_t) +
+                (*(pBSSDesc->pRsnIE)).IeeeHdr.Len;
+            if (copy_to_user(pTmpBuf, pBSSDesc->pRsnIE, ieLen)) {
+                PRINTM(INFO, "Copy to user failed\n");
+                return;
+            }
+        }
+
+        pTmpBuf += ieLen;
+    }
+
+    *ppBuffer = pTmpBuf;
+}
+
+/**
+ *  @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ *  TLVs can be included at the end of the scan response BSS information.
+ *    Parse the data in the buffer for pointers to TLVs that can potentially
+ *    be passed back in the response
+ *
+ *  @param pTlv        Pointer to the start of the TLV buffer to parse
+ *  @param tlvBufSize  Size of the TLV buffer
+ *  @param ppTsfTlv    Output parameter: Pointer to the TSF TLV if found
+ *
+ *  @return            void
+ */
+static void
+wlan_ret_802_11_scan_get_tlv_ptrs(MrvlIEtypes_Data_t * pTlv,
+                                  int tlvBufSize,
+                                  MrvlIEtypes_TsfTimestamp_t ** ppTsfTlv)
+{
+    MrvlIEtypes_Data_t *pCurrentTlv;
+    int tlvBufLeft;
+    u16 tlvType;
+    u16 tlvLen;
+
+    pCurrentTlv = pTlv;
+    tlvBufLeft = tlvBufSize;
+    *ppTsfTlv = NULL;
+
+    PRINTM(INFO, "SCAN_RESP: tlvBufSize = %d\n", tlvBufSize);
+    HEXDUMP("SCAN_RESP: TLV Buf", (u8 *) pTlv, tlvBufSize);
+
+    while (tlvBufLeft >= sizeof(MrvlIEtypesHeader_t)) {
+        tlvType = wlan_le16_to_cpu(pCurrentTlv->Header.Type);
+        tlvLen = wlan_le16_to_cpu(pCurrentTlv->Header.Len);
+
+        switch (tlvType) {
+        case TLV_TYPE_TSFTIMESTAMP:
+            PRINTM(INFO, "SCAN_RESP: TSF Timestamp TLV, len = %d\n", tlvLen);
+            *ppTsfTlv = (MrvlIEtypes_TsfTimestamp_t *) pCurrentTlv;
+            break;
+
+        default:
+            PRINTM(INFO, "SCAN_RESP: Unhandled TLV = %d\n", tlvType);
+            /* Give up, this seems corrupted */
+            return;
+        }                       /* switch */
+
+        tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen);
+        pCurrentTlv = (MrvlIEtypes_Data_t *) (pCurrentTlv->Data + tlvLen);
+    }                           /* while */
+}
+
+/**
+ *  @brief Interpret a BSS scan response returned from the firmware
+ *
+ *  Parse the various fixed fields and IEs passed back for a a BSS probe
+ *   response or beacon from the scan command.  Record information as needed
+ *   in the scan table BSSDescriptor_t for that entry.
+ *
+ *  @param pBSSEntry    Output parameter: Pointer to the BSS Entry
+ *  @param pBeaconInfo  Pointer to the Beacon information
+ *  @param bytesLeft    Number of bytes left to parse
+ *
+ *  @return             WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_interpret_bss_desc_with_ie(BSSDescriptor_t * pBSSEntry,
+                                u8 ** pBeaconInfo, int *bytesLeft)
+{
+    IEEEtypes_ElementId_e elemID;
+    IEEEtypes_FhParamSet_t *pFH;
+    IEEEtypes_DsParamSet_t *pDS;
+    IEEEtypes_CfParamSet_t *pCF;
+    IEEEtypes_IbssParamSet_t *pIbss;
+    IEEEtypes_CapInfo_t *pCap;
+    WLAN_802_11_FIXED_IEs fixedIE;
+    u8 *pCurrentPtr;
+    u8 *pRate;
+    u8 elemLen;
+    u16 totalIeLen;
+    u8 bytesToCopy;
+    u8 rateSize;
+    u16 beaconSize;
+    BOOLEAN foundDataRateIE;
+    int bytesLeftForCurrentBeacon;
+    IEEEtypes_ERPInfo_t *pERPInfo;
+
+    IEEEtypes_VendorSpecific_t *pVendorIe;
+    const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+    const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+    const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
+
+    IEEEtypes_CountryInfoSet_t *pcountryinfo;
+
+    ENTER();
+
+    foundDataRateIE = FALSE;
+    rateSize = 0;
+    beaconSize = 0;
+
+    if (*bytesLeft >= sizeof(beaconSize)) {
+        /* Extract & convert beacon size from the command buffer */
+        memcpy(&beaconSize, *pBeaconInfo, sizeof(beaconSize));
+        beaconSize = wlan_le16_to_cpu(beaconSize);
+        *bytesLeft -= sizeof(beaconSize);
+        *pBeaconInfo += sizeof(beaconSize);
+    }
+
+    if (beaconSize == 0 || beaconSize > *bytesLeft) {
+
+        *pBeaconInfo += *bytesLeft;
+        *bytesLeft = 0;
+
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /* Initialize the current working beacon pointer for this BSS iteration */
+    pCurrentPtr = *pBeaconInfo;
+
+    /* Advance the return beacon pointer past the current beacon */
+    *pBeaconInfo += beaconSize;
+    *bytesLeft -= beaconSize;
+
+    bytesLeftForCurrentBeacon = beaconSize;
+
+    memcpy(pBSSEntry->MacAddress, pCurrentPtr, ETH_ALEN);
+    PRINTM(INFO, "InterpretIE: AP MAC Addr-%02x:%02x:%02x:%02x:%02x:%02x\n",
+           pBSSEntry->MacAddress[0], pBSSEntry->MacAddress[1],
+           pBSSEntry->MacAddress[2], pBSSEntry->MacAddress[3],
+           pBSSEntry->MacAddress[4], pBSSEntry->MacAddress[5]);
+
+    pCurrentPtr += ETH_ALEN;
+    bytesLeftForCurrentBeacon -= ETH_ALEN;
+
+    if (bytesLeftForCurrentBeacon < 12) {
+        PRINTM(INFO, "InterpretIE: Not enough bytes left\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    /*
+     * next 4 fields are RSSI, time stamp, beacon interval,
+     *   and capability information
+     */
+
+    /* RSSI is 1 byte long */
+    pBSSEntry->Rssi = wlan_le32_to_cpu((LONG) (*pCurrentPtr));
+    PRINTM(INFO, "InterpretIE: RSSI=%02X\n", *pCurrentPtr);
+    pCurrentPtr += 1;
+    bytesLeftForCurrentBeacon -= 1;
+
+    /*
+     *  The RSSI is not part of the beacon/probe response.  After we have
+     *    advanced pCurrentPtr past the RSSI field, save the remaining
+     *    data for use at the application layer
+     */
+    pBSSEntry->pBeaconBuf = pCurrentPtr;
+    pBSSEntry->beaconBufSize = bytesLeftForCurrentBeacon;
+
+    /* time stamp is 8 bytes long */
+    memcpy(fixedIE.Timestamp, pCurrentPtr, 8);
+    memcpy(pBSSEntry->TimeStamp, pCurrentPtr, 8);
+    pCurrentPtr += 8;
+    bytesLeftForCurrentBeacon -= 8;
+
+    /* beacon interval is 2 bytes long */
+    memcpy(&fixedIE.BeaconInterval, pCurrentPtr, 2);
+    pBSSEntry->BeaconPeriod = wlan_le16_to_cpu(fixedIE.BeaconInterval);
+    pCurrentPtr += 2;
+    bytesLeftForCurrentBeacon -= 2;
+
+    /* capability information is 2 bytes long */
+    memcpy(&fixedIE.Capabilities, pCurrentPtr, 2);
+    PRINTM(INFO, "InterpretIE: fixedIE.Capabilities=0x%X\n",
+           fixedIE.Capabilities);
+    fixedIE.Capabilities = wlan_le16_to_cpu(fixedIE.Capabilities);
+    pCap = (IEEEtypes_CapInfo_t *) & fixedIE.Capabilities;
+    memcpy(&pBSSEntry->Cap, pCap, sizeof(IEEEtypes_CapInfo_t));
+    pCurrentPtr += 2;
+    bytesLeftForCurrentBeacon -= 2;
+
+    /* rest of the current buffer are IE's */
+    PRINTM(INFO, "InterpretIE: IELength for this AP = %d\n",
+           bytesLeftForCurrentBeacon);
+
+    HEXDUMP("InterpretIE: IE info", (u8 *) pCurrentPtr,
+            bytesLeftForCurrentBeacon);
+
+    if (pCap->Privacy) {
+        PRINTM(INFO, "InterpretIE: AP WEP enabled\n");
+        pBSSEntry->Privacy = Wlan802_11PrivFilter8021xWEP;
+    } else {
+        pBSSEntry->Privacy = Wlan802_11PrivFilterAcceptAll;
+    }
+
+    if (pCap->Ibss == 1) {
+        pBSSEntry->InfrastructureMode = Wlan802_11IBSS;
+    } else {
+        pBSSEntry->InfrastructureMode = Wlan802_11Infrastructure;
+    }
+
+    if (pCap->SpectrumMgmt == 1) {
+        PRINTM(INFO, "InterpretIE: 11h- Spectrum Management "
+               "capability bit found\n");
+        pBSSEntry->wlan_11h_bss_info.sensed11h = 1;
+    }
+
+    /* process variable IE */
+    while (bytesLeftForCurrentBeacon >= 2) {
+        elemID = (IEEEtypes_ElementId_e) (*((u8 *) pCurrentPtr));
+        elemLen = *((u8 *) pCurrentPtr + 1);
+        totalIeLen = elemLen + sizeof(IEEEtypes_Header_t);
+
+        if (bytesLeftForCurrentBeacon < elemLen) {
+            PRINTM(INFO, "InterpretIE: Error in processing IE, "
+                   "bytes left < IE length\n");
+            bytesLeftForCurrentBeacon = 0;
+            continue;
+        }
+
+        switch (elemID) {
+
+        case SSID:
+            pBSSEntry->Ssid.SsidLength = elemLen;
+            memcpy(pBSSEntry->Ssid.Ssid, (pCurrentPtr + 2), elemLen);
+            PRINTM(INFO, "InterpretIE: Ssid: %-32s\n", pBSSEntry->Ssid.Ssid);
+            break;
+
+        case SUPPORTED_RATES:
+            memcpy(pBSSEntry->DataRates, pCurrentPtr + 2, elemLen);
+            memcpy(pBSSEntry->SupportedRates, pCurrentPtr + 2, elemLen);
+            HEXDUMP("InterpretIE: SupportedRates:",
+                    pBSSEntry->SupportedRates, elemLen);
+            rateSize = elemLen;
+            foundDataRateIE = TRUE;
+            break;
+
+        case FH_PARAM_SET:
+            pFH = (IEEEtypes_FhParamSet_t *) pCurrentPtr;
+            pBSSEntry->NetworkTypeInUse = Wlan802_11FH;
+            memcpy(&pBSSEntry->PhyParamSet.FhParamSet, pFH,
+                   sizeof(IEEEtypes_FhParamSet_t));
+            pBSSEntry->PhyParamSet.FhParamSet.DwellTime
+                =
+                wlan_le16_to_cpu(pBSSEntry->PhyParamSet.FhParamSet.DwellTime);
+            break;
+
+        case DS_PARAM_SET:
+            pDS = (IEEEtypes_DsParamSet_t *) pCurrentPtr;
+
+            pBSSEntry->NetworkTypeInUse = Wlan802_11DS;
+            pBSSEntry->Channel = pDS->CurrentChan;
+
+            memcpy(&pBSSEntry->PhyParamSet.DsParamSet, pDS,
+                   sizeof(IEEEtypes_DsParamSet_t));
+            break;
+
+        case CF_PARAM_SET:
+            pCF = (IEEEtypes_CfParamSet_t *) pCurrentPtr;
+            memcpy(&pBSSEntry->SsParamSet.CfParamSet, pCF,
+                   sizeof(IEEEtypes_CfParamSet_t));
+            break;
+
+        case IBSS_PARAM_SET:
+            pIbss = (IEEEtypes_IbssParamSet_t *) pCurrentPtr;
+            pBSSEntry->ATIMWindow = wlan_le32_to_cpu(pIbss->AtimWindow);
+            memcpy(&pBSSEntry->SsParamSet.IbssParamSet, pIbss,
+                   sizeof(IEEEtypes_IbssParamSet_t));
+            break;
+
+            /* Handle Country Info IE */
+        case COUNTRY_INFO:
+            pcountryinfo = (IEEEtypes_CountryInfoSet_t *) pCurrentPtr;
+
+            if (pcountryinfo->Len < sizeof(pcountryinfo->CountryCode)
+                || pcountryinfo->Len > 254) {
+                PRINTM(INFO, "InterpretIE: 11D- Err "
+                       "CountryInfo len =%d min=%d max=254\n",
+                       pcountryinfo->Len, sizeof(pcountryinfo->CountryCode));
+                LEAVE();
+                return WLAN_STATUS_FAILURE;
+            }
+
+            memcpy(&pBSSEntry->CountryInfo,
+                   pcountryinfo, pcountryinfo->Len + 2);
+            HEXDUMP("InterpretIE: 11D- CountryInfo:",
+                    (u8 *) pcountryinfo, (u32) (pcountryinfo->Len + 2));
+            break;
+        case ERP_INFO:
+            pERPInfo = (IEEEtypes_ERPInfo_t *) pCurrentPtr;
+            pBSSEntry->ERPFlags = pERPInfo->ERPFlags;
+            break;
+        case POWER_CONSTRAINT:
+        case POWER_CAPABILITY:
+        case TPC_REPORT:
+        case CHANNEL_SWITCH_ANN:
+        case QUIET:
+        case IBSS_DFS:
+        case SUPPORTED_CHANNELS:
+        case TPC_REQUEST:
+            wlan_11h_process_bss_elem(&pBSSEntry->wlan_11h_bss_info,
+                                      pCurrentPtr);
+            break;
+        case EXTENDED_SUPPORTED_RATES:
+            /*
+             * only process extended supported rate
+             * if data rate is already found.
+             * data rate IE should come before
+             * extended supported rate IE
+             */
+            if (foundDataRateIE) {
+                if ((elemLen + rateSize) > WLAN_SUPPORTED_RATES) {
+                    bytesToCopy = (WLAN_SUPPORTED_RATES - rateSize);
+                } else {
+                    bytesToCopy = elemLen;
+                }
+
+                pRate = (u8 *) pBSSEntry->DataRates;
+                pRate += rateSize;
+                memcpy(pRate, pCurrentPtr + 2, bytesToCopy);
+
+                pRate = (u8 *) pBSSEntry->SupportedRates;
+                pRate += rateSize;
+                memcpy(pRate, pCurrentPtr + 2, bytesToCopy);
+            }
+            HEXDUMP("InterpretIE: ExtSupportedRates:",
+                    pBSSEntry->SupportedRates, elemLen + rateSize);
+            break;
+
+        case VENDOR_SPECIFIC_221:
+            pVendorIe = (IEEEtypes_VendorSpecific_t *) pCurrentPtr;
+
+            if (!memcmp(pVendorIe->VendHdr.Oui, wpa_oui, sizeof(wpa_oui))) {
+                pBSSEntry->pWpaIE =
+                    (IEEEtypes_VendorSpecific_t *) pCurrentPtr;
+                pBSSEntry->wpaOffset = pCurrentPtr - pBSSEntry->pBeaconBuf;
+                pBSSEntry->pWpaIE =
+                    (IEEEtypes_VendorSpecific_t *) (pBSSEntry->pBeaconBuf +
+                                                    pBSSEntry->wpaOffset);
+                HEXDUMP("InterpretIE: Resp WPA_IE", (u8 *) pBSSEntry->pWpaIE,
+                        ((*(pBSSEntry->pWpaIE)).VendHdr.Len +
+                         sizeof(IEEEtypes_Header_t)));
+            } else
+                if (!memcmp(pVendorIe->VendHdr.Oui, wmm_oui, sizeof(wmm_oui)))
+            {
+                if (totalIeLen == sizeof(IEEEtypes_WmmParameter_t)
+                    || totalIeLen == sizeof(IEEEtypes_WmmInfo_t)) {
+
+                    /* Only accept and copy the WMM IE if it matches
+                     *  the size expected for the WMM Info IE or the
+                     *  WMM Parameter IE.
+                     */
+                    memcpy((u8 *) & pBSSEntry->wmmIE, pCurrentPtr,
+                           totalIeLen);
+                    HEXDUMP("InterpretIE: Resp WMM_IE",
+                            (u8 *) & pBSSEntry->wmmIE, totalIeLen);
+                }
+            } else if (!memcmp(pVendorIe->VendHdr.Oui,
+                               wps_oui, sizeof(wps_oui))) {
+                pBSSEntry->pWpsIE =
+                    (IEEEtypes_VendorSpecific_t *) pCurrentPtr;
+                pBSSEntry->wpsOffset = pCurrentPtr - pBSSEntry->pBeaconBuf;
+                pBSSEntry->pWpsIE =
+                    (IEEEtypes_VendorSpecific_t *) (pBSSEntry->pBeaconBuf +
+                                                    pBSSEntry->wpsOffset);
+                HEXDUMP("InterpretIE: Resp WPS_IE", (u8 *) pBSSEntry->pWpsIE,
+                        totalIeLen);
+            }
+            break;
+        case RSN_IE:
+            pBSSEntry->pRsnIE = (IEEEtypes_Generic_t *) pCurrentPtr;
+            pBSSEntry->rsnOffset = pCurrentPtr - pBSSEntry->pBeaconBuf;
+            pBSSEntry->pRsnIE =
+                (IEEEtypes_Generic_t *) (pBSSEntry->pBeaconBuf +
+                                         pBSSEntry->rsnOffset);
+            HEXDUMP("InterpretIE: Resp RSN_IE", (u8 *) pBSSEntry->pRsnIE,
+                    (*(pBSSEntry->pRsnIE)).IeeeHdr.Len +
+                    sizeof(IEEEtypes_Header_t));
+            break;
+        }
+
+        pCurrentPtr += elemLen + 2;
+
+        /* need to account for IE ID and IE Len */
+        bytesLeftForCurrentBeacon -= (elemLen + 2);
+
+    }                           /* while (bytesLeftForCurrentBeacon > 2) */
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0--ssid is same, otherwise is different
+ */
+int
+wlan_ssid_cmp(WLAN_802_11_SSID * ssid1, WLAN_802_11_SSID * ssid2)
+{
+    if (!ssid1 || !ssid2)
+        return -1;
+
+    if (ssid1->SsidLength != ssid2->SsidLength)
+        return -1;
+
+    return memcmp(ssid1->Ssid, ssid2->Ssid, ssid1->SsidLength);
+}
+
+/**
+ *  @brief This function finds a specific compatible BSSID in the scan list
+ *
+ *  @param Adapter  A pointer to wlan_adapter
+ *  @param bssid    BSSID to find in the scan list
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list, or error return code (< 0)
+ */
+int
+wlan_find_bssid_in_list(wlan_adapter * Adapter, u8 * bssid, int mode)
+{
+    int ret = -ENETUNREACH;
+    int i;
+
+    if (!bssid)
+        return -EFAULT;
+
+    PRINTM(INFO, "FindBSSID: Num of BSSIDs = %d\n", Adapter->NumInScanTable);
+
+    /* Look through the scan table for a compatible match. The ret return
+     *   variable will be equal to the index in the scan table (greater
+     *   than zero) if the network is compatible.  The loop will continue
+     *   past a matched bssid that is not compatible in case there is an
+     *   AP with multiple SSIDs assigned to the same BSSID
+     */
+    for (i = 0; ret < 0 && i < Adapter->NumInScanTable; i++) {
+        if (!memcmp(Adapter->ScanTable[i].MacAddress, bssid, ETH_ALEN)) {
+            switch (mode) {
+            case Wlan802_11Infrastructure:
+            case Wlan802_11IBSS:
+                ret = wlan_is_network_compatible(Adapter, i, mode);
+                break;
+            default:
+                ret = i;
+                break;
+            }
+        }
+    }
+
+    if (ret >= 0) {
+        if (find_cfp_by_band_and_channel
+            (Adapter, Adapter->ScanTable[ret].bss_band,
+             Adapter->ScanTable[ret].Channel) == NULL) {
+            ret = -ENETUNREACH;
+        }
+    }
+    return ret;
+}
+
+/**
+ *  @brief This function finds ssid in ssid list.
+ *
+ *  @param Adapter      A pointer to wlan_adapter
+ *  @param ssid         SSID to find in the list
+ *  @param bssid        BSSID to qualify the SSID selection (if provided)
+ *  @param mode         Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list
+ */
+int
+wlan_find_ssid_in_list(wlan_adapter * Adapter, WLAN_802_11_SSID * ssid,
+                       u8 * bssid, int mode)
+{
+    int net = -ENETUNREACH;
+    u8 bestrssi = 0;
+    int i, j;
+
+    PRINTM(INFO, "Num of Entries in Table = %d\n", Adapter->NumInScanTable);
+
+    /* Loop through the table until the maximum is reached or until a match
+     *   is found based on the bssid field comparison 
+     */
+    for (i = 0;
+         i < Adapter->NumInScanTable && (bssid == NULL || (bssid && net < 0));
+         i++) {
+
+        if (!wlan_ssid_cmp(&Adapter->ScanTable[i].Ssid, ssid) &&
+            ((bssid == NULL)
+             || !memcmp(Adapter->ScanTable[i].MacAddress, bssid, ETH_ALEN))) {
+            switch (mode) {
+            case Wlan802_11Infrastructure:
+            case Wlan802_11IBSS:
+                j = wlan_is_network_compatible(Adapter, i, mode);
+
+                if (j >= 0) {
+                    if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                        bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                        net = i;
+                    }
+                } else {
+                    if (net == -ENETUNREACH) {
+                        net = j;
+                    }
+                }
+                break;
+            case Wlan802_11AutoUnknown:
+            default:
+                /* Do not check compatibility if the mode requested is 
+                 *   AutoUnknown.  Allows generic find to work without 
+                 *   verifying against the Adapter security settings
+                 */
+                if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                    bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                    net = i;
+                }
+                break;
+            }
+        }
+    }
+    if (net >= 0) {
+        if (find_cfp_by_band_and_channel
+            (Adapter, Adapter->ScanTable[net].bss_band,
+             Adapter->ScanTable[net].Channel) == NULL) {
+            net = -ENETUNREACH;
+        }
+    }
+    return net;
+}
+
+/**
+ *  @brief This function finds the best SSID in the Scan List
+ *
+ *  Search the scan table for the best SSID that also matches the current
+ *   adapter network preference (infrastructure or adhoc)
+ *
+ *  @param Adapter  A pointer to wlan_adapter
+ *
+ *  @return         index in BSSID list
+ */
+int
+wlan_find_best_ssid_in_list(wlan_adapter * Adapter)
+{
+    int mode = Adapter->InfrastructureMode;
+    int bestnet = -ENETUNREACH;
+    u8 bestrssi = 0;
+    int i;
+
+    ENTER();
+
+    PRINTM(INFO, "Num of BSSIDs = %d\n", Adapter->NumInScanTable);
+
+    for (i = 0; i < Adapter->NumInScanTable; i++) {
+        switch (mode) {
+        case Wlan802_11Infrastructure:
+        case Wlan802_11IBSS:
+            if (wlan_is_network_compatible(Adapter, i, mode) >= 0) {
+                if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                    bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                    bestnet = i;
+                }
+            }
+            break;
+        case Wlan802_11AutoUnknown:
+        default:
+            if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) {
+                bestrssi = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+                bestnet = i;
+            }
+            break;
+        }
+    }
+
+    LEAVE();
+    return bestnet;
+}
+
+/**
+ *  @brief Find the AP with specific ssid in the scan list
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pSSID        A pointer to AP's ssid
+ *
+ *  @return             WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+wlan_find_best_network_ssid(wlan_private * priv, WLAN_802_11_SSID * pSSID)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    BSSDescriptor_t *pReqBSSID;
+    int i;
+
+    ENTER();
+
+    memset(pSSID, 0, sizeof(WLAN_802_11_SSID));
+
+    wlan_scan_networks(priv, NULL);
+
+    i = wlan_find_best_ssid_in_list(Adapter);
+
+    if (i >= 0) {
+
+        pReqBSSID = &Adapter->ScanTable[i];
+        memcpy(pSSID, &pReqBSSID->Ssid, sizeof(WLAN_802_11_SSID));
+
+        /* Make sure we are in the right mode */
+        if (Adapter->InfrastructureMode == Wlan802_11AutoUnknown) {
+            Adapter->InfrastructureMode = pReqBSSID->InfrastructureMode;
+
+            ret = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_802_11_SNMP_MIB,
+                                   HostCmd_ACT_GEN_SET,
+                                   HostCmd_OPTION_WAITFORRSP,
+                                   DesiredBssType_i, NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+        }
+    }
+
+    if (!pSSID->SsidLength) {
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Convert radio type scan paramter to a band config used in join cmd
+ *
+ *  @param radioType Scan parameter indicating the radio used for a channel
+ *                   in a scan command.
+ *
+ *  @return          Band type conversion of scanBand used in join/assoc cmds
+ *
+ */
+static u8
+radio_type_to_band(u8 radioType)
+{
+    u8 retBand;
+
+    switch (radioType) {
+    case HostCmd_SCAN_RADIO_TYPE_A:
+        retBand = BAND_A;
+        break;
+    case HostCmd_SCAN_RADIO_TYPE_BG:
+    default:
+        retBand = BAND_G;
+        break;
+    }
+
+    return retBand;
+}
+
+/**
+ *  @brief Delete a specific indexed entry from the scan table.
+ *
+ *  Delete the scan table entry indexed by tableIdx.  Compact the remaining
+ *    entries and adjust any buffering of beacon/probe response data
+ *    if needed.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param tableIdx   Scan table entry index to delete from the table
+ *
+ *  @return           void
+ *
+ *  @pre              tableIdx must be an index to a valid entry
+ */
+static void
+wlan_scan_delete_table_entry(wlan_private * priv, int tableIdx)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int delIdx;
+    uint beaconBufAdj;
+    u8 *pBeaconBuf;
+
+    /* Shift the saved beacon buffer data for the scan table back over the
+     *   entry being removed.  Update the end of buffer pointer.  Save the 
+     *   deleted buffer allocation size for pointer adjustments for entries
+     *   compacted after the deleted index.
+     */
+    beaconBufAdj = Adapter->ScanTable[tableIdx].beaconBufSizeMax;
+
+    PRINTM(INFO, "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
+           tableIdx, beaconBufAdj);
+
+    /* Check if the table entry had storage allocated for its beacon */
+    if (beaconBufAdj) {
+        pBeaconBuf = Adapter->ScanTable[tableIdx].pBeaconBuf;
+
+        /* Remove the entry's buffer space, decrement the table end pointer
+         *   by the amount we are removing 
+         */
+        Adapter->pBeaconBufEnd -= beaconBufAdj;
+
+        PRINTM(INFO,
+               "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
+               tableIdx,
+               pBeaconBuf,
+               pBeaconBuf + beaconBufAdj,
+               Adapter->pBeaconBufEnd - pBeaconBuf);
+
+        /* Compact data storage.  Copy all data after the deleted entry's
+         *   end address (pBeaconBuf + beaconBufAdj) back to the original
+         *   start address (pBeaconBuf).
+         *
+         * Scan table entries affected by the move will have their entry
+         *   pointer adjusted below.
+         *
+         * Use memmove since the dest/src memory regions overlap.
+         */
+        memmove(pBeaconBuf,
+                pBeaconBuf + beaconBufAdj,
+                Adapter->pBeaconBufEnd - pBeaconBuf);
+    }
+
+    PRINTM(INFO, "Scan: Delete Entry %d, NumInScanTable = %d\n",
+           tableIdx, Adapter->NumInScanTable);
+
+    /* Shift all of the entries after the tableIdx back by one, compacting
+     *   the table and removing the requested entry
+     */
+    for (delIdx = tableIdx; (delIdx + 1) < Adapter->NumInScanTable; delIdx++) {
+        /* Copy the next entry over this one */
+        memcpy(Adapter->ScanTable + delIdx,
+               Adapter->ScanTable + delIdx + 1, sizeof(BSSDescriptor_t));
+
+        /* Adjust this entry's pointer to its beacon buffer based on the 
+         *   removed/compacted entry from the deleted index.  Don't decrement
+         *   if the buffer pointer is NULL (no data stored for this entry).
+         */
+        if (Adapter->ScanTable[delIdx].pBeaconBuf) {
+            Adapter->ScanTable[delIdx].pBeaconBuf -= beaconBufAdj;
+            if (Adapter->ScanTable[delIdx].pWpaIE) {
+                Adapter->ScanTable[delIdx].pWpaIE =
+                    (IEEEtypes_VendorSpecific_t *)
+                    (Adapter->ScanTable[delIdx].pBeaconBuf +
+                     Adapter->ScanTable[delIdx].wpaOffset);
+            }
+            if (Adapter->ScanTable[delIdx].pRsnIE) {
+                Adapter->ScanTable[delIdx].pRsnIE = (IEEEtypes_Generic_t *)
+                    (Adapter->ScanTable[delIdx].pBeaconBuf +
+                     Adapter->ScanTable[delIdx].rsnOffset);
+            }
+            if (Adapter->ScanTable[delIdx].pWpsIE) {
+                Adapter->ScanTable[delIdx].pWpsIE =
+                    (IEEEtypes_VendorSpecific_t *)
+                    (Adapter->ScanTable[delIdx].pBeaconBuf +
+                     Adapter->ScanTable[delIdx].wpsOffset);
+            }
+        }
+    }
+
+    /* The last entry is invalid now that it has been deleted or moved back */
+    memset(Adapter->ScanTable + Adapter->NumInScanTable - 1,
+           0x00, sizeof(BSSDescriptor_t));
+
+    Adapter->NumInScanTable--;
+}
+
+/**
+ *  @brief Delete all occurrences of a given SSID from the scan table
+ *
+ *  Iterate through the scan table and delete all entries that match a given
+ *    SSID.  Compact the remaining scan table entries.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param pDelSSID   Pointer to an SSID struct to use in deleting all
+ *                    matching SSIDs from the scan table
+ *
+ *  @return           WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ */
+static int
+wlan_scan_delete_ssid_table_entry(wlan_private * priv,
+                                  WLAN_802_11_SSID * pDelSSID)
+{
+    int tableIdx;
+    int retval = WLAN_STATUS_FAILURE;
+
+    ENTER();
+
+    PRINTM(INFO, "Scan: Delete Ssid Entry: %-32s\n", pDelSSID->Ssid);
+
+    /* If the requested SSID is found in the table, delete it.  Then keep
+     *   searching the table for multiple entires for the SSID until no
+     *   more are found 
+     */
+    while ((tableIdx = wlan_find_ssid_in_list(priv->adapter,
+                                              pDelSSID,
+                                              NULL,
+                                              Wlan802_11AutoUnknown)) >= 0) {
+        PRINTM(INFO, "Scan: Delete Ssid Entry: Found Idx = %d\n", tableIdx);
+        retval = WLAN_STATUS_SUCCESS;
+        wlan_scan_delete_table_entry(priv, tableIdx);
+    }
+
+    LEAVE();
+
+    return retval;
+}
+
+/**
+ *  @brief Scan Network
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param vwrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_scan(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    union iwreq_data wrqu;
+#if WIRELESS_EXT >= 18
+    struct iw_scan_req *req;
+    struct iw_point *dwrq = (struct iw_point *) vwrq;
+    wlan_ioctl_user_scan_cfg scanCfg;
+#endif
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_set_scan\n");
+        return -EBUSY;
+    }
+#endif
+#if WIRELESS_EXT >= 18
+    if ((dwrq->flags & IW_SCAN_THIS_ESSID) &&
+        (dwrq->length == sizeof(struct iw_scan_req))) {
+        req = (struct iw_scan_req *) extra;
+        if (req->essid_len <= MRVDRV_MAX_SSID_LENGTH) {
+            memset(&scanCfg, 0x00, sizeof(scanCfg));
+            memcpy(scanCfg.ssidList[0].ssid, (u8 *) req->essid,
+                   req->essid_len);
+            if (!wlan_scan_networks(priv, &scanCfg)) {
+                memset(&wrqu, 0, sizeof(union iwreq_data));
+                wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                    NULL);
+            }
+        }
+    } else {
+#endif
+        if (!wlan_scan_networks(priv, NULL)) {
+            memset(&wrqu, 0, sizeof(union iwreq_data));
+            wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+                                NULL);
+        }
+#if WIRELESS_EXT >= 18
+    }
+#endif
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+
+    if (Adapter->SurpriseRemoved)
+        return WLAN_STATUS_FAILURE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Send a scan command for all available channels filtered on a spec
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param pRequestedSSID   A pointer to AP's ssid
+ *
+ *  @return                WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+wlan_cmd_specific_scan_ssid(wlan_private * priv,
+                            WLAN_802_11_SSID * pRequestedSSID)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_user_scan_cfg scanCfg;
+
+    ENTER();
+
+    if (pRequestedSSID == NULL) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    wlan_scan_delete_ssid_table_entry(priv, pRequestedSSID);
+
+    memset(&scanCfg, 0x00, sizeof(scanCfg));
+
+    memcpy(scanCfg.ssidList[0].ssid,
+           pRequestedSSID->Ssid, pRequestedSSID->SsidLength);
+    scanCfg.keepPreviousScan = TRUE;
+
+    wlan_scan_networks(priv, &scanCfg);
+
+    if (Adapter->SurpriseRemoved)
+        return WLAN_STATUS_FAILURE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief scan an AP with specific BSSID
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param bssid     A pointer to AP's bssid
+ *
+ *  @return          WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+int
+wlan_cmd_specific_scan_bssid(wlan_private * priv, u8 * bssid)
+{
+    wlan_ioctl_user_scan_cfg scanCfg;
+
+    ENTER();
+
+    if (bssid == NULL) {
+        return WLAN_STATUS_FAILURE;
+    }
+
+    memset(&scanCfg, 0x00, sizeof(scanCfg));
+    memcpy(scanCfg.specificBSSID, bssid, sizeof(scanCfg.specificBSSID));
+    scanCfg.keepPreviousScan = TRUE;
+
+    wlan_scan_networks(priv, &scanCfg);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_scan(struct net_device *dev, struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    char *current_ev = extra;
+    char *end_buf = extra + IW_SCAN_MAX_DATA;
+    CHANNEL_FREQ_POWER *cfp;
+    BSSDescriptor_t *pScanTable;
+    char *current_val;          /* For rates */
+    struct iw_event iwe;        /* Temporary buffer */
+    int i;
+    int j;
+
+    u8 buf[16 + 256 * 2];
+    u8 *ptr;
+    u8 *pRawData;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        return -EBUSY;
+    }
+
+    if (dwrq->length)
+        end_buf = extra + dwrq->length;
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        PRINTM(INFO, "Current Ssid: %-32s\n",
+               Adapter->CurBssParams.BSSDescriptor.Ssid.Ssid);
+    }
+
+    PRINTM(INFO, "Scan: Get: NumInScanTable = %d\n", Adapter->NumInScanTable);
+
+#if WIRELESS_EXT > 13
+    /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
+     * The new API using SIOCGIWSCAN is only limited by buffer size
+     * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
+     * which is 4096.
+     */
+    for (i = 0; i < Adapter->NumInScanTable; i++) {
+        if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+            PRINTM(INFO, "i=%d break out: current_ev=%p end_buf=%p "
+                   "MAX_SCAN_CELL_SIZE=%d\n",
+                   i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+            ret = -E2BIG;
+            break;
+        }
+
+        pScanTable = &Adapter->ScanTable[i];
+
+        PRINTM(INFO, "i=%d  Ssid: %-32s\n", i, pScanTable->Ssid.Ssid);
+
+        cfp = find_cfp_by_band_and_channel(Adapter,
+                                           pScanTable->bss_band,
+                                           (u16) pScanTable->Channel);
+        if (!cfp) {
+            PRINTM(INFO, "Invalid channel number %d\n", pScanTable->Channel);
+            continue;
+        }
+
+        if (ssid_valid(&Adapter->ScanTable[i].Ssid) == FALSE) {
+            continue;
+        }
+
+        /* First entry *MUST* be the AP MAC address */
+        iwe.cmd = SIOCGIWAP;
+        iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+        memcpy(iwe.u.ap_addr.sa_data,
+               &Adapter->ScanTable[i].MacAddress, ETH_ALEN);
+
+        iwe.len = IW_EV_ADDR_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        //Add the ESSID
+        iwe.u.data.length = Adapter->ScanTable[i].Ssid.SsidLength;
+
+        if (iwe.u.data.length > 32) {
+            iwe.u.data.length = 32;
+        }
+
+        iwe.cmd = SIOCGIWESSID;
+        iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX;
+        iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                          (s8 *) Adapter->ScanTable[i].Ssid.
+                                          Ssid);
+
+        //Add mode
+        iwe.cmd = SIOCGIWMODE;
+        if (Adapter->ScanTable[i].InfrastructureMode == Wlan802_11IBSS)
+            iwe.u.mode = IW_MODE_ADHOC;
+        else if (Adapter->ScanTable[i].InfrastructureMode ==
+                 Wlan802_11Infrastructure)
+            iwe.u.mode = IW_MODE_MASTER;
+        else
+            iwe.u.mode = IW_MODE_AUTO;
+
+        iwe.len = IW_EV_UINT_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        //frequency
+        iwe.cmd = SIOCGIWFREQ;
+        iwe.u.freq.m = (long) cfp->Freq * 100000;
+        iwe.u.freq.e = 1;
+        iwe.len = IW_EV_FREQ_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        /* Add quality statistics */
+        iwe.cmd = IWEVQUAL;
+        iwe.u.qual.level = SCAN_RSSI(Adapter->ScanTable[i].Rssi);
+        iwe.u.qual.qual = 0;
+        if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+            iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+        } else {
+            iwe.u.qual.noise = CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+        }
+        if ((Adapter->InfrastructureMode == Wlan802_11IBSS) &&
+            !wlan_ssid_cmp(&Adapter->CurBssParams.BSSDescriptor.Ssid,
+                           &Adapter->ScanTable[i].Ssid)
+            && Adapter->AdhocState == ADHOC_STARTED) {
+            ret = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_802_11_RSSI,
+                                   0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+            iwe.u.qual.level =
+                CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                         Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+        }
+
+        iwe.len = IW_EV_QUAL_LEN;
+        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+        /* Add encryption capability */
+        iwe.cmd = SIOCGIWENCODE;
+        if (Adapter->ScanTable[i].Privacy) {
+            iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+        } else {
+            iwe.u.data.flags = IW_ENCODE_DISABLED;
+        }
+        iwe.u.data.length = 0;
+        iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
+
+        current_val = current_ev + IW_EV_LCP_LEN;
+
+        iwe.cmd = SIOCGIWRATE;
+
+        iwe.u.bitrate.fixed = 0;
+        iwe.u.bitrate.disabled = 0;
+        iwe.u.bitrate.value = 0;
+
+        /* Bit rate given in 500 kb/s units (+ 0x80) */
+        for (j = 0; j < sizeof(Adapter->ScanTable[i].SupportedRates); j++) {
+            if (Adapter->ScanTable[i].SupportedRates[j] == 0) {
+                break;
+            }
+
+            iwe.u.bitrate.value = (Adapter->ScanTable[i].SupportedRates[j]
+                                   & 0x7f) * 500000;
+            iwe.len = IW_EV_PARAM_LEN;
+            current_val =
+                iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+                                     iwe.len);
+
+        }
+        if ((Adapter->ScanTable[i].InfrastructureMode == Wlan802_11IBSS) &&
+            !wlan_ssid_cmp(&Adapter->CurBssParams.BSSDescriptor.Ssid,
+                           &Adapter->ScanTable[i].Ssid)
+            && Adapter->AdhocState == ADHOC_STARTED) {
+            iwe.u.bitrate.value = 22 * 500000;
+            iwe.len = IW_EV_PARAM_LEN;
+            current_val =
+                iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+                                     iwe.len);
+        }
+
+        /* Check if an event is added */
+        if ((current_val - current_ev) > IW_EV_PARAM_LEN)
+            current_ev = current_val;
+
+        /* Beacon Interval */
+        memset(&iwe, 0, sizeof(iwe));
+        memset(buf, 0, sizeof(buf));
+        ptr = buf;
+        ptr +=
+            sprintf(ptr, "Beacon interval=%d",
+                    Adapter->ScanTable[i].BeaconPeriod);
+
+        iwe.u.data.length = strlen(buf);
+        iwe.cmd = IWEVCUSTOM;
+        iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+        current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+
+        if (Adapter->ScanTable[i].pRsnIE) {
+            if ((*(Adapter->ScanTable[i].pRsnIE)).IeeeHdr.ElementId == RSN_IE) {
+                pRawData = (u8 *) Adapter->ScanTable[i].pRsnIE;
+                memset(&iwe, 0, sizeof(iwe));
+                memset(buf, 0, sizeof(buf));
+                ptr = buf;
+#if WIRELESS_EXT >= 18
+                memcpy(buf, pRawData,
+                       (*(Adapter->ScanTable[i].pRsnIE)).IeeeHdr.Len + 2);
+                iwe.cmd = IWEVGENIE;
+                iwe.u.data.length =
+                    (*(Adapter->ScanTable[i].pRsnIE)).IeeeHdr.Len + 2;
+#else
+                ptr += sprintf(ptr, "rsn_ie=");
+
+                for (j = 0;
+                     j < ((*(Adapter->ScanTable[i].pRsnIE)).IeeeHdr.Len
+                          + sizeof(IEEEtypes_Header_t)); j++) {
+                    ptr += sprintf(ptr, "%02x", *(pRawData + j));
+                }
+                iwe.u.data.length = strlen(buf);
+
+                PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+                PRINTM(INFO, "WPA2 BUF: %s \n", buf);
+                iwe.cmd = IWEVCUSTOM;
+#endif
+                iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+                current_ev =
+                    iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+                current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+            }
+        }
+        if (Adapter->ScanTable[i].pWpaIE) {
+            if ((*(Adapter->ScanTable[i].pWpaIE)).VendHdr.ElementId == WPA_IE) {
+                pRawData = (u8 *) Adapter->ScanTable[i].pWpaIE;
+                memset(&iwe, 0, sizeof(iwe));
+                memset(buf, 0, sizeof(buf));
+                ptr = buf;
+#if WIRELESS_EXT >= 18
+                memcpy(buf, pRawData,
+                       (*(Adapter->ScanTable[i].pWpaIE)).VendHdr.Len + 2);
+                iwe.cmd = IWEVGENIE;
+                iwe.u.data.length =
+                    (*(Adapter->ScanTable[i].pWpaIE)).VendHdr.Len + 2;
+#else
+                ptr += sprintf(ptr, "wpa_ie=");
+
+                for (j = 0;
+                     j < ((*(Adapter->ScanTable[i].pWpaIE)).VendHdr.Len
+                          + sizeof(IEEEtypes_Header_t)); j++) {
+                    ptr += sprintf(ptr, "%02x", *(pRawData + j));
+                }
+                iwe.u.data.length = strlen(buf);
+
+                PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+                PRINTM(INFO, "WPA BUF: %s \n", buf);
+
+                iwe.cmd = IWEVCUSTOM;
+#endif
+                iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+                current_ev =
+                    iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+                current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+            }
+        }
+        if (Adapter->ScanTable[i].pWpsIE) {
+            if ((*(Adapter->ScanTable[i].pWpsIE)).VendHdr.ElementId == WPS_IE) {
+                pRawData = (u8 *) Adapter->ScanTable[i].pWpsIE;
+                memset(&iwe, 0, sizeof(iwe));
+                memset(buf, 0, sizeof(buf));
+                ptr = buf;
+                ptr += sprintf(ptr, "wps_ie=");
+
+                for (j = 0;
+                     j < ((*(Adapter->ScanTable[i].pWpsIE)).VendHdr.Len
+                          + sizeof(IEEEtypes_Header_t)); j++) {
+                    ptr += sprintf(ptr, "%02x", *(pRawData + j));
+                }
+                iwe.u.data.length = strlen(buf);
+
+                PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+                PRINTM(INFO, "WPS BUF: %s \n", buf);
+
+                iwe.cmd = IWEVCUSTOM;
+                iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+                current_ev =
+                    iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+                current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+            }
+        }
+
+        if (Adapter->ScanTable[i].wmmIE.VendHdr.ElementId == WMM_IE) {
+            pRawData = (u8 *) & Adapter->ScanTable[i].wmmIE;
+            memset(&iwe, 0, sizeof(iwe));
+            memset(buf, 0, sizeof(buf));
+            ptr = buf;
+            ptr += sprintf(ptr, "wmm_ie=");
+
+            for (j = 0;
+                 j < (Adapter->ScanTable[i].wmmIE.VendHdr.Len
+                      + sizeof(IEEEtypes_Header_t)); j++) {
+                ptr += sprintf(ptr, "%02x", *(pRawData + j));
+            }
+            iwe.u.data.length = strlen(buf);
+
+            PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+            PRINTM(INFO, "WMM BUF: %s \n", buf);
+
+            iwe.cmd = IWEVCUSTOM;
+            iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+            current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+            current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+        }
+#if WIRELESS_EXT > 14
+        memset(&iwe, 0, sizeof(iwe));
+        memset(buf, 0, sizeof(buf));
+        ptr = buf;
+        ptr += sprintf(ptr, "band=");
+
+        memset(&iwe, 0, sizeof(iwe));
+
+        if (Adapter->ScanTable[i].bss_band == BAND_A) {
+            ptr += sprintf(ptr, "a");
+        } else {
+            ptr += sprintf(ptr, "bg");
+        }
+
+        iwe.u.data.length = strlen(buf);
+
+        PRINTM(INFO, "iwe.u.data.length %d\n", iwe.u.data.length);
+        PRINTM(INFO, "BUF: %s \n", buf);
+
+        iwe.cmd = IWEVCUSTOM;
+        iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+        current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+        current_val = current_ev + IW_EV_LCP_LEN + strlen(buf);
+#endif
+
+        current_val = current_ev + IW_EV_LCP_LEN;
+
+        /*
+         * Check if we added any event
+         */
+        if ((current_val - current_ev) > IW_EV_LCP_LEN)
+            current_ev = current_val;
+    }
+
+    dwrq->length = (current_ev - extra);
+    dwrq->flags = 0;
+
+    LEAVE();
+#endif
+    return ret;
+}
+
+/** 
+ *  @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS 
+ *         Descriptor for inclusion in the ioctl response to the user space
+ *         application.
+ *
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param pBSSDesc  Pointer to a BSS entry in the scan table to form
+ *                   scan response from for delivery to the application layer
+ *  @param ppBuffer  Output parameter: Buffer used to output scan return struct
+ *  @param pSpaceLeft Output parameter: Number of bytes available in the 
+ *                    response buffer.
+ *
+ *  @return WLAN_STATUS_SUCCESS, or < 0 with IOCTL error code
+ */
+static int
+wlan_get_scan_table_ret_entry(wlan_private * priv,
+                              BSSDescriptor_t * pBSSDesc,
+                              u8 ** ppBuffer, int *pSpaceLeft)
+{
+    wlan_adapter *Adapter;
+    wlan_ioctl_get_scan_table_entry *pRspEntry;
+    wlan_ioctl_get_scan_table_entry tmpRspEntry;
+    int spaceNeeded;
+    u8 *pCurrent;
+    int variableSize;
+
+    const int fixedSize = (sizeof(tmpRspEntry.fixedFieldLength)
+                           + sizeof(tmpRspEntry.fixedFields)
+                           + sizeof(tmpRspEntry.bssInfoLength));
+
+    ENTER();
+
+    Adapter = priv->adapter;
+    pCurrent = *ppBuffer;
+
+    /* The variable size returned is the stored beacon size */
+    variableSize = pBSSDesc->beaconBufSize;
+
+    /* If we stored a beacon and its size was zero, set the variable
+     *  size return value to the size of the brief scan response 
+     *  wlan_scan_create_brief_table_entry creates.  Also used if 
+     *  we are not configured to store beacons in the first place
+     */
+    if (variableSize == 0) {
+        variableSize = pBSSDesc->Ssid.SsidLength + 2;
+        variableSize += (sizeof(pBSSDesc->BeaconPeriod)
+                         + sizeof(pBSSDesc->TimeStamp)
+                         + sizeof(pBSSDesc->Cap));
+        if (pBSSDesc->wmmIE.VendHdr.ElementId == WMM_IE) {
+            variableSize += (sizeof(IEEEtypes_Header_t)
+                             + pBSSDesc->wmmIE.VendHdr.Len);
+        }
+
+        if (pBSSDesc->pWpaIE) {
+            if ((*(pBSSDesc->pWpaIE)).VendHdr.ElementId == WPA_IE) {
+                variableSize += (sizeof(IEEEtypes_Header_t)
+                                 + (*(pBSSDesc->pWpaIE)).VendHdr.Len);
+            }
+        }
+
+        if (pBSSDesc->pRsnIE) {
+            if ((*(pBSSDesc->pRsnIE)).IeeeHdr.ElementId == RSN_IE) {
+                variableSize += (sizeof(IEEEtypes_Header_t)
+                                 + (*(pBSSDesc->pRsnIE)).IeeeHdr.Len);
+            }
+        }
+    }
+
+    spaceNeeded = fixedSize + variableSize;
+
+    PRINTM(INFO, "GetScanTable: need(%d), left(%d)\n",
+           spaceNeeded, *pSpaceLeft);
+
+    if (spaceNeeded >= *pSpaceLeft) {
+        *pSpaceLeft = 0;
+        LEAVE();
+        return -E2BIG;
+    }
+
+    *pSpaceLeft -= spaceNeeded;
+
+    tmpRspEntry.fixedFieldLength = sizeof(pRspEntry->fixedFields);
+
+    memcpy(tmpRspEntry.fixedFields.bssid,
+           pBSSDesc->MacAddress, sizeof(pRspEntry->fixedFields.bssid));
+
+    tmpRspEntry.fixedFields.rssi = pBSSDesc->Rssi;
+    tmpRspEntry.fixedFields.channel = pBSSDesc->Channel;
+    tmpRspEntry.fixedFields.networkTSF = pBSSDesc->networkTSF;
+    tmpRspEntry.bssInfoLength = variableSize;
+
+    /*
+     *  Copy fixed fields to user space
+     */
+    if (copy_to_user(pCurrent, &tmpRspEntry, fixedSize)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    pCurrent += fixedSize;
+
+    if (pBSSDesc->pBeaconBuf) {
+        /*
+         *  Copy variable length elements to user space
+         */
+        if (copy_to_user(pCurrent, pBSSDesc->pBeaconBuf,
+                         pBSSDesc->beaconBufSize)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        pCurrent += pBSSDesc->beaconBufSize;
+    } else {
+        wlan_scan_create_brief_table_entry(&pCurrent, pBSSDesc);
+    }
+
+    *ppBuffer = pCurrent;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Retrieve the scan response/beacon table
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter;
+    BSSDescriptor_t *pBSSDesc;
+    wlan_ioctl_get_scan_table_info *pRspInfo;
+    int retcode;
+    int retlen;
+    int spaceLeft;
+    u8 *pCurrent;
+    u8 *pBufferEnd;
+    u32 scanStart;
+    u32 numScansDone;
+
+    numScansDone = 0;
+    retcode = WLAN_STATUS_SUCCESS;
+    Adapter = priv->adapter;
+
+    if (copy_from_user(&scanStart,
+                       wrq->u.data.pointer, sizeof(scanStart)) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "GetScanTable: copy from user failed\n");
+        return -EFAULT;
+    }
+
+    pRspInfo = (wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer;
+    pCurrent = pRspInfo->scan_table_entry_buffer;
+    pBufferEnd = wrq->u.data.pointer + wrq->u.data.length - 1;
+    spaceLeft = pBufferEnd - pCurrent;
+
+    PRINTM(INFO, "GetScanTable: scanStart req = %d\n", scanStart);
+    PRINTM(INFO, "GetScanTable: length avail = %d\n", wrq->u.data.length);
+
+    if (scanStart == 0) {
+        PRINTM(INFO, "GetScanTable: get current BSS Descriptor\n");
+
+        /* Use to get current association saved descriptor */
+        pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
+
+        retcode = wlan_get_scan_table_ret_entry(priv,
+                                                pBSSDesc,
+                                                &pCurrent, &spaceLeft);
+
+        if (retcode == WLAN_STATUS_SUCCESS) {
+            numScansDone = 1;
+        }
+
+    } else {
+        scanStart--;
+
+        while (spaceLeft
+               && (scanStart + numScansDone < Adapter->NumInScanTable)
+               && (retcode == WLAN_STATUS_SUCCESS)) {
+
+            pBSSDesc = &Adapter->ScanTable[scanStart + numScansDone];
+
+            PRINTM(INFO, "GetScanTable: get current BSS Descriptor [%d]\n",
+                   scanStart + numScansDone);
+
+            retcode = wlan_get_scan_table_ret_entry(priv,
+                                                    pBSSDesc,
+                                                    &pCurrent, &spaceLeft);
+
+            if (retcode == WLAN_STATUS_SUCCESS) {
+                numScansDone++;
+            }
+        }
+    }
+
+    pRspInfo->scanNumber = numScansDone;
+    retlen = pCurrent - (u8 *) wrq->u.data.pointer;
+
+    wrq->u.data.length = retlen;
+
+    /* Return retcode (EFAULT or E2BIG) in the case where no scan results were
+     *   successfully encoded.
+     */
+    return (numScansDone ? WLAN_STATUS_SUCCESS : retcode);
+}
+
+/**
+ *  @brief Update the scan entry TSF timestamps to reflect a new association
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pNewBssDesc  A pointer to the newly associated AP's scan table entry
+ *
+ *  @return             void
+ */
+void
+wlan_scan_update_tsf_timestamps(wlan_private * priv,
+                                BSSDescriptor_t * pNewBssDesc)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int tableIdx;
+    u64 newTsfBase;
+    s64 tsfDelta;
+
+    memcpy(&newTsfBase, pNewBssDesc->TimeStamp, sizeof(newTsfBase));
+
+    tsfDelta = newTsfBase - pNewBssDesc->networkTSF;
+
+    PRINTM(INFO, "TSF: Update TSF timestamps, 0x%016llx -> 0x%016llx\n",
+           pNewBssDesc->networkTSF, newTsfBase);
+
+    for (tableIdx = 0; tableIdx < Adapter->NumInScanTable; tableIdx++) {
+        Adapter->ScanTable[tableIdx].networkTSF += tsfDelta;
+    }
+}
+
+/**
+ *  @brief Private IOCTL entry to perform an app configured immediate scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure containing the
+ *                      wlan_ioctl_user_scan_cfg requesting this scan
+ *
+ *  @return             0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_user_scan_cfg scanReq;
+    int retcode;
+    union iwreq_data wrqu;
+
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&priv->adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_extscan_ioctl\n");
+        return -EBUSY;
+    }
+#endif
+
+    memset(&scanReq, 0x00, sizeof(scanReq));
+
+    if (copy_from_user(&scanReq,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(scanReq))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "SetUserScan: copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        retcode = wlan_scan_networks(priv, &scanReq);
+
+        memset(&wrqu, 0x00, sizeof(union iwreq_data));
+        wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+    }
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&priv->adapter->ReassocSem);
+#endif
+
+    return retcode;
+}
+
+/**
+ *  @brief Prepare a scan command to be sent to the firmware
+ *
+ *  Use the wlan_scan_cmd_config sent to the command processing module in
+ *   the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
+ *   struct to send to firmware.
+ *
+ *  The fixed fields specifying the BSS type and BSSID filters as well as a
+ *   variable number/length of TLVs are sent in the command to firmware.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param cmd        A pointer to HostCmd_DS_COMMAND structure to be sent to
+ *                    firmware with the HostCmd_DS_801_11_SCAN structure
+ *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
+ *                    to set the fields/TLVs for the command sent to firmware
+ *
+ *  @return           WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ *
+ *  @sa wlan_scan_create_channel_list
+ */
+int
+wlan_cmd_802_11_scan(wlan_private * priv,
+                     HostCmd_DS_COMMAND * cmd, void *pdata_buf)
+{
+    HostCmd_DS_802_11_SCAN *pScan = &cmd->params.scan;
+    wlan_scan_cmd_config *pScanCfg;
+
+    ENTER();
+
+    pScanCfg = (wlan_scan_cmd_config *) pdata_buf;
+
+    /* Set fixed field variables in scan command */
+    pScan->BSSType = pScanCfg->bssType;
+    memcpy(pScan->BSSID, pScanCfg->specificBSSID, sizeof(pScan->BSSID));
+    memcpy(pScan->TlvBuffer, pScanCfg->tlvBuffer, pScanCfg->tlvBufferLen);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+    /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+    cmd->Size = wlan_cpu_to_le16(sizeof(pScan->BSSType)
+                                 + sizeof(pScan->BSSID)
+                                 + pScanCfg->tlvBufferLen + S_DS_GEN);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Store a beacon or probe response for a BSS returned in the scan
+ *  
+ *  Store a new scan response or an update for a previous scan response.  New
+ *    entries need to verify that they do not exceed the total amount of 
+ *    memory allocated for the table.
+
+ *  Replacement entries need to take into consideration the amount of space 
+ *    currently allocated for the beacon/probe response and adjust the entry
+ *    as needed.  
+ *
+ *  A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ *    for an entry in case it is a beacon since a probe response for the
+ *    network will by larger per the standard.  This helps to reduce the 
+ *    amount of memory copying to fit a new probe response into an entry 
+ *    already occupied by a network's previously stored beacon.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param beaconIdx  Index in the scan table to store this entry; may be
+ *                    replacing an older duplicate entry for this BSS
+ *  @param numInTable Number of entries currently in the table
+ *  @param pNewBeacon Pointer to the new beacon/probe response to save
+ *
+ *  @return           void
+ */
+void
+wlan_ret_802_11_scan_store_beacon(wlan_private * priv,
+                                  int beaconIdx,
+                                  int numInTable,
+                                  BSSDescriptor_t * pNewBeacon)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u8 *pBcnStore;
+    int newBcnSize;
+    int oldBcnSize;
+    int bcnSpace;
+    int adjIdx;
+
+    if (Adapter->ScanTable[beaconIdx].pBeaconBuf != NULL) {
+
+        newBcnSize = pNewBeacon->beaconBufSize;
+        oldBcnSize = Adapter->ScanTable[beaconIdx].beaconBufSize;
+        bcnSpace = Adapter->ScanTable[beaconIdx].beaconBufSizeMax;
+        pBcnStore = Adapter->ScanTable[beaconIdx].pBeaconBuf;
+
+        /* Set the max to be the same as current entry unless changed below */
+        pNewBeacon->beaconBufSizeMax = bcnSpace;
+
+        if (newBcnSize == oldBcnSize) {
+            /*
+             * Beacon is the same size as the previous entry.
+             *   Replace the previous contents with the scan result
+             */
+            memcpy(pBcnStore,
+                   pNewBeacon->pBeaconBuf, pNewBeacon->beaconBufSize);
+
+        } else if (newBcnSize <= bcnSpace) {
+            /*
+             * New beacon size will fit in the amount of space
+             *   we have previously allocated for it
+             */
+
+            /* Copy the new beacon buffer entry over the old one */
+            memcpy(pBcnStore, pNewBeacon->pBeaconBuf, newBcnSize);
+
+            /* If the old beacon size was less than the maximum
+             *  we had alloted for the entry, and the new entry
+             *  is even smaller, reset the max size to the old beacon
+             *  entry and compress the storage space (leaving a new
+             *  pad space of (oldBcnSize - newBcnSize).
+             */
+            if (oldBcnSize < bcnSpace && newBcnSize != bcnSpace) {
+                /*
+                 * Old Beacon size is smaller than the alloted storage size.
+                 *   Shrink the alloted storage space.
+                 */
+                PRINTM(INFO, "AppControl: Smaller Duplicate Beacon (%d), "
+                       "old = %d, new = %d, space = %d, left = %d\n",
+                       beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
+                       (sizeof(Adapter->beaconBuffer) -
+                        (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+                /* memmove (since the memory overlaps) the data
+                 *  after the beacon we just stored to the end of
+                 *  the current beacon.  This cleans up any unused
+                 *  space the old larger beacon was using in the buffer
+                 */
+                memmove(pBcnStore + oldBcnSize,
+                        pBcnStore + bcnSpace,
+                        Adapter->pBeaconBufEnd - (pBcnStore + bcnSpace));
+
+                /* Decrement the end pointer by the difference between
+                 *  the old larger size and the new smaller size since
+                 *  we are using less space due to the new beacon being
+                 *  smaller
+                 */
+                Adapter->pBeaconBufEnd -= (bcnSpace - oldBcnSize);
+
+                /* Set the maximum storage size to the old beacon size */
+                pNewBeacon->beaconBufSizeMax = oldBcnSize;
+
+                /* Adjust beacon buffer pointers that are past the current */
+                for (adjIdx = 0; adjIdx < numInTable; adjIdx++) {
+                    if (Adapter->ScanTable[adjIdx].pBeaconBuf > pBcnStore) {
+                        Adapter->ScanTable[adjIdx].pBeaconBuf
+                            -= (bcnSpace - oldBcnSize);
+                        if (Adapter->ScanTable[adjIdx].pWpaIE) {
+                            Adapter->ScanTable[adjIdx].pWpaIE =
+                                (IEEEtypes_VendorSpecific_t *)
+                                (Adapter->ScanTable[adjIdx].pBeaconBuf +
+                                 Adapter->ScanTable[adjIdx].wpaOffset);
+                        }
+                        if (Adapter->ScanTable[adjIdx].pRsnIE) {
+                            Adapter->ScanTable[adjIdx].pRsnIE =
+                                (IEEEtypes_Generic_t *)
+                                (Adapter->ScanTable[adjIdx].pBeaconBuf +
+                                 Adapter->ScanTable[adjIdx].rsnOffset);
+                        }
+                        if (Adapter->ScanTable[adjIdx].pWpsIE) {
+                            Adapter->ScanTable[adjIdx].pWpsIE =
+                                (IEEEtypes_VendorSpecific_t *)
+                                (Adapter->ScanTable[adjIdx].pBeaconBuf +
+                                 Adapter->ScanTable[adjIdx].wpsOffset);
+                        }
+                    }
+                }
+            }
+        } else if (Adapter->pBeaconBufEnd + (newBcnSize - bcnSpace)
+                   < (Adapter->beaconBuffer + sizeof(Adapter->beaconBuffer))) {
+            /*
+             * Beacon is larger than space previously allocated (bcnSpace)
+             *   and there is enough space left in the beaconBuffer to store
+             *   the additional data
+             */
+            PRINTM(INFO, "AppControl: Larger Duplicate Beacon (%d), "
+                   "old = %d, new = %d, space = %d, left = %d\n",
+                   beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+            /* memmove (since the memory overlaps) the data
+             *  after the beacon we just stored to the end of
+             *  the current beacon.  This moves the data for
+             *  the beacons after this further in memory to
+             *  make space for the new larger beacon we are
+             *  about to copy in.
+             */
+            memmove(pBcnStore + newBcnSize,
+                    pBcnStore + bcnSpace,
+                    Adapter->pBeaconBufEnd - (pBcnStore + bcnSpace));
+
+            /* Copy the new beacon buffer entry over the old one */
+            memcpy(pBcnStore, pNewBeacon->pBeaconBuf, newBcnSize);
+
+            /* Move the beacon end pointer by the amount of new
+             *  beacon data we are adding
+             */
+            Adapter->pBeaconBufEnd += (newBcnSize - bcnSpace);
+
+            /* This entry is bigger than the alloted max space
+             *  previously reserved.  Increase the max space to
+             *  be equal to the new beacon size
+             */
+            pNewBeacon->beaconBufSizeMax = newBcnSize;
+
+            /* Adjust beacon buffer pointers that are past the current */
+            for (adjIdx = 0; adjIdx < numInTable; adjIdx++) {
+                if (Adapter->ScanTable[adjIdx].pBeaconBuf > pBcnStore) {
+                    Adapter->ScanTable[adjIdx].pBeaconBuf
+                        += (newBcnSize - bcnSpace);
+                    if (Adapter->ScanTable[adjIdx].pWpaIE) {
+                        Adapter->ScanTable[adjIdx].pWpaIE =
+                            (IEEEtypes_VendorSpecific_t *)
+                            (Adapter->ScanTable[adjIdx].pBeaconBuf +
+                             Adapter->ScanTable[adjIdx].wpaOffset);
+                    }
+                    if (Adapter->ScanTable[adjIdx].pRsnIE) {
+                        Adapter->ScanTable[adjIdx].pRsnIE =
+                            (IEEEtypes_Generic_t *)
+                            (Adapter->ScanTable[adjIdx].pBeaconBuf +
+                             Adapter->ScanTable[adjIdx].rsnOffset);
+                    }
+                    if (Adapter->ScanTable[adjIdx].pWpsIE) {
+                        Adapter->ScanTable[adjIdx].pWpsIE =
+                            (IEEEtypes_VendorSpecific_t *)
+                            (Adapter->ScanTable[adjIdx].pBeaconBuf +
+                             Adapter->ScanTable[adjIdx].wpsOffset);
+                    }
+                }
+            }
+        } else {
+            /*
+             * Beacon is larger than the previously allocated space, but
+             *   there is not enough free space to store the additional data
+             */
+            PRINTM(INFO,
+                   "AppControl: Failed: Larger Duplicate Beacon (%d),"
+                   " old = %d, new = %d, space = %d, left = %d\n",
+                   beaconIdx, oldBcnSize, newBcnSize, bcnSpace,
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+            /* Storage failure, keep old beacon intact */
+            pNewBeacon->beaconBufSize = oldBcnSize;
+        }
+
+        /* Point the new entry to its permanent storage space */
+        pNewBeacon->pBeaconBuf = pBcnStore;
+        if (pNewBeacon->pWpaIE != NULL) {
+            pNewBeacon->pWpaIE = (IEEEtypes_VendorSpecific_t *)
+                (pNewBeacon->pBeaconBuf + pNewBeacon->wpaOffset);
+        }
+        if (pNewBeacon->pRsnIE != NULL) {
+            pNewBeacon->pRsnIE = (IEEEtypes_Generic_t *)
+                (pNewBeacon->pBeaconBuf + pNewBeacon->rsnOffset);
+        }
+        if (pNewBeacon->pWpsIE != NULL) {
+            pNewBeacon->pWpsIE = (IEEEtypes_VendorSpecific_t *)
+                (pNewBeacon->pBeaconBuf + pNewBeacon->wpsOffset);
+        }
+
+    } else {
+        /* No existing beacon data exists for this entry, check to see
+         *   if we can fit it in the remaining space
+         */
+        if (Adapter->pBeaconBufEnd + pNewBeacon->beaconBufSize +
+            SCAN_BEACON_ENTRY_PAD < (Adapter->beaconBuffer +
+                                     sizeof(Adapter->beaconBuffer))) {
+
+            /* Copy the beacon buffer data from the local entry to the
+             *   adapter dev struct buffer space used to store the raw
+             *   beacon data for each entry in the scan table
+             */
+            memcpy(Adapter->pBeaconBufEnd, pNewBeacon->pBeaconBuf,
+                   pNewBeacon->beaconBufSize);
+
+            /* Update the beacon ptr to point to the table save area */
+            pNewBeacon->pBeaconBuf = Adapter->pBeaconBufEnd;
+            pNewBeacon->beaconBufSizeMax = (pNewBeacon->beaconBufSize
+                                            + SCAN_BEACON_ENTRY_PAD);
+
+            if (pNewBeacon->pWpaIE != NULL) {
+                pNewBeacon->pWpaIE = (IEEEtypes_VendorSpecific_t *)
+                    (pNewBeacon->pBeaconBuf + pNewBeacon->wpaOffset);
+            }
+            if (pNewBeacon->pRsnIE != NULL) {
+                pNewBeacon->pRsnIE = (IEEEtypes_Generic_t *)
+                    (pNewBeacon->pBeaconBuf + pNewBeacon->rsnOffset);
+            }
+            if (pNewBeacon->pWpsIE != NULL) {
+                pNewBeacon->pWpsIE = (IEEEtypes_VendorSpecific_t *)
+                    (pNewBeacon->pBeaconBuf + pNewBeacon->wpsOffset);
+            }
+            /* Increment the end pointer by the size reserved */
+            Adapter->pBeaconBufEnd += pNewBeacon->beaconBufSizeMax;
+
+            PRINTM(INFO, "AppControl: Beacon[%02d] sz=%03d,"
+                   " used = %04d, left = %04d\n",
+                   beaconIdx,
+                   pNewBeacon->beaconBufSize,
+                   (Adapter->pBeaconBufEnd - Adapter->beaconBuffer),
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+        } else {
+            /*
+             * No space for new beacon
+             */
+            PRINTM(INFO, "AppControl: No space beacon (%d): "
+                   "%02x:%02x:%02x:%02x:%02x:%02x; sz=%03d, left=%03d\n",
+                   beaconIdx,
+                   pNewBeacon->MacAddress[0], pNewBeacon->MacAddress[1],
+                   pNewBeacon->MacAddress[2], pNewBeacon->MacAddress[3],
+                   pNewBeacon->MacAddress[4], pNewBeacon->MacAddress[5],
+                   pNewBeacon->beaconBufSize,
+                   (sizeof(Adapter->beaconBuffer) -
+                    (Adapter->pBeaconBufEnd - Adapter->beaconBuffer)));
+
+            /* Storage failure; clear storage records for this bcn */
+            pNewBeacon->pBeaconBuf = NULL;
+            pNewBeacon->beaconBufSize = 0;
+            pNewBeacon->beaconBufSizeMax = 0;
+            pNewBeacon->pWpaIE = NULL;
+            pNewBeacon->wpaOffset = 0;
+            pNewBeacon->pRsnIE = NULL;
+            pNewBeacon->rsnOffset = 0;
+            pNewBeacon->pWpsIE = NULL;
+            pNewBeacon->wpsOffset = 0;
+        }
+    }
+}
+
+/**
+ *  @brief This function handles the command response of scan
+ *
+ *   The response buffer for the scan command has the following
+ *      memory layout:
+ *
+ *     .-----------------------------------------------------------.
+ *     |  Header (4 * sizeof(u16)):  Standard command response hdr |
+ *     .-----------------------------------------------------------.
+ *     |  BufSize (u16) : sizeof the BSS Description data          |
+ *     .-----------------------------------------------------------.
+ *     |  NumOfSet (u8) : Number of BSS Descs returned             |
+ *     .-----------------------------------------------------------.
+ *     |  BSSDescription data (variable, size given in BufSize)    |
+ *     .-----------------------------------------------------------.
+ *     |  TLV data (variable, size calculated using Header->Size,  |
+ *     |            BufSize and sizeof the fixed fields above)     |
+ *     .-----------------------------------------------------------.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to HostCmd_DS_COMMAND
+ *
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_ret_802_11_scan(wlan_private * priv, HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_SCAN_RSP *pScan;
+    BSSDescriptor_t newBssEntry;
+    MrvlIEtypes_Data_t *pTlv;
+    MrvlIEtypes_TsfTimestamp_t *pTsfTlv;
+    u8 *pBssInfo;
+    u16 scanRespSize;
+    int bytesLeft;
+    int numInTable;
+    int bssIdx;
+    int idx;
+    int tlvBufSize;
+    u64 tsfVal;
+    ChanScanParamSet_t *pChanScan;
+    u8 band;
+    BOOLEAN bgScanResp;
+
+    ENTER();
+
+    bgScanResp = (resp->Command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
+    if (bgScanResp) {
+        pScan = &resp->params.bgscanqueryresp.scanresp;
+    } else {
+        pScan = &resp->params.scanresp;
+    }
+
+    if (pScan->NumberOfSets > MRVDRV_MAX_BSSID_LIST) {
+        PRINTM(INFO, "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+               pScan->NumberOfSets);
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    bytesLeft = wlan_le16_to_cpu(pScan->BSSDescriptSize);
+    PRINTM(INFO, "SCAN_RESP: BSSDescriptSize %d\n", bytesLeft);
+
+    scanRespSize = resp->Size;
+
+    PRINTM(CMND, "SCAN_RESP: returned %d APs before parsing\n",
+           pScan->NumberOfSets);
+
+    numInTable = Adapter->NumInScanTable;
+    pBssInfo = pScan->BssDescAndTlvBuffer;
+
+    /* The size of the TLV buffer is equal to the entire command response
+     *   size (scanRespSize) minus the fixed fields (sizeof()'s), the
+     *   BSS Descriptions (BSSDescriptSize as bytesLef) and the command
+     *   response header (S_DS_GEN)
+     */
+    tlvBufSize = scanRespSize - (bytesLeft + sizeof(pScan->BSSDescriptSize)
+                                 + sizeof(pScan->NumberOfSets)
+                                 + S_DS_GEN);
+
+    pTlv = (MrvlIEtypes_Data_t *) (pScan->BssDescAndTlvBuffer + bytesLeft);
+
+    /* Search the TLV buffer space in the scan response for any valid TLVs */
+    wlan_ret_802_11_scan_get_tlv_ptrs(pTlv, tlvBufSize, &pTsfTlv);
+
+    /*
+     *  Process each scan response returned (pScan->NumberOfSets).  Save
+     *    the information in the newBssEntry and then insert into the
+     *    driver scan table either as an update to an existing entry
+     *    or as an addition at the end of the table
+     */
+    for (idx = 0; idx < pScan->NumberOfSets && bytesLeft; idx++) {
+        /* Zero out the newBssEntry we are about to store info in */
+        memset(&newBssEntry, 0x00, sizeof(newBssEntry));
+
+        /* Process the data fields and IEs returned for this BSS */
+        if ((wlan_interpret_bss_desc_with_ie(&newBssEntry,
+                                             &pBssInfo,
+                                             &bytesLeft) ==
+             WLAN_STATUS_SUCCESS)
+            && CHECK_SSID_IS_VALID(&newBssEntry.Ssid)) {
+
+            PRINTM(INFO, "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   newBssEntry.MacAddress[0], newBssEntry.MacAddress[1],
+                   newBssEntry.MacAddress[2], newBssEntry.MacAddress[3],
+                   newBssEntry.MacAddress[4], newBssEntry.MacAddress[5]);
+
+            /*
+             * Search the scan table for the same bssid
+             */
+            for (bssIdx = 0; bssIdx < numInTable; bssIdx++) {
+                if (memcmp(newBssEntry.MacAddress,
+                           Adapter->ScanTable[bssIdx].MacAddress,
+                           sizeof(newBssEntry.MacAddress)) == 0) {
+                    /*
+                     * If the SSID matches as well, it is a duplicate of
+                     *   this entry.  Keep the bssIdx set to this
+                     *   entry so we replace the old contents in the table
+                     */
+                    if ((newBssEntry.Ssid.SsidLength ==
+                         Adapter->ScanTable[bssIdx].Ssid.SsidLength)
+                        && (memcmp(newBssEntry.Ssid.Ssid,
+                                   Adapter->ScanTable[bssIdx].Ssid.Ssid,
+                                   newBssEntry.Ssid.SsidLength) == 0)) {
+                        PRINTM(INFO, "SCAN_RESP: Duplicate of index: %d\n",
+                               bssIdx);
+                        break;
+                    }
+                }
+            }
+            /*
+             * If the bssIdx is equal to the number of entries in the table,
+             *   the new entry was not a duplicate; append it to the scan
+             *   table
+             */
+            if (bssIdx == numInTable) {
+                /* Range check the bssIdx, keep it limited to the last entry */
+                if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
+                    bssIdx--;
+                } else {
+                    numInTable++;
+                }
+            }
+
+            /*
+             * Save the beacon/probe response returned for later application
+             *   retrieval.  Duplicate beacon/probe responses are updated if
+             *   possible
+             */
+            wlan_ret_802_11_scan_store_beacon(priv,
+                                              bssIdx,
+                                              numInTable, &newBssEntry);
+            /*
+             * If the TSF TLV was appended to the scan results, save
+             *   this entry's TSF value in the networkTSF field.  The
+             *   networkTSF is the firmware's TSF value at the time the
+             *   beacon or probe response was received.
+             */
+            if (pTsfTlv) {
+                memcpy(&tsfVal, &pTsfTlv->tsfTable[idx], sizeof(tsfVal));
+                tsfVal = wlan_le64_to_cpu(tsfVal);
+
+                memcpy(&newBssEntry.networkTSF,
+                       &tsfVal, sizeof(newBssEntry.networkTSF));
+            }
+
+            band = BAND_G;
+            pChanScan = NULL;
+
+            if (bgScanResp) {
+                MrvlIEtypes_ChanListParamSet_t *chanList;
+
+                chanList = (MrvlIEtypes_ChanListParamSet_t *)
+                    ((u8 *) Adapter->bgScanConfig +
+                     sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG));
+
+                while (!pChanScan
+                       && ((u8 *) chanList < ((u8 *) Adapter->bgScanConfig
+                                              + Adapter->bgScanConfigSize))) {
+
+                    PRINTM(INFO, "SCAN_RESP: Header type=%#x  len=%d\n",
+                           chanList->Header.Type, chanList->Header.Len);
+
+                    if (chanList->Header.Type == TLV_TYPE_CHANLIST) {
+                        pChanScan = chanList->ChanScanParam;
+                        break;
+                    } else {
+                        chanList = (MrvlIEtypes_ChanListParamSet_t *)
+                            ((u8 *) chanList + chanList->Header.Len
+                             + sizeof(chanList->Header));
+                    }
+                }
+
+                if (pChanScan) {
+                    band = radio_type_to_band(pChanScan->RadioType);
+                    PRINTM(INFO, "SCAN_RESP: radio_type=%#x, "
+                           "chan=%#x, band=%#x\n", pChanScan->RadioType,
+                           pChanScan->ChanNumber, band);
+                } else {
+                    PRINTM(INFO, "SCAN_RESP: Cannot find valid "
+                           "radio_type/channel info. in channel list\n");
+                }
+            } else {
+                pChanScan = Adapter->pScanChannels;
+
+                /* Search the channel list we sent down in the command
+                 *   for the channel this new entry was found on.
+                 */
+                while (pChanScan && pChanScan->ChanNumber) {
+                    if (pChanScan->ChanNumber == newBssEntry.Channel) {
+                        /*
+                         * Convert the radio type we sent with the channel
+                         *  in the scan command to a band type that can be
+                         *  used in the join commands later
+                         */
+                        band = radio_type_to_band(pChanScan->RadioType);
+                        PRINTM(INFO, "SCAN_RESP: radio_type=%#x, "
+                               "chan=%#x, band=%#x\n", pChanScan->RadioType,
+                               pChanScan->ChanNumber, band);
+
+                        break;
+                    }
+                    pChanScan++;
+                }
+            }
+
+            /* save the band designation for this entry for use in join */
+            newBssEntry.bss_band = band;
+
+            /* Copy the locally created newBssEntry to the scan table */
+            memcpy(&Adapter->ScanTable[bssIdx],
+                   &newBssEntry, sizeof(Adapter->ScanTable[bssIdx]));
+
+        } else {
+
+            /* Error parsing/interpreting the scan response, skipped */
+            PRINTM(INFO, "SCAN_RESP: "
+                   "wlan_interpret_bss_desc_with_ie returned ERROR\n");
+        }
+    }
+
+    PRINTM(CMND, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+           pScan->NumberOfSets, numInTable - Adapter->NumInScanTable,
+           numInTable);
+
+    /* Update the total number of BSSIDs in the scan table */
+    Adapter->NumInScanTable = numInTable;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief scan network with specific ssid
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_extscan_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_SSID Ext_Scan_SSID;
+    wlan_ioctl_user_scan_cfg scanCfg;
+    union iwreq_data wrqu;
+
+    ENTER();
+
+    if (copy_from_user(&Ext_Scan_SSID, req->ifr_data, sizeof(Ext_Scan_SSID))) {
+        PRINTM(INFO, "copy of SSID for ext scan from user failed \n");
+        LEAVE();
+        return -EFAULT;
+    }
+#ifdef REASSOCIATION
+    if (OS_ACQ_SEMAPHORE_BLOCK(&Adapter->ReassocSem)) {
+        PRINTM(ERROR, "Acquire semaphore error, wlan_extscan_ioctl\n");
+        return -EBUSY;
+    }
+#endif
+
+    memset(&scanCfg, 0x00, sizeof(scanCfg));
+
+    memcpy(scanCfg.ssidList[0].ssid, Ext_Scan_SSID.Ssid,
+           Ext_Scan_SSID.SsidLength);
+
+    wlan_scan_networks(priv, &scanCfg);
+
+    memset(&wrqu, 0, sizeof(union iwreq_data));
+    wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+#ifdef REASSOCIATION
+    OS_REL_SEMAPHORE(&Adapter->ReassocSem);
+#endif
+
+    if (Adapter->SurpriseRemoved)
+        return WLAN_STATUS_FAILURE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function sends BG_SCAN query command to firmware.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *
+ *  @return        WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_bgs_query(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* Clear the previous scan result */
+    memset(Adapter->ScanTable, 0x00,
+           sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
+    Adapter->NumInScanTable = 0;
+    Adapter->pBeaconBufEnd = Adapter->beaconBuffer;
+
+    return wlan_prepare_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY,
+                            0, 0, 0, NULL);
+}
+
+/**
+ *  @brief Enable/Disable BG Scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param enable       TRUE-enable, FALSE-disable
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_bg_scan_enable(wlan_private * priv, BOOLEAN enable)
+{
+    int ret;
+
+    priv->adapter->bgScanConfig->Enable = enable;
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                           0, HostCmd_OPTION_WAITFORRSP,
+                           0, priv->adapter->bgScanConfig);
+    return ret;
+}
+
+/**
+ *  @brief config BGSCAN parameter
+
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_do_bg_scan_config_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 action;
+    u8 *buf = NULL;
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *tmp;
+
+    ENTER();
+
+    action = *((u8 *) req->ifr_data + SKIP_CMDNUM + SKIP_SIZE);
+    PRINTM(INFO, "Action = %d\n", action);
+
+    switch (action) {
+    case HostCmd_ACT_GEN_GET:
+        buf = kmalloc(Adapter->bgScanConfigSize + SKIP_TYPE_SIZE, GFP_KERNEL);
+        if (!buf) {
+            PRINTM(MSG, "kmalloc no memory !!\n");
+            return -ENOMEM;
+        }
+        memcpy(buf, &Adapter->bgScanConfigSize, SKIP_SIZE);
+        memcpy(buf + SKIP_TYPE_SIZE, Adapter->bgScanConfig,
+               Adapter->bgScanConfigSize);
+
+        if (copy_to_user(req->ifr_data, buf,
+                         Adapter->bgScanConfigSize + SKIP_TYPE_SIZE)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            kfree(buf);
+            return -EFAULT;
+        }
+
+        kfree(buf);
+
+        break;
+
+    case HostCmd_ACT_GEN_SET:
+        Adapter->bgScanConfigSize = *(u16 *) (req->ifr_data + SKIP_CMDNUM);
+        PRINTM(INFO, "bgscanConfigSize = %d\n", Adapter->bgScanConfigSize);
+
+        if (!(tmp = kmalloc(Adapter->bgScanConfigSize, GFP_KERNEL))) {
+            PRINTM(MSG, "kmalloc no memory !!\n");
+            Adapter->bgScanConfigSize = 0;
+            return -ENOMEM;
+        }
+
+        HEXDUMP("treq", req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
+                Adapter->bgScanConfigSize);
+
+        if (copy_from_user(tmp, req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
+                           Adapter->bgScanConfigSize)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            kfree(tmp);
+            return -EFAULT;
+        }
+
+        if (Adapter->bgScanConfig) {
+            tmp->Enable = Adapter->bgScanConfig->Enable;
+            buf = (u8 *) Adapter->bgScanConfig;
+        }
+        Adapter->bgScanConfig = tmp;
+        if (buf)
+            kfree(buf);
+
+        break;
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief config PPS/UAPSD or normal BGSCAN 
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_do_bgscfg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 action;
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *pstBgScanCfg;
+
+    ENTER();
+    Adapter->bgScanConfigSize = *(u16 *) (req->ifr_data + SKIP_CMDNUM);
+    if (!(pstBgScanCfg = kmalloc(Adapter->bgScanConfigSize, GFP_KERNEL))) {
+        PRINTM(INFO, "Allocate memory failed\n");
+        return -ENOMEM;
+    }
+    memset(pstBgScanCfg, 0, Adapter->bgScanConfigSize);
+
+    if (copy_from_user(pstBgScanCfg, req->ifr_data + SKIP_CMDNUM + SKIP_SIZE,
+                       Adapter->bgScanConfigSize)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(pstBgScanCfg);
+        return -EFAULT;
+    }
+
+    action = (pstBgScanCfg->Action == HostCmd_ACT_GEN_SET) ?
+        HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET;
+
+    HEXDUMP("bgscfg", (u8 *) pstBgScanCfg, Adapter->bgScanConfigSize);
+
+    PRINTM(INFO, "bgscfg action = 0x%0X\n", action);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                           action,
+                           HostCmd_OPTION_WAITFORRSP, 0, pstBgScanCfg);
+
+    if (!ret && action == HostCmd_ACT_GEN_GET) {
+        if (copy_to_user
+            (req->ifr_data + SKIP_CMDNUM + SKIP_SIZE, pstBgScanCfg,
+             MAX_SETGET_CONF_CMD_LEN)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+    }
+
+    kfree(pstBgScanCfg);
+
+    LEAVE();
+
+    return ret;
+}
+
+/**
+ *  @brief This function prepares command of bg_scan_config.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param cmd          A pointer to HostCmd_DS_COMMAND structure
+ *  @param cmd_action   the action: GET or SET
+ *  @param pdata_buf    A pointer to data buffer
+ *
+ *  @return             WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_bg_scan_config(wlan_private * priv,
+                               HostCmd_DS_COMMAND * cmd,
+                               int cmd_action, void *pdata_buf)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *bgcfg = &cmd->params.bgscancfg;
+    HostCmd_DS_802_11_BG_SCAN_CONFIG *pstBgScanCfg =
+        (HostCmd_DS_802_11_BG_SCAN_CONFIG *) pdata_buf;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+    cmd->Size =
+        wlan_cpu_to_le16((priv->adapter->bgScanConfigSize) + S_DS_GEN);
+
+    memcpy(bgcfg, pstBgScanCfg, Adapter->bgScanConfigSize);
+
+    bgcfg->Action = wlan_cpu_to_le16(bgcfg->Action);
+    bgcfg->ScanInterval = wlan_cpu_to_le32(bgcfg->ScanInterval);
+    bgcfg->ReportConditions = wlan_cpu_to_le32(bgcfg->ReportConditions);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief This function prepares command of bg_scan_query.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param cmd      A pointer to HostCmd_DS_COMMAND structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_802_11_bg_scan_query(wlan_private * priv, HostCmd_DS_COMMAND * cmd)
+{
+    HostCmd_DS_802_11_BG_SCAN_QUERY *bgquery = &cmd->params.bgscanquery;
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) + S_DS_GEN);
+
+    bgquery->Flush = 1;
+
+    return WLAN_STATUS_SUCCESS;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_scan.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_scan.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_scan.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_scan.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,427 @@
+/** @file wlan_scan.h
+ *
+ *  @brief Interface for the wlan network scan routines
+ *
+ *  Driver interface functions and type declarations for the scan module
+ *    implemented in wlan_scan.c.
+ *
+ *  (c) Copyright © 2003-2006, Marvell International Ltd.  
+ *   
+ *  This software file (the "File") is distributed by Marvell International 
+ *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ *  (the "License").  You may use, redistribute and/or modify this File in 
+ *  accordance with the terms and conditions of the License, a copy of which 
+ *  is available along with the File in the gpl.txt file or by writing to 
+ *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ *  this warranty disclaimer.
+ *
+ */
+/*************************************************************
+Change Log:
+    01/11/06: Initial revision. New scan code, relocate related functions
+
+************************************************************/
+
+#ifndef _WLAN_SCAN_H
+#define _WLAN_SCAN_H
+
+/**
+ *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+ *  @sa wlan_ioctl_user_scan_cfg
+ */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX  50
+
+//! Infrastructure BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_BSS         1
+
+//! Adhoc BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_IBSS        2
+
+//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+#define WLAN_SCAN_BSS_TYPE_ANY         3
+
+/** @brief Maximum buffer space for beacons retrieved from scan responses
+ *    4000 has successfully stored up to 40 beacons
+ *    6000 has successfully stored the max scan results (max 64)
+ */
+#define MAX_SCAN_BEACON_BUFFER         6000
+
+/**
+ * @brief Buffer pad space for newly allocated beacons/probe responses
+ *
+ * Beacons are typically 6 bytes longer than an equivalent probe response.
+ *  For each scan response stored, allocate an extra byte pad at the end to
+ *  allow easy expansion to store a beacon in the same memory a probe reponse
+ *  previously contained
+ */
+#define SCAN_BEACON_ENTRY_PAD          6
+
+//! Scan time specified in the channel TLV for each channel for passive scans
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME  200
+
+//! Scan time specified in the channel TLV for each channel for active scans
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME   200
+
+//! Scan time specified in the channel TLV for each channel for specific scans
+#define MRVDRV_SPECIFIC_SCAN_CHAN_TIME 110
+
+//! Max passive scan time for each channel in milliseconds
+#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME   2000
+
+//! Max active scan time for each channel in milliseconds 
+#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME    500
+
+/**
+ * Max total scan time in milliseconds
+ * The total scan time should be less than scan command timeout value (10s)
+ */
+#define MRVDRV_MAX_TOTAL_SCAN_TIME     (MRVDRV_TIMER_10S - MRVDRV_TIMER_1S)
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+ *   scan command prepared by wlan_cmd_802_11_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+typedef struct
+{
+    /**
+     *  @brief BSS Type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  Valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+    u8 bssType;
+
+    /**
+     *  @brief Specific BSSID used to filter scan results in the firmware
+     */
+    u8 specificBSSID[ETH_ALEN];
+
+    /**
+     *  @brief Length of TLVs sent in command starting at tlvBuffer
+     */
+    int tlvBufferLen;
+
+    /**
+     *  @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+     *
+     *  @sa TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t
+     *  @sa TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t
+     */
+    u8 tlvBuffer[1];            //!< SSID TLV(s) and ChanList TLVs are stored here
+} wlan_scan_cmd_config;
+
+/**
+ *  @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ *  Multiple instances of this structure are included in the IOCTL command
+ *   to configure a instance of a scan on the specific channel.
+ */
+typedef struct
+{
+    u8 chanNumber;              //!< Channel Number to scan
+    u8 radioType;               //!< Radio type: 'B/G' Band = 0, 'A' Band = 1
+    u8 scanType;                //!< Scan type: Active = 0, Passive = 1
+    u8 reserved;                //!< Reserved
+    u16 scanTime;               //!< Scan duration in milliseconds; if 0 default used
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_chan;
+
+/**
+ *  @brief IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg
+ * 
+ *  Used to specify SSID specific filters as well as SSID pattern matching
+ *    filters for scan result processing in firmware.
+ */
+typedef struct
+{
+    char ssid[MRVDRV_MAX_SSID_LENGTH + 1];      //!< SSID
+    u8 maxLen;                  //!< Maximum length of SSID
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_ssid;
+
+/**
+ *  @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+ *  Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl.  Specifies
+ *   a number of parameters to be used in general for the scan as well
+ *   as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ *   desired.
+ *
+ *  @sa wlan_set_user_scan_ioctl
+ */
+typedef struct
+{
+
+    /**
+     *  @brief Flag set to keep the previous scan table intact
+     *
+     *  If set, the scan results will accumulate, replacing any previous
+     *   matched entries for a BSS with the new scan data
+     */
+    u8 keepPreviousScan;        //!< Do not erase the existing scan results
+
+    /**
+     *  @brief BSS Type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  Valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+    u8 bssType;
+
+    /**
+     *  @brief Configure the number of probe requests for active chan scans
+     */
+    u8 numProbes;
+
+    /**
+     *  @brief Reserved
+     */
+    u8 reserved;
+
+    /**
+     *  @brief BSSID filter sent in the firmware command to limit the results
+     */
+    u8 specificBSSID[ETH_ALEN];
+
+    /**
+     *  @brief SSID filter list used in the to limit the scan results
+     */
+    wlan_ioctl_user_scan_ssid ssidList[MRVDRV_MAX_SSID_LIST_LENGTH];
+
+    /**
+     *  @brief Variable number (fixed maximum) of channels to scan up
+     */
+    wlan_ioctl_user_scan_chan chanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+
+} __ATTRIB_PACK__ wlan_ioctl_user_scan_cfg;
+
+/**
+ *  @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS
+ *
+ *  Fixed field information returned for the scan response in the IOCTL
+ *    response.
+ */
+typedef struct
+{
+    u8 bssid[ETH_ALEN];         //!< BSSID of this network
+    u8 channel;                 //!< Channel this beacon/probe response was detected
+    u8 rssi;                    //!< RSSI for the received packet
+    u64 networkTSF;             //!< TSF value from the firmware at packet reception
+} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_fixed;
+
+/**
+ *  @brief Structure passed in the wlan_ioctl_get_scan_table_info for each
+ *         BSS returned in the WLAN_GET_SCAN_RESP IOCTL
+ *
+ *  @sa wlan_get_scan_table_ioctl
+ */
+typedef struct
+{
+
+    /**
+     *  @brief Fixed field length included in the response.
+     *
+     *  Length value is included so future fixed fields can be added to the
+     *   response without breaking backwards compatibility.  Use the length
+     *   to find the offset for the bssInfoLength field, not a sizeof() calc.
+     */
+    u32 fixedFieldLength;
+
+    /**
+     *  @brief Always present, fixed length data fields for the BSS
+     */
+    wlan_ioctl_get_scan_table_fixed fixedFields;
+
+    /**
+     *  @brief Length of the BSS Information (probe resp or beacon) that
+     *         follows starting at bssInfoBuffer
+     */
+    u32 bssInfoLength;
+
+    /**
+     *  @brief Probe response or beacon scanned for the BSS.
+     *
+     *  Field layout:
+     *   - TSF              8 octets
+     *   - Beacon Interval  2 octets
+     *   - Capability Info  2 octets
+     *
+     *   - IEEE Infomation Elements; variable number & length per 802.11 spec
+     */
+    u8 bssInfoBuffer[1];
+} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_entry;
+
+/**
+ *  @brief WLAN_GET_SCAN_RESP private IOCTL struct to retrieve the scan table
+ *
+ *  @sa wlan_get_scan_table_ioctl
+ */
+typedef struct
+{
+
+    /**
+     *  - Zero based scan entry to start retrieval in command request
+     *  - Number of scans entires returned in command response
+     */
+    u32 scanNumber;
+
+     /**
+      * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures.
+      *   Each struct is padded to the nearest 32 bit boundary.
+      */
+    u8 scan_table_entry_buffer[1];
+
+} __ATTRIB_PACK__ wlan_ioctl_get_scan_table_info;
+
+/**
+ *  @brief Structure used to store information for each beacon/probe response
+ */
+typedef struct
+{
+    /** MAC address */
+    WLAN_802_11_MAC_ADDRESS MacAddress;
+
+    /** SSID */
+    WLAN_802_11_SSID Ssid;
+
+    /** WEP encryption requirement */
+    u32 Privacy;
+
+    /** receive signal strength in dBm */
+    WLAN_802_11_RSSI Rssi;
+
+    /** Channel */
+    u32 Channel;
+
+    /** Beacon period */
+    u16 BeaconPeriod;
+
+    /** ATIM window */
+    u32 ATIMWindow;
+    /** ERP flags */
+    u8 ERPFlags;
+
+    /** Type of network in use */
+    WLAN_802_11_NETWORK_TYPE NetworkTypeInUse;
+    /** Network infrastructure mode */
+    WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+    /** Network supported rates */
+    WLAN_802_11_RATES SupportedRates;
+    /** WMM IE */
+    IEEEtypes_WmmParameter_t wmmIE;
+
+    /** Network band.
+     * BAND_B(0x01): 'b' band
+     * BAND_G(0x02): 'g' band
+     * BAND_A(0X04): 'a' band
+     */
+    u16 bss_band;
+
+    u8 TimeStamp[8];            //!< TSF value included in the beacon/probe response
+
+    /** PHY parameter set */
+    IEEEtypes_PhyParamSet_t PhyParamSet;
+    /** SS parameter set */
+    IEEEtypes_SsParamSet_t SsParamSet;
+    /** Capability information */
+    IEEEtypes_CapInfo_t Cap;
+
+    /** Supported data rates */
+    u8 DataRates[WLAN_SUPPORTED_RATES];
+
+    u64 networkTSF;             //!< TSF timestamp from the current firmware TSF
+
+    /** 802.11h BSS information */
+    wlan_11h_bss_info_t wlan_11h_bss_info;
+
+    /** Country information set */
+    IEEEtypes_CountryInfoFullSet_t CountryInfo;
+
+    /** WPA IE */
+    IEEEtypes_VendorSpecific_t *pWpaIE;
+    /** WPA IE offset in the beacon buffer */
+    u8 wpaOffset;
+    /** RSN IE */
+    IEEEtypes_Generic_t *pRsnIE;
+    /** RSN IE offset in the beacon buffer */
+    u8 rsnOffset;
+
+    /** WPS IE */
+    IEEEtypes_VendorSpecific_t *pWpsIE;
+    /** WPS IE offset in the beacon buffer */
+    u8 wpsOffset;
+
+    u8 *pBeaconBuf;             //!< Pointer to the returned scan response
+    uint beaconBufSize;         //!< Length of the stored scan response
+    uint beaconBufSizeMax;      //!< Max allocated size for updated scan response
+
+} BSSDescriptor_t;
+
+extern int wlan_ssid_cmp(WLAN_802_11_SSID * ssid1, WLAN_802_11_SSID * ssid2);
+extern int wlan_find_ssid_in_list(wlan_adapter * Adapter,
+                                  WLAN_802_11_SSID * ssid, u8 * bssid,
+                                  int mode);
+extern int wlan_find_best_ssid_in_list(wlan_adapter * Adapter);
+extern int wlan_find_bssid_in_list(wlan_adapter * Adapter, u8 * bssid,
+                                   int mode);
+
+extern int wlan_find_best_network_ssid(wlan_private * priv,
+                                       WLAN_802_11_SSID * pSSID);
+
+extern int wlan_cmd_specific_scan_ssid(wlan_private * priv,
+                                       WLAN_802_11_SSID * pRequestedSSID);
+extern int wlan_cmd_specific_scan_bssid(wlan_private * priv, u8 * bssid);
+
+extern int wlan_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+extern int wlan_associate(wlan_private * priv, BSSDescriptor_t * pBSSDesc);
+
+extern int wlan_cmd_802_11_scan(wlan_private * priv,
+                                HostCmd_DS_COMMAND * cmd, void *pdata_buf);
+
+extern void wlan_scan_update_tsf_timestamps(wlan_private * priv,
+                                            BSSDescriptor_t * pNewBssDesc);
+
+extern int wlan_ret_802_11_scan(wlan_private * priv,
+                                HostCmd_DS_COMMAND * resp);
+
+extern int wlan_extscan_ioctl(wlan_private * priv, struct ifreq *req);
+
+extern int wlan_cmd_bgs_query(wlan_private * priv);
+extern int wlan_bg_scan_enable(wlan_private * priv, BOOLEAN enable);
+extern int wlan_do_bg_scan_config_ioctl(wlan_private * priv,
+                                        struct ifreq *req);
+extern int wlan_do_bgscfg_ioctl(wlan_private * priv, struct ifreq *req);
+
+extern int wlan_cmd_802_11_bg_scan_config(wlan_private * priv,
+                                          HostCmd_DS_COMMAND * cmd,
+                                          int cmd_action, void *pdata_buf);
+extern int wlan_cmd_802_11_bg_scan_query(wlan_private * priv,
+                                         HostCmd_DS_COMMAND * cmd);
+
+#ifdef __KERNEL__
+extern int wlan_get_scan(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_point *dwrq, char *extra);
+extern int wlan_set_scan(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra);
+#endif
+
+#endif /* _WLAN_SCAN_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1684 @@
+/** @file wlan_sdio.c
+ *  @brief This file contains SDIO IF (interface) module
+ *  related functions.
+ * 
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+	10/14/05: add Doxygen format comments 
+	01/05/06: add kernel 2.6.x support
+	01/23/06: add fw downlaod
+	06/06/06: add macro SD_BLOCK_SIZE_FW_DL for firmware download
+		  add macro ALLOC_BUF_SIZE for cmd resp/Rx data skb buffer allocation
+****************************************************/
+
+#include	"wlan_sdio.h"
+
+#include <linux/firmware.h>
+
+/** define SD block size for firmware download */
+#define SD_BLOCK_SIZE_FW_DL	32
+
+/** define SD block size for data Tx/Rx */
+#define SD_BLOCK_SIZE		256
+
+/** define allocated buffer size */
+#define ALLOC_BUF_SIZE		(((MAX(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, \
+					MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \
+					+ SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE) * SD_BLOCK_SIZE)
+
+/** Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY	2
+
+/* The macros below are hardware platform dependent.
+   The definition should match the actual platform */
+#define GPIO_PORT_INIT()
+/** Set GPIO port to high */
+#define GPIO_PORT_TO_HIGH()
+/** Set GPIO port to low */
+#define GPIO_PORT_TO_LOW()
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+static wlan_private *pwlanpriv;
+static wlan_private *(*wlan_add_callback) (void *dev_id);
+static int (*wlan_remove_callback) (void *dev_id);
+
+/** SDIO func 1 */
+static u8 sdio_func_wlan = SDIO_FUNC1;
+
+/** SDIO Rx unit */
+static u8 sdio_rx_unit = 0;
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+#define SDIO_CLK_RATE_6MHZ	6       /**< 6 MHz */
+#define SDIO_CLK_RATE_12MHZ	12      /**< 12 MHz */
+#define SDIO_CLK_RATE_25MHZ	25      /**< 25 MHz */
+#define SDIO_CLK_RATE_DEFAULT	0   /**< Default rate */
+/** SDIO clock rate */
+int clkrate = SDIO_CLK_RATE_DEFAULT;
+module_param(clkrate, int, 0);
+
+/** ISR */
+//sd_int_handler isr_function;
+//int request_gpio_irq_callback(void (*callback) (void *), void *arg);
+//int release_gpio_irq_callback(void (*callback) (void *), void *arg);
+
+/** Chip ID for 8686 */
+#define CHIP_ID_8686 0x3042
+/** Chip ID for 8688 */
+#define CHIP_ID_8688 0x3130
+/** Chip ID for 8688R3 */
+#define CHIP_ID_8688R3 0x3131
+/** Chip ID for 8682 */
+#define CHIP_ID_8682 0x3139
+/** Null chip ID */
+#define CHIP_ID_NULL 0x0000
+
+
+/** Default helper name */
+#define DEFAULT_HELPER_NAME "mrvl/helper_sd.bin"
+/** Maximum length for firmware name */
+#define MAX_FW_NAME 32
+
+typedef struct _chipid_fwname
+{
+    /** Chip ID */
+    u16 chip_id;
+    /** Firmware filename */
+    char fw_name[MAX_FW_NAME];
+} chipid_fwname;
+
+static chipid_fwname chip_fw[] = {
+    {.chip_id = CHIP_ID_8688,.fw_name = "mrvl/sd8688.bin"},
+    {.chip_id = CHIP_ID_8686,.fw_name = "mrvl/sd8686.bin"},
+    {.chip_id = CHIP_ID_8688R3,.fw_name = "mrvl/sd8688.bin"},
+    {.chip_id = CHIP_ID_8682,.fw_name = "mrvl/sd8682.bin"},
+    {.chip_id = CHIP_ID_NULL,.fw_name = ""},    /* must be the last one */
+};
+
+extern u8 *helper_name;
+extern u8 *fw_name;
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function removes the card
+ *  
+ *  @param card    A pointer to the card
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+
+static inline u16
+get_chip_id(wlan_private * priv)
+{
+    u8 id0;
+    u8 id1;
+    u16 chip_id;
+
+    if (sbi_read_ioreg(priv, CARD_CHIP_ID_0_REG, &id0) < 0)
+        return CHIP_ID_NULL;
+
+    if (sbi_read_ioreg(priv, CARD_CHIP_ID_1_REG, &id1) < 0)
+        return CHIP_ID_NULL;
+
+    chip_id = (((u16) id0) << 8) | id1;
+    PRINTM(INFO, "Chip ID %#x\n", chip_id);
+
+    return chip_id;
+}
+
+static inline int
+get_enhance_flag(wlan_private * priv)
+{
+    u16 chip_id;
+
+    chip_id = get_chip_id(priv);
+    if ((chip_id == CHIP_ID_8688) || (chip_id == CHIP_ID_8682))
+        return TRUE;
+    else
+        return FALSE;
+}
+
+static inline char *
+find_fw_name(wlan_private * priv)
+{
+    u16 chip_id;
+    int i = 0;
+
+    chip_id = get_chip_id(priv);
+
+    while (chip_id && (chip_fw[i].chip_id != CHIP_ID_NULL)) {
+        if (chip_fw[i].chip_id == chip_id) {
+            return chip_fw[i].fw_name;
+        }
+        i++;
+    }
+    PRINTM(ERROR, "Unknown Chip ID %#x\n", chip_id);
+    return NULL;
+}
+
+/* some tool function */
+int sbi_read_iomem(wlan_private *priv, void *buf, unsigned int reg_addr, int cnt)
+{
+	struct sdio_mmc_card *card = priv->wlan_dev.card;
+	int ret = 0;
+
+	sdio_claim_host(card->func);
+	ret = sdio_readsb(card->func, buf, reg_addr, cnt);
+	sdio_release_host(card->func);
+
+	return ret;
+}
+
+int sbi_write_iomem(wlan_private *priv, void *buf, unsigned int reg_addr, int cnt)
+{
+	struct sdio_mmc_card *card = priv->wlan_dev.card;
+	int ret = 0;
+
+	sdio_claim_host(card->func);
+	ret = sdio_writesb(card->func, reg_addr, buf, cnt);
+	sdio_release_host(card->func);
+
+	return ret;
+}
+
+/** 
+ *  @brief This function get rx_unit value
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sd_get_rx_unit(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 reg;
+    ret = sbi_read_ioreg(priv, CARD_RX_UNIT_REG, &reg);
+    if (ret == WLAN_STATUS_SUCCESS)
+        sdio_rx_unit = reg;
+    return ret;
+}
+
+/** 
+ *  @brief This function reads rx length
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param dat	   A pointer to keep returned data
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+sd_read_rx_len(wlan_private * priv, u16 * dat)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 reg;
+    ret = sbi_read_ioreg(priv, CARD_RX_LEN_REG, &reg);
+    if (ret == WLAN_STATUS_SUCCESS) {
+        *dat = (u16) reg << sdio_rx_unit;
+    }
+    return ret;
+}
+
+/** 
+ *  @brief This function reads fw status registers
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param dat	   A pointer to keep returned data
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+sd_read_firmware_status(wlan_private * priv, u16 * dat)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 fws0;
+    u8 fws1;
+    ENTER();
+    ret = sbi_read_ioreg(priv, CARD_FW_STATUS0_REG, &fws0);
+    if (ret < 0)
+        return WLAN_STATUS_FAILURE;
+    ret = sbi_read_ioreg(priv, CARD_FW_STATUS1_REG, &fws1);
+    if (ret < 0)
+        return WLAN_STATUS_FAILURE;
+    *dat = (((u16) fws1) << 8) | fws0;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function reads scratch registers
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param dat	   A pointer to keep returned data
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+mv_sdio_read_scratch(wlan_private * priv, u16 * dat)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 scr0;
+    u8 scr1;
+
+    ret = sbi_read_ioreg(priv, CARD_OCR_0_REG, &scr0);
+    if (ret < 0)
+        return WLAN_STATUS_FAILURE;
+
+    ret = sbi_read_ioreg(priv, CARD_OCR_1_REG, &scr1);
+    PRINTM(INFO, "CARD_OCR_0_REG = 0x%x, CARD_OCR_1_REG = 0x%x\n", scr0,
+           scr1);
+    if (ret < 0)
+        return WLAN_STATUS_FAILURE;
+
+    *dat = (((u16) scr1) << 8) | scr0;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function polls the card status register.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param bits    	the bit mask
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+mv_sdio_poll_card_status(wlan_private * priv, u8 bits)
+{
+    int tries;
+    u8 cs;
+
+    for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+        if (sbi_read_ioreg(priv, CARD_STATUS_REG, &cs) < 0)
+            break;
+        else if ((cs & bits) == bits)
+            return WLAN_STATUS_SUCCESS;
+        udelay(10);
+    }
+
+    PRINTM(WARN, "mv_sdio_poll_card_status failed, tries = %d\n", tries);
+    return WLAN_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief This function set the sdio bus width.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param mode    	1--1 bit mode, 4--4 bit mode
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sdio_set_bus_width(wlan_private * priv, u8 mode)
+{
+    return WLAN_STATUS_SUCCESS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ *  @brief This function reads data from the card.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param type	   	A pointer to keep type as data or command
+ *  @param nb		A pointer to keep the data/cmd length retured in buffer
+ *  @param payload 	A pointer to the data/cmd buffer
+ *  @param nb	   	the length of data/cmd buffer
+ *  @param npayload	the length of data/cmd buffer
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+/* external lock needed */
+static int
+mv_sdio_card_to_host(wlan_private * priv,
+                     u32 * type, int *nb, u8 * payload, int npayload)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 buf_len = 0;
+    int buf_block_len;
+    int blksz;
+    u32 event;
+
+	ENTER();
+	
+    if (!card || !card->func) {
+        PRINTM(ERROR, "card or function is NULL!\n");
+        ret = WLAN_STATUS_FAILURE;
+        return ret; 
+    }
+
+    if (!payload) {
+        PRINTM(WARN, "payload NULL pointer received!\n");
+        ret = WLAN_STATUS_FAILURE;
+	return ret;
+    }
+
+    //sdio_claim_host(card->func);
+
+    /* Read the length of data to be transferred */
+    if (priv->enhance_flag)
+        ret = sd_read_rx_len(priv, &buf_len);
+    else
+        ret = mv_sdio_read_scratch(priv, &buf_len);
+    if (ret < 0) {
+        PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+
+    if (buf_len <= SDIO_HEADER_LEN || buf_len > npayload) {
+        PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+
+    /* Allocate buffer */
+    blksz = SD_BLOCK_SIZE;
+    buf_block_len = (buf_len + blksz - 1) / blksz;
+
+    ret = sdio_readsb(card->func, payload, priv->wlan_dev.ioport,
+                      buf_block_len * blksz);
+
+    if (ret < 0) {
+        PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+    if (priv->enhance_flag)
+        *nb = wlan_le16_to_cpu(*(u16 *) & payload[0]);
+    else
+        *nb = buf_len;
+
+    DBG_HEXDUMP(IF_D, "SDIO Blk Rd", payload, blksz * buf_block_len);
+
+    *type = wlan_le16_to_cpu(*(u16 *) & payload[2]);
+    if (*type == MV_TYPE_EVENT) {
+        event = *(u32 *) & payload[4];
+        priv->adapter->EventCause = wlan_le32_to_cpu(event);
+    }
+
+  exit:
+//	sdio_release_host(card->func);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function enables the host interrupts mask
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param mask	   the interrupt mask
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+/* external lock needed */
+static int
+enable_host_int_mask(wlan_private * priv, u8 mask)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    /* Simply write the mask to the register */
+    ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, mask);
+
+    if (ret) {
+        PRINTM(WARN, "Unable to enable the host interrupt!\n");
+        ret = WLAN_STATUS_FAILURE;
+    }
+
+    priv->adapter->HisRegCpy = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/**  @brief This function disables the host interrupts mask.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param mask	   the interrupt mask
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+/* external lock needed */
+static int
+disable_host_int_mask(wlan_private * priv, u8 mask)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 host_int_mask;
+
+    ENTER();
+
+    /* Read back the host_int_mask register */
+    ret = sbi_read_ioreg(priv, HOST_INT_MASK_REG, &host_int_mask);
+    if (ret) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    /* Update with the mask and write back to the register */
+    host_int_mask &= ~mask;
+    ret = sbi_write_ioreg(priv, HOST_INT_MASK_REG, host_int_mask);
+    if (ret < 0) {
+        PRINTM(WARN, "Unable to diable the host interrupt!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+
+/** 
+ *  @brief This function handles the interrupt.
+ *  
+ *  @param card	   The card handle.
+ *  @return 	   n/a
+ */
+static void
+sbi_interrupt(struct sdio_func *func)
+{
+    struct sdio_mmc_card *card;
+    wlan_private *priv;
+    u8 ireg = 0;
+
+    ENTER();
+
+    card = sdio_get_drvdata(func);
+    if (!card || !card->priv) {
+        PRINTM(INFO, "%s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",
+               __FUNCTION__, func, card);
+        return;
+    }
+
+    priv = card->priv;
+    wlan_interrupt(priv);
+    if (sbi_get_int_status(priv, &ireg)) {
+        PRINTM(ERROR, "%s: reading HOST_INT_STATUS_REG failed\n",
+               __FUNCTION__);
+    } else
+        PRINTM(INFO, "%s: HOST_INT_STATUS_REG %#x\n", __FUNCTION__, ireg);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+}
+
+/** client driver probe handler 		*/
+static int
+wlan_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+    int ret = WLAN_STATUS_FAILURE;
+    struct sdio_mmc_card *card = NULL;
+    u8 chiprev;
+
+    ENTER();
+
+    if (!wlan_add_callback) {
+        PRINTM(FATAL, "%s: add_card callback function not found!\n",
+               __FUNCTION__);
+        goto done;
+    }
+
+    if (func->class != SDIO_CLASS_WLAN) {
+        PRINTM(FATAL, "%s: class-id SD_CLASS_WLAN not found!\n",
+               __FUNCTION__);
+        goto done;
+    }
+
+    PRINTM(INFO, "%s: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+           __FUNCTION__, func->vendor, func->device, func->class, func->num);
+
+    sdio_claim_host(func);
+
+    ret = sdio_enable_func(func);
+    if (ret) {
+        PRINTM(FATAL, "sdio_enable_func() failed: ret=%d\n", ret);
+        goto release_host;
+    }
+
+    ret = sdio_claim_irq(func, sbi_interrupt);
+    if (ret) {
+        PRINTM(FATAL, "sdio_claim_irq failed: ret=%d\n", ret);
+        goto disable_func;
+    }
+
+    /* read Revision Register to get the chip revision number */
+    chiprev = sdio_readb(func, CARD_REVISION_REG, &ret);
+    if (ret) {
+        PRINTM(FATAL, "cannot read CARD_REVISION_REG\n");
+        goto release_irq;
+    }
+
+    PRINTM(INFO, "revision=%#x\n", chiprev);
+
+    card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+    if (!card) {
+        ret = -ENOMEM;
+        goto release_irq;
+    }
+
+    card->func = func;
+
+    ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE);
+    if (ret) {
+        PRINTM(ERROR, "%s: cannot set SDIO block size\n", __FUNCTION__);
+                ret = WLAN_STATUS_FAILURE;
+        goto release_irq;
+            }
+
+    sdio_release_host(func);
+
+    if (!wlan_add_callback(card)) {
+        PRINTM(ERROR, "%s: wlan_add_callback failed\n", __FUNCTION__);
+                ret = WLAN_STATUS_FAILURE;
+        goto reclaim_host;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+    goto done;
+
+  reclaim_host:
+    sdio_claim_host(func);
+  release_irq:
+    sdio_release_irq(func);
+  disable_func:
+    sdio_disable_func(func);
+  release_host:
+    sdio_release_host(func);
+
+    if (card) {
+        kfree(card);
+        card = NULL;
+    }
+
+    if (pwlanpriv)
+        return WLAN_STATUS_SUCCESS;
+    else
+        return WLAN_STATUS_FAILURE;
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** client driver remove handler 	*/
+static void
+wlan_remove(struct sdio_func *func)
+{
+    struct sdio_mmc_card *card;
+
+    ENTER();
+
+    if (!wlan_remove_callback) {
+        PRINTM(FATAL, "%s: remove_card callback function not found!\n",
+               __FUNCTION__);
+        goto done;
+        }
+    if (func) {
+        card = sdio_get_drvdata(func);
+        if (card) {
+            sdio_claim_host(func);
+            sdio_release_irq(func);
+            sdio_disable_func(func);
+            sdio_release_host(func);
+
+            wlan_remove_callback(card);
+
+            kfree(card);
+            card = NULL;
+        }
+    }
+
+  done:
+    LEAVE();
+}
+
+#ifdef CONFIG_PM
+/* client driver suspend handler 	*/
+int wlan_suspend(struct sdio_func *func)
+{
+    ENTER();
+    LEAVE();
+    return 0;
+}
+
+/* client driver resume handler 	*/
+int wlan_resume(struct sdio_func *func)
+{
+    ENTER();
+    LEAVE();
+    return 0;
+}
+#endif
+
+/** WLAN IDs */
+static const struct sdio_device_id wlan_ids[] = {
+    {SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN)},
+    {},
+};
+
+MODULE_DEVICE_TABLE(sdio, wlan_ids);
+
+static struct sdio_driver wlan_sdio = {
+    .name = "wlan_sdio",
+    .id_table = wlan_ids,
+    .probe = wlan_probe,
+    .remove = wlan_remove,
+#ifdef CONFIG_PM
+//    .suspend  = wlan_suspend,
+//    .resume   = wlan_resume, 
+#endif
+
+};
+
+/** 
+ *  @brief This function registers the IF module in bus driver.
+ *  
+ *  @param add	   wlan driver's call back funtion for add card.
+ *  @param remove  wlan driver's call back funtion for remove card.
+ *  @param arg     not been used
+ *  @return	   An int pointer that keeps returned value
+ */
+int *
+sbi_register(wlan_notifier_fn_add add, wlan_notifier_fn_remove remove,
+             void *arg)
+{
+    int *sdio_ret = (int *) 1;
+
+    ENTER();
+
+    wlan_add_callback = add;
+    wlan_remove_callback = remove;
+
+    /* SDIO Driver Registration */
+    if (sdio_register_driver(&wlan_sdio) != 0) {
+        PRINTM(FATAL, "SDIO Driver Registration Failed \n");
+        sdio_ret = NULL;
+    }
+
+    LEAVE();
+    return sdio_ret;
+}
+
+/** 
+ *  @brief This function de-registers the IF module in bus driver.
+ *  
+ *  @return 	   n/a
+ */
+void
+sbi_unregister(void)
+{
+    ENTER();
+
+    /* SDIO Driver Unregistration */
+    sdio_unregister_driver(&wlan_sdio);
+
+    LEAVE();
+}
+
+/** 
+ *  @brief This function reads the IO register.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param reg	   register to be read
+ *  @param dat	   A pointer to variable that keeps returned value
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_read_ioreg(wlan_private * priv, u32 reg, u8 * dat)
+{
+    struct sdio_mmc_card *card;
+    int ret = WLAN_STATUS_FAILURE;
+
+    ENTER();
+
+    card = priv->wlan_dev.card;
+    if (!card || !card->func) {
+        PRINTM(ERROR, "sbi_read_ioreg(): card or function is NULL!\n");
+        goto done;
+    }
+
+    *dat = sdio_readb(card->func, reg, &ret);
+    if (ret) {
+        PRINTM(ERROR, "sbi_read_ioreg(): sdio_readb failed! ret=%d\n", ret);
+        goto done;
+    }
+
+    PRINTM(INFO, "sbi_read_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
+           card->func->num, reg, *dat);
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function writes the IO register.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param reg	   register to be written
+ *  @param dat	   the value to be written
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_write_ioreg(wlan_private * priv, u32 reg, u8 dat)
+{
+    struct sdio_mmc_card *card;
+    int ret = WLAN_STATUS_FAILURE;
+
+    ENTER();
+
+    card = priv->wlan_dev.card;
+    if (!card || !card->func) {
+        PRINTM(ERROR, "sbi_write_ioreg(): card or function is NULL!\n");
+        goto done;
+    }
+
+    PRINTM(INFO, "sbi_write_ioreg() priv=%p func=%d reg=%#x dat=%#x\n", priv,
+           card->func->num, reg, dat);
+
+    sdio_writeb(card->func, dat, reg, &ret);
+    if (ret) {
+        PRINTM(ERROR, "sbi_write_ioreg(): sdio_readb failed! ret=%d\n", ret);
+        goto done;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function checks the interrupt status and handle it accordingly.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param ireg    A pointer to variable that keeps returned value
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 sdio_ireg = 0;
+    u8 *cmdBuf;
+    wlan_dev_t *wlan_dev = &priv->wlan_dev;
+    struct sk_buff *skb;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "%s: card or function is NULL!\n", __FUNCTION__);
+        ret = WLAN_STATUS_FAILURE;
+	return ret;
+    }
+
+        //PRINTM(ERROR, "%s: before claim host!\n", __FUNCTION__);
+	//sdio_claim_host(card->func);
+        ///PRINTM(ERROR, "%s: after claim host!\n", __FUNCTION__);
+
+    *ireg = 0;
+    if ((ret = sbi_read_ioreg(priv, HOST_INTSTATUS_REG, &sdio_ireg))) {
+        PRINTM(WARN, "sbi_read_ioreg: read int status register failed\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (sdio_ireg != 0) {
+        /*
+         * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+         * Clear the interrupt status register and re-enable the interrupt
+         */
+        PRINTM(INFO, "sdio_ireg = 0x%x\n", sdio_ireg);
+        if ((ret = sbi_write_ioreg(priv, HOST_INTSTATUS_REG,
+                                    ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |
+                                                    UP_LD_HOST_INT_STATUS))) <
+            0) {
+            PRINTM(WARN,
+                   "sbi_write_ioreg: clear int status register failed\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+    } else
+        PRINTM(ERROR, "cause=0 sdio_ireg = 0x%x\n", sdio_ireg);
+
+    if (sdio_ireg & DN_LD_HOST_INT_STATUS) {    /* tx_done INT */
+        *ireg |= HIS_TxDnLdRdy;
+        if (!priv->wlan_dev.dnld_sent) {        /* tx_done already received */
+            PRINTM(INFO, "warning: tx_done already received:"
+                   " dnld_sent=0x%x int status=0x%x\n",
+                   priv->wlan_dev.dnld_sent, sdio_ireg);
+        } else {
+            wmm_process_fw_iface_tx_xfer_end(priv);
+            priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+        }
+    }
+
+    if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+
+        /* 
+         * DMA read data is by block alignment,so we need alloc extra block
+         * to avoid wrong memory access.
+         */
+        if (!(skb = dev_alloc_skb(ALLOC_BUF_SIZE))) {
+            PRINTM(WARN, "No free skb\n");
+            priv->stats.rx_dropped++;
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        /* 
+         * Transfer data from card
+         * skb->tail is passed as we are calling skb_put after we
+         * are reading the data
+         */
+        if (mv_sdio_card_to_host(priv, &wlan_dev->upld_typ,
+                                 (int *) &wlan_dev->upld_len, skb->tail,
+                                 ALLOC_BUF_SIZE) < 0) {
+            u8 cr = 0;
+
+            PRINTM(ERROR, "Card to host failed: int status=0x%x\n",
+                   sdio_ireg);
+            if (sbi_read_ioreg(priv, CONFIGURATION_REG, &cr) < 0)
+                PRINTM(ERROR, "read ioreg failed (CFG)\n");
+
+            PRINTM(INFO, "Config Reg val = %d\n", cr);
+            if (sbi_write_ioreg(priv, CONFIGURATION_REG, (cr | 0x04)) < 0)
+                PRINTM(ERROR, "write ioreg failed (CFG)\n");
+
+            PRINTM(INFO, "write success\n");
+            if (sbi_read_ioreg(priv, CONFIGURATION_REG, &cr) < 0)
+                PRINTM(ERROR, "read ioreg failed (CFG)\n");
+
+            PRINTM(INFO, "Config reg val =%x\n", cr);
+            ret = WLAN_STATUS_FAILURE;
+            kfree_skb(skb);
+            goto done;
+        }
+
+        switch (wlan_dev->upld_typ) {
+        case MV_TYPE_DAT:
+            PRINTM(DATA, "Data <= FW\n");
+            skb_put(skb, priv->wlan_dev.upld_len);
+            skb_pull(skb, SDIO_HEADER_LEN);
+            wlan_process_rx_packet(priv, skb);
+            priv->adapter->IntCounter = 0;
+            /* skb will be freed by kernel later */
+            break;
+
+        case MV_TYPE_CMD:
+            *ireg |= HIS_CmdUpLdRdy;
+            priv->adapter->HisRegCpy |= *ireg;
+
+            /* take care of CurCmd = NULL case */
+            if (!priv->adapter->CurCmd) {
+                cmdBuf = priv->wlan_dev.upld_buf;
+            } else {
+                cmdBuf = priv->adapter->CurCmd->BufVirtualAddr;
+            }
+
+            priv->wlan_dev.upld_len -= SDIO_HEADER_LEN;
+            memcpy(cmdBuf, skb->data + SDIO_HEADER_LEN,
+                   MIN(MRVDRV_SIZE_OF_CMD_BUFFER, priv->wlan_dev.upld_len));
+            kfree_skb(skb);
+            break;
+
+        case MV_TYPE_EVENT:
+            *ireg |= HIS_CardEvent;
+            priv->adapter->HisRegCpy |= *ireg;
+            /* event cause has been saved to priv->adapter->EventCause */
+            kfree_skb(skb);
+            break;
+
+        default:
+            PRINTM(ERROR, "SDIO unknown upld type = 0x%x\n",
+                   wlan_dev->upld_typ);
+            kfree_skb(skb);
+            break;
+        }
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+done:
+    //sdio_release_host(card->func);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function disables the host interrupts.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_disable_host_int(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret;
+
+    sdio_claim_host(card->func);
+    ret = disable_host_int_mask(priv, HIM_DISABLE);
+    sdio_release_host(card->func);
+    return ret;
+}
+
+/** 
+ *  @brief This function enables the host interrupts.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_enable_host_int(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret;
+
+    sdio_claim_host(card->func);
+    ret = enable_host_int_mask(priv, HIM_ENABLE);
+    sdio_release_host(card->func);
+    return ret;
+}
+
+/** 
+ *  @brief This function de-registers the device.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_unregister_dev(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "Error: card or function is NULL!\n");
+        goto done;
+    }
+
+    sdio_set_drvdata(card->func, NULL);
+
+    GPIO_PORT_TO_LOW();
+
+  done:
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function registers the device.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_register_dev(wlan_private * priv)
+{
+    int ret = WLAN_STATUS_FAILURE;
+    u8 reg;
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    struct sdio_func *func;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "Error: card or function is NULL!\n");
+        goto free_card;
+    }
+
+    func = card->func;
+
+    GPIO_PORT_INIT();
+    GPIO_PORT_TO_HIGH();
+
+    /* Initialize the private structure */
+    strncpy(priv->wlan_dev.name, "sdio0", sizeof(priv->wlan_dev.name));
+    priv->wlan_dev.ioport = 0;
+    priv->wlan_dev.upld_rcv = 0;
+    priv->wlan_dev.upld_typ = 0;
+    priv->wlan_dev.upld_len = 0;
+
+    sdio_claim_host(func);
+
+    /* Read the IO port */
+    ret = sbi_read_ioreg(priv, IO_PORT_0_REG, &reg);
+    if (ret)
+        goto release_irq;
+    else
+        priv->wlan_dev.ioport |= reg;
+
+    ret = sbi_read_ioreg(priv, IO_PORT_1_REG, &reg);
+    if (ret)
+        goto release_irq;
+    else
+        priv->wlan_dev.ioport |= (reg << 8);
+
+    ret = sbi_read_ioreg(priv, IO_PORT_2_REG, &reg);
+    if (ret)
+        goto release_irq;
+    else
+        priv->wlan_dev.ioport |= (reg << 16);
+
+    PRINTM(INFO, "SDIO FUNC #%d IO port: 0x%x\n", func->num,
+           priv->wlan_dev.ioport);
+
+    priv->hotplug_device = &func->dev;
+    if (helper_name == NULL) {
+        helper_name = DEFAULT_HELPER_NAME;
+    }
+    if (fw_name == NULL) {
+        fw_name = find_fw_name(priv);
+        if (fw_name == NULL) {
+            goto release_irq;
+        }
+    }
+
+    sdio_release_host(func);
+
+    sdio_set_drvdata(func, card);
+
+    ret = WLAN_STATUS_SUCCESS;
+    goto done;
+
+  release_irq:
+    sdio_release_irq(func);
+    sdio_disable_func(func);
+    sdio_release_host(func);
+  free_card:
+    if (card) {
+        kfree(card);
+        card = NULL;
+    }
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function sends data to the card.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param type	   data or command
+ *  @param payload A pointer to the data/cmd buffer
+ *  @param nb	   the length of data/cmd
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret = WLAN_STATUS_SUCCESS;
+    int buf_block_len;
+    int blksz;
+    int i = 0;
+    void *tmpcmdbuf = NULL;
+    int tmpcmdbufsz;
+    u8 *cmdbuf = NULL;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "card or function is NULL!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto exit;
+    }
+
+    priv->adapter->HisRegCpy = 0;
+
+    /* Allocate buffer and copy payload */
+    blksz = SD_BLOCK_SIZE;
+    buf_block_len = (nb + SDIO_HEADER_LEN + blksz - 1) / blksz;
+
+    /* This is SDIO specific header
+     *  u16 length,
+     *  u16 type (MV_TYPE_DAT = 0, MV_TYPE_CMD = 1, MV_TYPE_EVENT = 3) 
+     */
+    if (type == MV_TYPE_DAT) {
+        *(u16 *) & payload[0] = wlan_cpu_to_le16(nb + SDIO_HEADER_LEN);
+        *(u16 *) & payload[2] = wlan_cpu_to_le16(type);
+    } else if (type == MV_TYPE_CMD) {
+        tmpcmdbufsz = WLAN_UPLD_SIZE;
+        tmpcmdbuf = kmalloc(tmpcmdbufsz, GFP_KERNEL);
+        if (!tmpcmdbuf) {
+            PRINTM(ERROR, "Unable to allocate buffer for CMD.\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto exit;
+        }
+        memset(tmpcmdbuf, 0, tmpcmdbufsz);
+        cmdbuf = (u8 *) tmpcmdbuf;
+
+        *(u16 *) & cmdbuf[0] = wlan_cpu_to_le16(nb + SDIO_HEADER_LEN);
+        *(u16 *) & cmdbuf[2] = wlan_cpu_to_le16(type);
+
+        if (payload != NULL &&
+            (nb > 0 && nb <= (WLAN_UPLD_SIZE - SDIO_HEADER_LEN))) {
+
+            memcpy(&cmdbuf[SDIO_HEADER_LEN], payload, nb);
+        } else {
+            PRINTM(WARN, "sbi_host_to_card(): Error: payload=%p, nb=%d\n",
+                   payload, nb);
+        }
+    }
+
+    sdio_claim_host(card->func);
+
+    do {
+
+        /* Transfer data to card */
+        ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
+                           (type == MV_TYPE_DAT) ? payload : cmdbuf,
+                           buf_block_len * blksz);
+        if (ret < 0) {
+            i++;
+            PRINTM(ERROR, "host_to_card, write iomem (%d) failed: %d\n", i,
+                   ret);
+            if (sbi_write_ioreg(priv, CONFIGURATION_REG, 0x04) < 0) {
+                PRINTM(ERROR, "write ioreg failed (CFG)\n");
+            }
+            ret = WLAN_STATUS_FAILURE;
+            if (i > MAX_WRITE_IOMEM_RETRY)
+                goto exit;
+        } else {
+            DBG_HEXDUMP(IF_D, "SDIO Blk Wr",
+                        (type == MV_TYPE_DAT) ? payload : cmdbuf,
+                        blksz * buf_block_len);
+        }
+    } while (ret == WLAN_STATUS_FAILURE);
+
+    if (type == MV_TYPE_DAT)
+        priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
+    else
+        priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
+
+  exit:
+    sdio_release_host(card->func);
+    if (tmpcmdbuf)
+        kfree(tmpcmdbuf);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function reads CIS informaion.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param cisinfo A pointer to CIS information output buffer
+ *  @param cislen  The length of CIS information output buffer
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_get_cis_info(wlan_private * priv, void *cisinfo, int *cislen)
+{
+#define CIS_PTR (0x8000)
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    unsigned int i, cis_ptr = CIS_PTR;
+    int ret = WLAN_STATUS_FAILURE;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "sbi_get_cis_info(): card or function is NULL!\n");
+        goto exit;
+    }
+#define MAX_SDIO_CIS_INFO_LEN (256)
+    if (!cisinfo || (*cislen < MAX_SDIO_CIS_INFO_LEN)) {
+        PRINTM(WARN, "ERROR! get_cis_info: insufficient buffer passed\n");
+        goto exit;
+    }
+
+    *cislen = MAX_SDIO_CIS_INFO_LEN;
+
+    sdio_claim_host(card->func);
+
+    PRINTM(INFO, "cis_ptr=%#x\n", cis_ptr);
+
+    /* Read the Tuple Data */
+    for (i = 0; i < *cislen; i++) {
+        ((unsigned char *) cisinfo)[i] =
+            sdio_readb(card->func, cis_ptr + i, &ret);
+        if (ret) {
+            PRINTM(WARN, "get_cis_info error: ret=%d\n", ret);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        PRINTM(INFO, "cisinfo[%d]=%#x\n", i, ((unsigned char *) cisinfo)[i]);
+    }
+
+  done:
+    sdio_release_host(card->func);
+  exit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function downloads helper image to the card.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_prog_helper(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    u8 *helper = NULL;
+    int helperlen;
+    int ret = WLAN_STATUS_SUCCESS;
+    void *tmphlprbuf = NULL;
+    int tmphlprbufsz;
+    u8 *hlprbuf;
+    int hlprblknow;
+    u32 tx_len;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "sbi_prog_helper(): card or function is NULL!\n");
+        goto done;
+    }
+
+    if (priv->fw_helper) {
+        helper = priv->fw_helper->data;
+        helperlen = priv->fw_helper->size;
+    } else {
+        PRINTM(MSG, "No helper image found! Terminating download.\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    PRINTM(INFO, "Downloading helper image (%d bytes), block size %d bytes\n",
+           helperlen, SD_BLOCK_SIZE);
+
+    tmphlprbufsz = WLAN_UPLD_SIZE;
+    tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);
+    if (!tmphlprbuf) {
+        PRINTM(ERROR,
+               "Unable to allocate buffer for helper. Terminating download\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    memset(tmphlprbuf, 0, tmphlprbufsz);
+    hlprbuf = (u8 *) tmphlprbuf;
+
+    sdio_claim_host(card->func);
+
+    /* Perform helper data transfer */
+    tx_len = (FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE) - SDIO_HEADER_LEN;
+    hlprblknow = 0;
+    do {
+        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+        ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+        if (ret < 0) {
+            PRINTM(FATAL, "Helper download poll status timeout @ %d\n",
+                   hlprblknow);
+            goto done;
+        }
+
+        /* More data? */
+        if (hlprblknow >= helperlen)
+            break;
+
+        /* Set blocksize to transfer - checking for last block */
+        if (helperlen - hlprblknow < tx_len)
+            tx_len = helperlen - hlprblknow;
+
+        /* Set length to the 4-byte header */
+        *(u32 *) hlprbuf = wlan_cpu_to_le32(tx_len);
+
+        /* Copy payload to buffer */
+        memcpy(&hlprbuf[SDIO_HEADER_LEN], &helper[hlprblknow], tx_len);
+
+        PRINTM(INFO, ".");
+
+        /* Send data */
+        ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
+                           hlprbuf, FIRMWARE_TRANSFER_NBLOCK * SD_BLOCK_SIZE);
+
+        if (ret < 0) {
+            PRINTM(FATAL, "IO error during helper download @ %d\n",
+                   hlprblknow);
+            goto done;
+        }
+
+        hlprblknow += tx_len;
+    } while (TRUE);
+
+    /* Write last EOF data */
+    PRINTM(INFO, "\nTransferring helper image EOF block\n");
+    memset(hlprbuf, 0x0, SD_BLOCK_SIZE);
+    ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
+                       hlprbuf, SD_BLOCK_SIZE);
+
+    if (ret < 0) {
+        PRINTM(FATAL, "IO error in writing helper image EOF block\n");
+        goto done;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+
+  done:
+    sdio_release_host(card->func);
+    if (tmphlprbuf)
+        kfree(tmphlprbuf);
+
+    return ret;
+}
+
+/** 
+ *  @brief This function downloads firmware image to the card.
+ *  
+ *  @param priv    	A pointer to wlan_private structure
+ *  @return 	   	WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_prog_fw_w_helper(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    u8 *firmware = NULL;
+    int firmwarelen;
+    u8 base0;
+    u8 base1;
+    int ret = WLAN_STATUS_SUCCESS;
+    int offset;
+    void *tmpfwbuf = NULL;
+    int tmpfwbufsz;
+    u8 *fwbuf;
+    u16 len;
+    int txlen = 0;
+    int tx_blocks = 0;
+    int i = 0;
+    int tries = 0;
+
+    ENTER();
+
+    if (!card || !card->func) {
+        PRINTM(ERROR, "sbi_prog_fw_w_helper(): card or function is NULL!\n");
+        goto done;
+    }
+
+    if (priv->firmware) {
+        firmware = priv->firmware->data;
+        firmwarelen = priv->firmware->size;
+    } else {
+        PRINTM(MSG, "No firmware image found! Terminating download.\n");
+        return WLAN_STATUS_FAILURE;
+    }
+
+    PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);
+
+    tmpfwbufsz = WLAN_UPLD_SIZE;
+    tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
+    if (!tmpfwbuf) {
+        PRINTM(ERROR,
+               "Unable to allocate buffer for firmware. Terminating download.\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+    memset(tmpfwbuf, 0, tmpfwbufsz);
+    fwbuf = (u8 *) tmpfwbuf;
+
+    sdio_claim_host(card->func);
+
+    /* Perform firmware data transfer */
+    offset = 0;
+    do {
+        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
+        ret = mv_sdio_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
+        if (ret < 0) {
+            PRINTM(FATAL,
+                   "FW download with helper poll status timeout @ %d\n",
+                   offset);
+            goto done;
+        }
+
+        /* More data? */
+        if (offset >= firmwarelen)
+            break;
+
+        for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+            if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_0, &base0)) < 0) {
+                PRINTM(WARN, "Dev BASE0 register read failed:"
+                       " base0=0x%04X(%d). Terminating download.\n", base0,
+                       base0);
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            if ((ret = sbi_read_ioreg(priv, HOST_F1_RD_BASE_1, &base1)) < 0) {
+                PRINTM(WARN, "Dev BASE1 register read failed:"
+                       " base1=0x%04X(%d). Terminating download.\n", base1,
+                       base1);
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            len = (((u16) base1) << 8) | base0;
+
+            if (len != 0)
+                break;
+            udelay(10);
+        }
+
+        if (len == 0)
+            break;
+        else if (len > WLAN_UPLD_SIZE) {
+            PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
+                   offset, len);
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+
+        txlen = len;
+
+        if (len & BIT(0)) {
+            i++;
+            if (i > MAX_WRITE_IOMEM_RETRY) {
+                PRINTM(FATAL,
+                       "FW download failure @ %d, over max retry count\n",
+                       offset);
+                ret = WLAN_STATUS_FAILURE;
+                goto done;
+            }
+            PRINTM(ERROR, "FW CRC error indicated by the helper:"
+                   " len = 0x%04X, txlen = %d\n", len, txlen);
+            len &= ~BIT(0);
+            /* Setting this to 0 to resend from same offset */
+            txlen = 0;
+        } else
+            i = 0;
+
+        /* Set blocksize to transfer - checking for last block */
+        if (firmwarelen - offset < txlen) {
+            txlen = firmwarelen - offset;
+        }
+        PRINTM(INFO, ".");
+
+        tx_blocks = (txlen + SD_BLOCK_SIZE - 1) / SD_BLOCK_SIZE;
+
+        /* Copy payload to buffer */
+        memcpy(fwbuf, &firmware[offset], txlen);
+
+        /* Send data */
+        ret = sdio_writesb(card->func, priv->wlan_dev.ioport,
+                           fwbuf, tx_blocks * SD_BLOCK_SIZE);
+        if (ret < 0) {
+            PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
+                   offset);
+            if (sbi_write_ioreg(priv, CONFIGURATION_REG, 0x04) < 0) {
+                PRINTM(ERROR, "write ioreg failed (CFG)\n");
+            }
+        }
+
+        offset += txlen;
+    } while (TRUE);
+
+    PRINTM(INFO, "\nFW download over, size %d bytes\n", firmwarelen);
+
+    ret = WLAN_STATUS_SUCCESS;
+  done:
+    sdio_release_host(card->func);
+    if (tmpfwbuf)
+        kfree(tmpfwbuf);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function checks if the firmware is ready to accept
+ *  command or not.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_check_fw_status(wlan_private * priv, int pollnum)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 firmwarestat;
+    int tries;
+
+    ENTER();
+
+    sdio_claim_host(card->func);
+
+    /* Wait for firmware initialization event */
+    for (tries = 0; tries < pollnum; tries++) {
+        if (!priv->enhance_flag) {
+            if ((ret = mv_sdio_read_scratch(priv, &firmwarestat)) < 0)
+                continue;
+        } else {
+            if ((ret = sd_read_firmware_status(priv, &firmwarestat)) < 0)
+                continue;
+        }
+
+        if (firmwarestat == FIRMWARE_READY) {
+            ret = WLAN_STATUS_SUCCESS;
+            break;
+        } else {
+            mdelay(10);
+            ret = WLAN_STATUS_FAILURE;
+        }
+    }
+
+    if (ret < 0) {
+        PRINTM(WARN, "Timeout waiting for FW to become active\n");
+        goto done;
+    }
+
+    ret = WLAN_STATUS_SUCCESS;
+    if (priv->enhance_flag)
+        sd_get_rx_unit(priv);
+  done:
+    sdio_release_host(card->func);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function set bus clock on/off
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param option    TRUE--on , FALSE--off
+ *  @return 	   WLAN_STATUS_SUCCESS
+ */
+int
+sbi_set_bus_clock(wlan_private * priv, u8 option)
+{
+	/*
+    if (option == TRUE)
+        sd_start_clock((psd_device) priv->wlan_dev.card);
+    else
+        sd_stop_clock((psd_device) priv->wlan_dev.card);
+    */  
+        
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief This function makes firmware exiting from deep sleep.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_exit_deep_sleep(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    sdio_claim_host(card->func);
+
+    sbi_set_bus_clock(priv, TRUE);
+
+    if (priv->adapter->fwWakeupMethod == WAKEUP_FW_THRU_GPIO) {
+        GPIO_PORT_TO_LOW();
+    } else
+        ret = sbi_write_ioreg(priv, CONFIGURATION_REG, HOST_POWER_UP);
+
+    sdio_release_host(card->func);
+
+    return ret;
+}
+
+/** 
+ *  @brief This function resets the setting of deep sleep.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+sbi_reset_deepsleep_wakeup(wlan_private * priv)
+{
+    struct sdio_mmc_card *card = priv->wlan_dev.card;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+
+	if (priv->adapter->fwWakeupMethod == WAKEUP_FW_THRU_GPIO) {
+		GPIO_PORT_TO_HIGH();
+	} else {
+		sdio_claim_host(card->func);
+		ret = sbi_write_ioreg(priv, CONFIGURATION_REG, 0);
+		sdio_release_host(card->func);
+	}
+
+
+    LEAVE();
+
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_sdio.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,206 @@
+/** @file wlan_sdio.h
+ *  @brief This file contains SDIO IF (interface) module
+ *  related macros, enum, and structure.
+ * 
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+	10/12/05: add Doxygen format comments 
+****************************************************/
+
+#ifndef	_WLAN_SDIO_H
+#define	_WLAN_SDIO_H
+#include	<linux/mmc/sdio.h>
+#include	<linux/mmc/sdio_ids.h>
+#include	<linux/mmc/sdio_func.h>
+#include	<linux/mmc/card.h>
+
+#include	<wlan_headers.h>
+
+/** SDIO Function */
+#define SDIO_FUNC(x)			(x)
+/** SDIO Function 0 */
+#define SDIO_FUNC0			SDIO_FUNC(0)
+/** SDIO Function 1 */
+#define SDIO_FUNC1			SDIO_FUNC(1)
+
+//#include	<sdio.h>
+
+/** SD BUS width = 1 */
+#define SD_BUS_WIDTH_1			0x00
+/** SD BUS width = 4 */
+#define SD_BUS_WIDTH_4			0x02
+/** SD BUS width mask */
+#define SD_BUS_WIDTH_MASK		0x03
+/** Asynchronous interrupt mode */
+#define ASYNC_INT_MODE			0x20
+
+/* Host Control Registers */
+/** Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG			0x00
+/** Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG			0x01
+/** Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG			0x02
+/** Host Control Registers : Configuration */
+#define CONFIGURATION_REG		0x03
+/** Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST	(0x1U << 2)
+/** Host Control Registers : Host power up */
+#define HOST_POWER_UP			(0x1U << 1)
+/** Host Control Registers : Host power down */
+#define HOST_POWER_DOWN			(0x1U << 0)
+/** Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG		0x04
+/** Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK		(0x1U)
+/** Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK		(0x2U)
+/** Host Control Registers : Host interrupt status */
+#define HOST_INTSTATUS_REG		0x05
+/** Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS		(0x1U)
+/** Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS		(0x2U)
+/** Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG		0x06
+/** Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR		(0x1U)
+/** Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG		0x07
+/** Host Control Registers : Upload CRC error */
+#define UP_LD_CRC_ERR			(0x1U << 2)
+/** Host Control Registers : Upload restart */
+#define UP_LD_RESTART              	(0x1U << 1)
+/** Host Control Registers : Download restart */
+#define DN_LD_RESTART              	(0x1U << 0)
+
+/* Card Control Registers */
+/** Card Control Registers : Read SQ base address A0 register */
+#define SQ_READ_BASE_ADDRESS_A0_REG  	0x10
+/** Card Control Registers : Read SQ base address A1 register */
+#define SQ_READ_BASE_ADDRESS_A1_REG  	0x11
+/** Card Control Registers : Read SQ base address A2 register */
+#define SQ_READ_BASE_ADDRESS_A2_REG  	0x12
+/** Card Control Registers : Read SQ base address A3 register */
+#define SQ_READ_BASE_ADDRESS_A3_REG  	0x13
+/** Card Control Registers : Read SQ base address B0 register */
+#define SQ_READ_BASE_ADDRESS_B0_REG  	0x14
+/** Card Control Registers : Read SQ base address B1 register */
+#define SQ_READ_BASE_ADDRESS_B1_REG  	0x15
+/** Card Control Registers : Read SQ base address B2 register */
+#define SQ_READ_BASE_ADDRESS_B2_REG  	0x16
+/** Card Control Registers : Read SQ base address B3 register */
+#define SQ_READ_BASE_ADDRESS_B3_REG  	0x17
+/** Card Control Registers : Card status register */
+#define CARD_STATUS_REG              	0x20
+/** Card Control Registers : Card I/O ready */
+#define CARD_IO_READY              	(0x1U << 3)
+/** Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY                 	(0x1U << 2)
+/** Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY               	(0x1U << 1)
+/** Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY               	(0x1U << 0)
+/** Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG      	0x24
+/** Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK          	(0x1U << 3)
+/** Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK          	(0x1U << 2)
+/** Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK          	(0x1U << 1)
+/** Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK          	(0x1U << 0)
+/** Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG    	0x28
+/** Card Control Registers : Power up interrupt */
+#define POWER_UP_INT                 	(0x1U << 4)
+/** Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT               	(0x1U << 3)
+/** Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG       	0x2c
+/** Card Control Registers : Power up RSR */
+#define POWER_UP_RSR                 	(0x1U << 4)
+/** Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR               	(0x1U << 3)
+/** Card Control Registers : Debug 0 register */
+#define DEBUG_0_REG                  	0x30
+/** Card Control Registers : SD test BUS 0 */
+#define SD_TESTBUS0                  	(0x1U)
+/** Card Control Registers : Debug 1 register */
+#define DEBUG_1_REG                  	0x31
+/** Card Control Registers : SD test BUS 1 */
+#define SD_TESTBUS1                  	(0x1U)
+/** Card Control Registers : Debug 2 register */
+#define DEBUG_2_REG                  	0x32
+/** Card Control Registers : SD test BUS 2 */
+#define SD_TESTBUS2                  	(0x1U)
+/** Card Control Registers : Debug 3 register */
+#define DEBUG_3_REG                  	0x33
+/** Card Control Registers : SD test BUS 3 */
+#define SD_TESTBUS3                  	(0x1U)
+/** Card Control Registers : Card OCR 0 register */
+#define CARD_OCR_0_REG               	0x34
+/** Card Control Registers : Card OCR 1 register */
+#define CARD_OCR_1_REG               	0x35
+/** Card Control Registers : Card OCR 3 register */
+#define CARD_OCR_3_REG               	0x36
+/** Card Control Registers : Card config register */
+#define CARD_CONFIG_REG              	0x38
+/** Card Control Registers : Card revision register */
+#define CARD_REVISION_REG            	0x3c
+/** Card Control Registers : Command 53 finish G BUS */
+#define CMD53_FINISH_GBUS            	(0x1U << 1)
+/** Card Control Registers : SD negative edge */
+#define SD_NEG_EDGE                  	(0x1U << 0)
+
+/* Special registers in function 0 of the SDxx card */
+/** Special register in function 0 of the SDxxx card : Scratch 0 */
+#define	SCRATCH_0_REG			0x80fe
+/** Special register in function 0 of the SDxxx card : Scratch 1 */
+#define	SCRATCH_1_REG			0x80ff
+/** Host F1 read base 0 */
+#define HOST_F1_RD_BASE_0		0x0010
+/** Host F1 read base 1 */
+#define HOST_F1_RD_BASE_1		0x0011
+/** Host F1 card ready */
+#define HOST_F1_CARD_RDY		0x0020
+
+/** Chip Id Register 0 */
+#define CARD_CHIP_ID_0_REG		0x801c
+/** Chip Id Register 1 */
+#define CARD_CHIP_ID_1_REG		0x801d
+/** Firmware status 0 register */
+#define CARD_FW_STATUS0_REG		0x40
+/** Firmware status 1 register */
+#define CARD_FW_STATUS1_REG		0x41
+/** Rx length register */
+#define CARD_RX_LEN_REG			0x42
+/** Rx unit register */
+#define CARD_RX_UNIT_REG		0x43
+
+struct sdio_mmc_card
+{
+	struct sdio_func *func;
+        wlan_private *priv;
+};
+
+
+int sbi_read_iomem(wlan_private *priv, void *buf, unsigned int reg_addr, int cnt);
+#endif /* _WLAN_SDIO_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_tx.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_tx.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_tx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_tx.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,317 @@
+/** @file wlan_tx.c
+  * @brief This file contains the handling of TX in wlan
+  * driver.
+  *    
+  *  (c) Copyright © 2003-2006, Marvell International Ltd.  
+  *   
+  *  This software file (the "File") is distributed by Marvell International 
+  *  Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  *  (the "License").  You may use, redistribute and/or modify this File in 
+  *  accordance with the terms and conditions of the License, a copy of which 
+  *  is available along with the File in the gpl.txt file or by writing to 
+  *  the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  *  02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  *  this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	09/28/05: Add Doxygen format comments
+	12/13/05: Add Proprietary periodic sleep support
+	01/05/06: Add kernel 2.6.x support	
+	04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+********************************************************/
+
+#include	"wlan_headers.h"
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/********************************************************
+		Global Variables
+********************************************************/
+
+/********************************************************
+		Local Functions
+********************************************************/
+
+/** 
+ *  @brief This function processes a single packet and sends
+ *  to IF layer
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @param skb     A pointer to skb which includes TX packet
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+static int
+wlan_send_single_packet(wlan_private * priv, struct sk_buff *skb)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    TxPD *pLocalTxPD;
+    u8 *headptr;
+    struct sk_buff *newskb;
+    int newheadlen;
+
+    ENTER();
+
+    ASSERT(skb);
+
+    if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+        PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n",
+               skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (skb_headroom(skb) < (sizeof(TxPD) + SDIO_HEADER_LEN)) {
+        newheadlen = sizeof(TxPD) + SDIO_HEADER_LEN;
+        PRINTM(WARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb));
+
+        /* Insufficient skb headroom - allocate a new skb */
+        newskb = skb_realloc_headroom(skb, newheadlen);
+        if (unlikely(newskb == NULL)) {
+            PRINTM(ERROR, "Tx: Cannot allocate skb\n");
+            ret = WLAN_STATUS_FAILURE;
+            goto done;
+        }
+        kfree_skb(skb);
+        skb = newskb;
+
+        Adapter->CurrentTxSkb = skb;
+        PRINTM(INFO, "new skb headroom %d\n", skb_headroom(skb));
+    }
+
+    /* The skb->head is always 16-byte aligned */
+    headptr = skb->head;
+    pLocalTxPD = (TxPD *) (headptr + SDIO_HEADER_LEN);
+
+    memset(pLocalTxPD, 0, sizeof(TxPD));
+
+    pLocalTxPD->TxPacketLength = skb->len;
+
+    /* 
+     * original skb->priority has been overwritten 
+     * by wmm_map_and_add_skb()
+     */
+    pLocalTxPD->Priority = (u8) skb->priority;
+    pLocalTxPD->PktDelay_2ms = wmm_compute_driver_packet_delay(priv, skb);
+
+    if (pLocalTxPD->Priority < NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
+        /* 
+         * Set the priority specific TxControl field, setting of 0 will
+         *   cause the default value to be used later in this function
+         */
+        pLocalTxPD->TxControl
+            = Adapter->wmm.userPriPktTxCtrl[pLocalTxPD->Priority];
+    }
+
+    if (Adapter->PSState != PS_STATE_FULL_POWER) {
+        if (TRUE == wlan_check_last_packet_indication(priv)) {
+            Adapter->TxLockFlag = TRUE;
+            pLocalTxPD->Flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
+        }
+    }
+
+    /* offset of actual data */
+    pLocalTxPD->TxPacketLocation = (long) skb->data - (long) pLocalTxPD;
+
+    if (pLocalTxPD->TxControl == 0) {
+        /* TxCtrl set by user or default */
+        pLocalTxPD->TxControl = Adapter->PktTxCtrl;
+    }
+
+    endian_convert_TxPD(pLocalTxPD);
+
+    memcpy((u8 *) pLocalTxPD->TxDestAddr, skb->data, ETH_ALEN);
+
+    ret = sbi_host_to_card(priv, MV_TYPE_DAT, headptr,
+                           skb->len + ((long) skb->data - (long) pLocalTxPD));
+    if (ret) {
+        PRINTM(ERROR,
+               "wlan_send_single_packet Error: sbi_host_to_card failed: 0x%X\n",
+               ret);
+        Adapter->dbg.num_tx_host_to_card_failure++;
+        goto done;
+    }
+
+    PRINTM(DATA, "Data => FW\n");
+    DBG_HEXDUMP(DAT_D, "Tx", headptr,
+                MIN(skb->len + sizeof(TxPD), MAX_DATA_DUMP_LEN));
+
+    wmm_process_fw_iface_tx_xfer_start(priv);
+
+  done:
+    if (!ret) {
+        priv->stats.tx_packets++;
+        priv->stats.tx_bytes += skb->len;
+    } else {
+        priv->stats.tx_dropped++;
+        priv->stats.tx_errors++;
+    }
+
+    /* need to be freed in all cases */
+    os_free_tx_packet(priv);
+
+    LEAVE();
+    return ret;
+}
+
+/********************************************************
+		Global functions
+********************************************************/
+
+/** 
+ *  @brief This function checks the conditions and sends packet to IF
+ *  layer if everything is ok.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void
+wlan_process_tx(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    unsigned long driver_flags;
+
+    ENTER();
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    if (priv->wlan_dev.dnld_sent) {
+        PRINTM(MSG, "TX Error: dnld_sent = %d, not sending\n",
+               priv->wlan_dev.dnld_sent);
+        goto done;
+    }
+
+    wlan_send_single_packet(priv, Adapter->CurrentTxSkb);
+    OS_INT_DISABLE(priv, driver_flags);
+    priv->adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
+    OS_INT_RESTORE(priv, driver_flags);
+
+  done:
+    LEAVE();
+}
+
+/** 
+ *  @brief This function queues the packet received from
+ *  kernel/upper layer and wake up the main thread to handle it.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+  * @param skb     A pointer to skb which includes TX packet
+ *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
+ */
+int
+wlan_tx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+    ulong flags;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    HEXDUMP("TX Data", skb->data, MIN(skb->len, 100));
+
+    spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
+
+    wmm_map_and_add_skb(priv, skb);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+    spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief This function tells firmware to send a NULL data packet.
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *  @param flags    Trasnit Pkt Flags
+ *  @return 	    n/a
+ */
+int
+wlan_send_null_packet(wlan_private * priv, u8 flags)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    TxPD *ptxpd;
+/* sizeof(TxPD) + Interface specific header */
+#define NULL_PACKET_HDR 64
+    u8 tmpbuf[NULL_PACKET_HDR] = { 0 };
+    u8 *ptr = tmpbuf;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->SurpriseRemoved == TRUE) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    ptr += SDIO_HEADER_LEN;
+    ptxpd = (TxPD *) ptr;
+
+    ptxpd->TxControl = Adapter->PktTxCtrl;
+    ptxpd->Flags = flags;
+    ptxpd->Priority = WMM_HIGHEST_PRIORITY;
+    ptxpd->TxPacketLocation = sizeof(TxPD);
+
+    endian_convert_TxPD(ptxpd);
+
+    ret = sbi_host_to_card(priv, MV_TYPE_DAT, tmpbuf, sizeof(TxPD));
+
+    if (ret != 0) {
+        PRINTM(ERROR, "TX Error: wlan_send_null_packet failed!\n");
+        Adapter->dbg.num_tx_host_to_card_failure++;
+        goto done;
+    }
+    PRINTM(DATA, "Null data => FW\n");
+    DBG_HEXDUMP(DAT_D, "Tx", ptr, sizeof(TxPD));
+
+  done:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief This function check if we need send last packet indication.
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *
+ *  @return 	   TRUE or FALSE
+ */
+BOOLEAN
+wlan_check_last_packet_indication(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    BOOLEAN ret = FALSE;
+    BOOLEAN prop_ps = TRUE;
+
+    ENTER();
+
+    if (Adapter->sleep_period.period == 0 || Adapter->gen_null_pkg == FALSE     /* for UPSD certification tests */
+        ) {
+        LEAVE();
+        return ret;
+    }
+
+    if (wmm_lists_empty(priv)) {
+        if (((Adapter->CurBssParams.wmm_uapsd_enabled == TRUE)
+             && (Adapter->wmm.qosinfo != 0)) || prop_ps) {
+            ret = TRUE;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wext.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wext.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wext.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wext.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,8971 @@
+/** @file  wlan_wext.c 
+  * @brief This file contains ioctl functions
+  * 
+  * (c) Copyright © 2003-2007, Marvell International Ltd. 
+  *
+  * This software file (the "File") is distributed by Marvell International 
+  * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+  * (the "License").  You may use, redistribute and/or modify this File in 
+  * accordance with the terms and conditions of the License, a copy of which 
+  * is available along with the File in the gpl.txt file or by writing to 
+  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+  * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+  *
+  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+  * this warranty disclaimer.
+  *
+  */
+/********************************************************
+Change log:
+	10/10/05: Add Doxygen format comments
+	12/23/05: Modify FindBSSIDInList to search entire table for
+	          duplicate BSSIDs when earlier matches are not compatible
+	12/26/05: Remove errant memcpy in wlanidle_off; overwriting stack space
+	01/05/06: Add kernel 2.6.x support	
+	01/11/06: Conditionalize new scan/join functions.
+	          Update statics/externs.  Move forward decl. from wlan_decl.h
+	04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+	04/10/06: Add hostcmd generic API
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	05/04/06: Add IBSS coalescing related new iwpriv command
+	08/29/06: Add ledgpio private command
+	10/23/06: Validate setbcnavg/setdataavg command parameters and
+	          return error if out of range
+********************************************************/
+
+#include	"wlan_headers.h"
+
+/** Get log buffer size */
+#define GETLOG_BUFSIZE  512
+
+/** Maximum scan cell size */
+#define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
+				MRVDRV_MAX_SSID_LENGTH + \
+				IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+				IW_EV_QUAL_LEN + MRVDRV_MAX_SSID_LENGTH + \
+				IW_EV_PARAM_LEN + 40)   /* 40 for WPAIE */
+
+typedef struct _ioctl_cmd
+{
+    /** IOCTL command number */
+    int cmd;
+    /** IOCTL subcommand number */
+    int subcmd;
+    /** Size fix flag */
+    BOOLEAN fixsize;
+} ioctl_cmd;
+
+static ioctl_cmd Commands_Allowed_In_DeepSleep[] = {
+    {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLAN_SETONEINT_GETWORDCHAR,.subcmd = WLANVERSION,.fixsize =
+     FALSE},
+    {.cmd = WLAN_SETINT_GETINT,.subcmd = WLANSDIOCLOCK,.fixsize = TRUE},
+    {.cmd = WLAN_SET_GET_2K,.subcmd = WLAN_GET_CFP_TABLE,.fixsize = FALSE},
+#ifdef DEBUG_LEVEL1
+    {.cmd = WLAN_SET_GET_SIXTEEN_INT,.subcmd = WLAN_DRV_DBG,.fixsize = FALSE},
+#endif
+};
+
+static ioctl_cmd Commands_Allowed_In_HostSleep[] = {
+    {.cmd = WLAN_SETONEINT_GETWORDCHAR,.subcmd = WLANVERSION,.fixsize =
+     FALSE},
+    {.cmd = WLANDEEPSLEEP,.subcmd = 1,.fixsize = FALSE},
+    {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLAN_SETINT_GETINT,.subcmd = WLANSDIOCLOCK,.fixsize = TRUE},
+    {.cmd = WLAN_SET_GET_2K,.subcmd = WLAN_GET_CFP_TABLE,.fixsize = FALSE},
+#ifdef DEBUG_LEVEL1
+    {.cmd = WLAN_SET_GET_SIXTEEN_INT,.subcmd = WLAN_DRV_DBG,.fixsize = FALSE},
+#endif
+};
+
+static ioctl_cmd Commands_DisAllowed_In_AutoDeepSleep[] = {
+    {.cmd = WLANDEEPSLEEP,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLANCMD52RDWR,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLANCMD53RDWR,.subcmd = 0,.fixsize = FALSE},
+    {.cmd = WLANCISDUMP,.subcmd = 0,.fixsize = FALSE},
+};
+
+/********************************************************
+		Local Variables
+********************************************************/
+
+/********************************************************
+		Global Variables
+********************************************************/
+#ifdef DEBUG_LEVEL1
+#ifdef DEBUG_LEVEL2
+#define	DEFAULT_DEBUG_MASK	(0xffffffff & ~DBG_EVENT)
+#else
+#define DEFAULT_DEBUG_MASK	(DBG_MSG | DBG_FATAL | DBG_ERROR)
+#endif
+u32 drvdbg = DEFAULT_DEBUG_MASK;
+u32 ifdbg = 0;
+#endif
+
+/********************************************************
+		Local Functions
+********************************************************/
+static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra);
+static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_param *vwrq, char *extra);
+
+static int wlan_get_essid(struct net_device *dev,
+                          struct iw_request_info *info, struct iw_point *dwrq,
+                          char *extra);
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_freq *fwrq, char *extra);
+static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+                         struct iw_freq *fwrq, char *extra);
+
+static int wlan_set_mode(struct net_device *dev, struct iw_request_info *info,
+                         u32 * uwrq, char *extra);
+static int wlan_get_mode(struct net_device *dev, struct iw_request_info *info,
+                         u32 * uwrq, char *extra);
+
+static int wlan_set_encode(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct iw_point *dwrq, char *extra);
+static int wlan_get_encode(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct iw_point *dwrq, u8 * extra);
+
+static int wlan_set_txpow(struct net_device *dev,
+                          struct iw_request_info *info, struct iw_param *vwrq,
+                          char *extra);
+static int wlan_get_txpow(struct net_device *dev,
+                          struct iw_request_info *info, struct iw_param *vwrq,
+                          char *extra);
+
+static int wlan_set_coalescing_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+/** 
+ *  @brief This function checks if the commans is allowed
+ *  in deepsleep/hostsleep mode or not.
+ * 
+ *  @param req	       A pointer to ifreq structure 
+ *  @param cmd         the command ID
+ *  @return 	   TRUE or FALSE
+ */
+static BOOLEAN
+wlan_is_cmd_allowed_in_ds_hs(struct ifreq *req, int cmd,
+                             ioctl_cmd * allowed_cmds, int count)
+{
+    int subcmd = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < count; i++) {
+        if (cmd == allowed_cmds[i].cmd) {
+            if (allowed_cmds[i].subcmd == 0) {
+                LEAVE();
+                return TRUE;
+            }
+            if (allowed_cmds[i].fixsize == TRUE)
+                subcmd = (int) req->ifr_data;
+            else
+                subcmd = wrq->u.data.flags;
+            if (allowed_cmds[i].subcmd == subcmd) {
+                LEAVE();
+                return TRUE;
+            }
+        }
+    }
+
+    LEAVE();
+
+    return FALSE;
+}
+
+/** 
+ *  @brief This function checks if the commans is disallowed
+ *  in auto deepsleep mode.
+ * 
+ *  @param req		A pointer to ifreq structure 
+ *  @param cmd		Command ID
+ *  @return   		TRUE or FALSE
+ */
+static BOOLEAN
+wlan_is_cmd_disallowed_in_ads(struct ifreq *req, int cmd,
+                              ioctl_cmd * disallowed_cmds, int count)
+{
+    int subcmd = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < count; i++) {
+        if (cmd == disallowed_cmds[i].cmd) {
+            if (disallowed_cmds[i].subcmd == 0) {
+                LEAVE();
+                return TRUE;
+            }
+            if (disallowed_cmds[i].fixsize == TRUE)
+                subcmd = (int) req->ifr_data;
+            else
+                subcmd = wrq->u.data.flags;
+            if (disallowed_cmds[i].subcmd == subcmd) {
+                LEAVE();
+                return TRUE;
+            }
+        }
+    }
+
+    LEAVE();
+    return FALSE;
+}
+
+/** 
+ *  @brief This function checks if the command is allowed.
+ * 
+ *  @param priv		A pointer to wlan_private structure
+ *  @return		TRUE or FALSE
+ */
+BOOLEAN
+wlan_is_cmd_allowed(wlan_private * priv)
+{
+    BOOLEAN ret = TRUE;
+
+    ENTER();
+
+    if (priv->adapter->bHostSleepConfigured) {
+        PRINTM(INFO, "IOCTLS called when WLAN access is blocked\n");
+        ret = FALSE;
+    }
+    if (!priv->adapter->IsAutoDeepSleepEnabled) {
+        if ((priv->adapter->IsDeepSleep == TRUE)) {
+            PRINTM(INFO, "IOCTLS called when station is in DeepSleep\n");
+            ret = FALSE;
+        }
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief Find a character in a string.
+ *   
+ *  @param s	   A pointer to string
+ *  @param c	   Character to be located 
+ *  @param n       the length of string
+ *  @return 	   A pointer to the first occurrence of c in string, or NULL if c is not found.
+ */
+static void *
+wlan_memchr(void *s, int c, int n)
+{
+    const u8 *p = s;
+
+    ENTER();
+
+    while (n-- != 0) {
+        if ((u8) c == *p++) {
+            LEAVE();
+            return (void *) (p - 1);
+        }
+    }
+
+    LEAVE();
+
+    return NULL;
+}
+
+#if WIRELESS_EXT > 14
+/** 
+ *  @brief This function sends customized event to application.
+ *  
+ *  @param priv    A pointer to wlan_private structure
+ *  @para str	   A pointer to event string
+ *  @return 	   n/a
+ */
+void
+send_iwevcustom_event(wlan_private * priv, s8 * str)
+{
+    union iwreq_data iwrq;
+    u8 buf[50];
+
+    ENTER();
+
+    memset(&iwrq, 0, sizeof(union iwreq_data));
+    memset(buf, 0, sizeof(buf));
+
+    snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+    iwrq.data.pointer = buf;
+    iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+    /* Send Event to upper layer */
+    wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+    PRINTM(INFO, "Wireless event %s is sent to app\n", str);
+
+    LEAVE();
+    return;
+}
+#endif
+
+/** 
+ *  @brief get the channel frequency power info with specific channel
+ *   
+ *  @param band	 		it can be BAND_A, BAND_G or BAND_B
+ *  @param channel       	the channel for looking	
+ *  @param region_channel 	A pointer to REGION_CHANNEL structure
+ *  @return 	   			A pointer to CHANNEL_FREQ_POWER structure or NULL if not find.
+ */
+
+CHANNEL_FREQ_POWER *
+get_cfp_by_band_and_channel(u8 band, u16 channel,
+                            REGION_CHANNEL * region_channnel)
+{
+    REGION_CHANNEL *rc;
+    CHANNEL_FREQ_POWER *cfp = NULL;
+    int i, j;
+
+    for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) {
+        rc = &region_channnel[j];
+
+        if (!rc->Valid || !rc->CFP)
+            continue;
+        switch (rc->Band) {
+        case BAND_A:
+            switch (band) {
+            case BAND_A:       // matching BAND_A
+                break;
+            default:
+                continue;
+            }
+            break;
+        case BAND_B:
+        case BAND_G:
+            switch (band) {
+            case BAND_B:       //matching BAND_B/G
+            case BAND_G:
+                break;
+            default:
+                continue;
+            }
+            break;
+        default:
+            continue;
+        }
+        if (channel == FIRST_VALID_CHANNEL)
+            cfp = &rc->CFP[0];
+        else {
+            for (i = 0; i < rc->NrCFP; i++) {
+                if (rc->CFP[i].Channel == channel) {
+                    cfp = &rc->CFP[i];
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!cfp && channel)
+        PRINTM(INFO, "get_cfp_by_band_and_channel(): cannot find "
+               "cfp by band %d & channel %d\n", band, channel);
+
+    LEAVE();
+    return cfp;
+}
+
+/** 
+ *  @brief Find the channel frequency power info with specific channel
+ *   
+ *  @param adapter 	A pointer to wlan_adapter structure
+ *  @param band		it can be BAND_A, BAND_G or BAND_B
+ *  @param channel      the channel for looking	
+ *  @return 	   	A pointer to CHANNEL_FREQ_POWER structure or NULL if not find.
+ */
+CHANNEL_FREQ_POWER *
+find_cfp_by_band_and_channel(wlan_adapter * adapter, u8 band, u16 channel)
+{
+    CHANNEL_FREQ_POWER *cfp = NULL;
+
+    ENTER();
+
+    if (adapter->State11D.Enable11D == ENABLE_11D)
+        cfp =
+            get_cfp_by_band_and_channel(band, channel,
+                                        adapter->universal_channel);
+    else
+        cfp =
+            get_cfp_by_band_and_channel(band, channel,
+                                        adapter->region_channel);
+
+    return cfp;
+}
+
+/** 
+ *  @brief Find the channel frequency power info with specific frequency
+ *   
+ *  @param adapter  A pointer to wlan_adapter structure
+ *  @param band     it can be BAND_A, BAND_G or BAND_B
+ *  @param freq     the frequency for looking   
+ *  @return         Pointer to CHANNEL_FREQ_POWER structure; NULL if not found
+ */
+static CHANNEL_FREQ_POWER *
+find_cfp_by_band_and_freq(wlan_adapter * adapter, u8 band, u32 freq)
+{
+    CHANNEL_FREQ_POWER *cfp = NULL;
+    REGION_CHANNEL *rc;
+    int count = sizeof(adapter->region_channel) /
+        sizeof(adapter->region_channel[0]);
+    int i, j;
+
+    ENTER();
+
+    for (j = 0; !cfp && (j < count); j++) {
+        rc = &adapter->region_channel[j];
+
+        if (adapter->State11D.Enable11D == ENABLE_11D) {
+            rc = &adapter->universal_channel[j];
+        }
+
+        if (!rc->Valid || !rc->CFP)
+            continue;
+        switch (rc->Band) {
+        case BAND_A:
+            switch (band) {
+            case BAND_A:       // matching BAND_A
+                break;
+            default:
+                continue;
+            }
+            break;
+        case BAND_B:
+        case BAND_G:
+            switch (band) {
+            case BAND_B:
+            case BAND_G:
+                break;
+            default:
+                continue;
+            }
+            break;
+        default:
+            continue;
+        }
+        for (i = 0; i < rc->NrCFP; i++) {
+            if (rc->CFP[i].Freq == freq) {
+                cfp = &rc->CFP[i];
+                break;
+            }
+        }
+    }
+
+    if (!cfp && freq)
+        PRINTM(INFO, "find_cfp_by_band_and_freql(): cannot find cfp by "
+               "band %d & freq %d\n", band, freq);
+
+    LEAVE();
+
+    return cfp;
+}
+
+#ifdef MFG_CMD_SUPPORT
+/** 
+ *  @brief Manufacturing command ioctl function
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq 		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+static int
+wlan_mfg_command(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_GEN *pCmdPtr;
+    u8 *mfg_cmd;
+    u16 mfg_cmd_len;
+    int ret;
+
+    ENTER();
+
+    /* allocate MFG command buffer */
+    if (!(mfg_cmd = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
+        PRINTM(INFO, "allocate MFG command buffer failed!\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+
+    /* get MFG command header */
+    if (copy_from_user(mfg_cmd, wrq->u.data.pointer, sizeof(HostCmd_DS_GEN))) {
+        PRINTM(INFO, "copy from user failed: MFG command header\n");
+        ret = -EFAULT;
+        goto mfg_exit;
+    }
+
+    /* get the command size */
+    pCmdPtr = (HostCmd_DS_GEN *) mfg_cmd;
+    mfg_cmd_len = pCmdPtr->Size;
+    PRINTM(INFO, "MFG command len = %d\n", mfg_cmd_len);
+
+    if (mfg_cmd_len > MRVDRV_SIZE_OF_CMD_BUFFER) {
+        ret = -EINVAL;
+        goto mfg_exit;
+    }
+
+    /* get the whole command from user */
+    if (copy_from_user(mfg_cmd, wrq->u.data.pointer, mfg_cmd_len)) {
+        PRINTM(INFO, "copy from user failed: MFG command\n");
+        ret = -EFAULT;
+        goto mfg_exit;
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_MFG_COMMAND,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, mfg_cmd);
+
+    /* copy the response back to user */
+    if (!ret && pCmdPtr->Size) {
+        mfg_cmd_len = MIN(pCmdPtr->Size, mfg_cmd_len);
+        if (copy_to_user(wrq->u.data.pointer, mfg_cmd, mfg_cmd_len)) {
+            PRINTM(INFO, "copy to user failed: MFG command\n");
+            ret = -EFAULT;
+        }
+        wrq->u.data.length = mfg_cmd_len;
+    }
+
+  mfg_exit:
+    kfree(mfg_cmd);
+    LEAVE();
+    return ret;
+}
+#endif
+
+/** 
+ *  @brief Check if Rate Auto
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @return 	   		TRUE/FALSE
+ */
+BOOLEAN
+wlan_is_rate_auto(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    int ratenum = 0;
+    int bitsize = 0;
+
+    ENTER();
+
+    bitsize = sizeof(Adapter->RateBitmap) * 8;
+    for (i = 0; i < bitsize; i++) {
+        if (Adapter->RateBitmap & (1 << i))
+            ratenum++;
+        if (ratenum > 1)
+            break;
+    }
+
+    LEAVE();
+
+    if (ratenum > 1)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+/** 
+ *  @brief Covert Rate Bitmap to Rate index
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @return 	   		TRUE/FALSE
+ */
+int
+wlan_get_rate_index(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int bitsize = sizeof(Adapter->RateBitmap) * 8;
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < bitsize; i++) {
+        if (Adapter->RateBitmap & (1 << i)) {
+            LEAVE();
+            return i;
+        }
+    }
+
+    LEAVE();
+
+    return 0;
+}
+
+/** 
+ *  @brief Update Current Channel 
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+static int
+wlan_update_current_chan(wlan_private * priv)
+{
+    int ret;
+
+    /*
+     ** the channel in f/w could be out of sync, get the current channel
+     */
+    ENTER();
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+                           HostCmd_OPT_802_11_RF_CHANNEL_GET,
+                           HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    PRINTM(INFO, "Current Channel = %d\n",
+           priv->adapter->CurBssParams.BSSDescriptor.Channel);
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief Set Current Channel 
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @param channel		The channel to be set. 
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+static int
+wlan_set_current_chan(wlan_private * priv, int channel)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    PRINTM(INFO, "Set Channel = %d\n", channel);
+
+    /* 
+     **  Current channel is not set to AdhocChannel requested, set channel
+     */
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+                           HostCmd_OPT_802_11_RF_CHANNEL_SET,
+                           HostCmd_OPTION_WAITFORRSP, 0, &channel);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Change Adhoc Channel
+ *   
+ *  @param priv 		A pointer to wlan_private structure
+ *  @param channel		The channel to be set. 
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail
+ */
+static int
+wlan_change_adhoc_chan(wlan_private * priv, int channel)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+    Adapter->AdhocChannel = channel;
+
+    wlan_update_current_chan(priv);
+
+    if (Adapter->CurBssParams.BSSDescriptor.Channel == Adapter->AdhocChannel) {
+        /* AdhocChannel is set to the current Channel already */
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    PRINTM(INFO, "Updating Channel from %d to %d\n",
+           Adapter->CurBssParams.BSSDescriptor.Channel,
+           Adapter->AdhocChannel);
+
+    wlan_set_current_chan(priv, Adapter->AdhocChannel);
+
+    wlan_update_current_chan(priv);
+
+    if (Adapter->CurBssParams.BSSDescriptor.Channel != Adapter->AdhocChannel) {
+        PRINTM(INFO, "Failed to updated Channel to %d, channel = %d\n",
+               Adapter->AdhocChannel,
+               Adapter->CurBssParams.BSSDescriptor.Channel);
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        int i;
+        WLAN_802_11_SSID curAdhocSsid;
+
+        PRINTM(INFO, "Channel Changed while in an IBSS\n");
+
+        /* Copy the current ssid */
+        memcpy(&curAdhocSsid,
+               &Adapter->CurBssParams.BSSDescriptor.Ssid,
+               sizeof(WLAN_802_11_SSID));
+
+        /* Exit Adhoc mode */
+        PRINTM(INFO, "In wlan_change_adhoc_chan(): Sending Adhoc Stop\n");
+        ret = wlan_disconnect(priv);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+
+        /* Scan for the network */
+        wlan_cmd_specific_scan_ssid(priv, &curAdhocSsid);
+
+        // find out the BSSID that matches the current SSID 
+        i = wlan_find_ssid_in_list(Adapter, &curAdhocSsid, NULL,
+                                   Wlan802_11IBSS);
+
+        if (i >= 0) {
+            PRINTM(INFO, "SSID found at %d in List," "so join\n", i);
+            wlan_join_adhoc(priv, &Adapter->ScanTable[i]);
+        } else {
+            // else send START command
+            PRINTM(INFO, "SSID not found in list, "
+                   "so creating adhoc with ssid = %s\n", curAdhocSsid.Ssid);
+            wlan_start_adhoc(priv, &curAdhocSsid);
+        }                       // end of else (START command)
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set/Get WPA IE   
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param ie_data_ptr  A pointer to IE
+ *  @param ie_len       Length of the IE
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_wpa_ie_helper(wlan_private * priv, u8 * ie_data_ptr, u16 ie_len)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (ie_len) {
+        if (ie_len > sizeof(Adapter->Wpa_ie)) {
+            PRINTM(INFO, "failed to copy WPA IE, too big \n");
+            LEAVE();
+            return -EFAULT;
+        }
+        if (copy_from_user(Adapter->Wpa_ie, ie_data_ptr, ie_len)) {
+            PRINTM(INFO, "failed to copy WPA IE \n");
+            LEAVE();
+            return -EFAULT;
+        }
+        Adapter->Wpa_ie_len = ie_len;
+        PRINTM(INFO, "Set Wpa_ie_len=%d IE=%#x\n",
+               Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]);
+        HEXDUMP("Wpa_ie", Adapter->Wpa_ie, Adapter->Wpa_ie_len);
+
+        if (Adapter->Wpa_ie[0] == WPA_IE) {
+            Adapter->SecInfo.WPAEnabled = TRUE;
+        } else if (Adapter->Wpa_ie[0] == RSN_IE) {
+            Adapter->SecInfo.WPA2Enabled = TRUE;
+        } else {
+            Adapter->SecInfo.WPAEnabled = FALSE;
+            Adapter->SecInfo.WPA2Enabled = FALSE;
+        }
+    } else {
+        memset(Adapter->Wpa_ie, 0, sizeof(Adapter->Wpa_ie));
+        Adapter->Wpa_ie_len = ie_len;
+        PRINTM(INFO, "Reset Wpa_ie_len=%d IE=%#x\n",
+               Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]);
+        Adapter->SecInfo.WPAEnabled = FALSE;
+        Adapter->SecInfo.WPA2Enabled = FALSE;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set/Get WPA IE
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_wpa_ie_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    struct iwreq *wrq = (struct iwreq *) req;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    ret = wlan_set_wpa_ie_helper(priv,
+                                 wrq->u.data.pointer, wrq->u.data.length);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set WPA key
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode_wpa(struct net_device *dev,
+                    struct iw_request_info *info,
+                    struct iw_point *dwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    WLAN_802_11_KEY *pKey;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    pKey = (WLAN_802_11_KEY *) extra;
+
+    HEXDUMP("Key buffer: ", extra, dwrq->length);
+
+    // current driver only supports key length of up to 32 bytes
+    if (pKey->KeyLength > MRVL_MAX_WPA_KEY_LENGTH) {
+        PRINTM(INFO, " Error in key length \n");
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11IBSS) {
+        /* IBSS/WPA-None uses only one key (Group) for both receiving and
+           sending unicast and multicast packets. */
+        /*Send the key as PTK to firmware */
+        pKey->KeyIndex = 0x40000000;
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_KEY_MATERIAL,
+                               HostCmd_ACT_GEN_SET,
+                               HostCmd_OPTION_WAITFORRSP,
+                               KEY_INFO_ENABLED, pKey);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+        /*Send the key as GTK to firmware */
+        pKey->KeyIndex = ~0x40000000;
+    }
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_KEY_MATERIAL,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, KEY_INFO_ENABLED, pKey);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/*
+ *  iwconfig ethX key on:	WEPEnabled;
+ *  iwconfig ethX key off:	WEPDisabled;
+ *  iwconfig ethX key [x]:	CurrentWepKeyIndex = x; WEPEnabled;
+ *  iwconfig ethX key [x] kstr:	WepKey[x] = kstr;
+ *  iwconfig ethX key kstr:	WepKey[CurrentWepKeyIndex] = kstr;
+ *
+ *  all:			Send command SET_WEP;
+ 				SetMacPacketFilter;
+ */
+
+/** 
+ *  @brief Set WEP key
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param dwrq 		A pointer to iw_point structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode_nonwpa(struct net_device *dev,
+                       struct iw_request_info *info,
+                       struct iw_point *dwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    MRVL_WEP_KEY *pWep;
+    int index, PrevAuthMode;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    if (Adapter->CurrentWepKeyIndex >= MRVL_NUM_WEP_KEY)
+        Adapter->CurrentWepKeyIndex = 0;
+    pWep = &Adapter->WepKey[Adapter->CurrentWepKeyIndex];
+    PrevAuthMode = Adapter->SecInfo.AuthenticationMode;
+
+    index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+    if (index >= 4) {
+        PRINTM(INFO, "Key index #%d out of range.\n", index + 1);
+        LEAVE();
+        return -EINVAL;
+    }
+
+    PRINTM(INFO, "Flags=0x%x, Length=%d Index=%d CurrentWepKeyIndex=%d\n",
+           dwrq->flags, dwrq->length, index, Adapter->CurrentWepKeyIndex);
+
+    if (dwrq->length > 0) {
+        /* iwconfig ethX key [n] xxxxxxxxxxx 
+         * Key has been provided by the user 
+         */
+
+        /*
+         * Check the size of the key 
+         */
+
+        if (dwrq->length > MAX_WEP_KEY_SIZE) {
+            LEAVE();
+            return -EINVAL;
+        }
+
+        /*
+         * Check the index (none -> use current) 
+         */
+
+        if (index < 0 || index > 3)     //invalid index or no index
+            index = Adapter->CurrentWepKeyIndex;
+        else                    //index is given & valid
+            pWep = &Adapter->WepKey[index];
+
+        /*
+         * Check if the key is not marked as invalid 
+         */
+        if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
+            /* Cleanup */
+            memset(pWep, 0, sizeof(MRVL_WEP_KEY));
+
+            /* Copy the key in the driver */
+            memcpy(pWep->KeyMaterial, extra, dwrq->length);
+
+            /* Set the length */
+            if (dwrq->length > MIN_WEP_KEY_SIZE) {
+                pWep->KeyLength = MAX_WEP_KEY_SIZE;
+            } else {
+                if (dwrq->length > 0) {
+                    pWep->KeyLength = MIN_WEP_KEY_SIZE;
+                } else {
+                    /* Disable the key */
+                    pWep->KeyLength = 0;
+                }
+            }
+            pWep->KeyIndex = index;
+
+            if (Adapter->SecInfo.WEPStatus != Wlan802_11WEPEnabled) {
+                /*
+                 * The status is set as Key Absent 
+                 * so as to make sure we display the 
+                 * keys when iwlist ethX key is used
+                 */
+                Adapter->SecInfo.WEPStatus = Wlan802_11WEPKeyAbsent;
+            }
+
+            PRINTM(INFO, "KeyIndex=%u KeyLength=%u\n",
+                   pWep->KeyIndex, pWep->KeyLength);
+            HEXDUMP("WepKey", (u8 *) pWep->KeyMaterial, pWep->KeyLength);
+        }
+    } else {
+        /*
+         * No key provided so it is either enable key, 
+         * on or off */
+        if (dwrq->flags & IW_ENCODE_DISABLED) {
+            PRINTM(INFO, "*** iwconfig ethX key off ***\n");
+
+            Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled;
+            if (Adapter->SecInfo.AuthenticationMode ==
+                Wlan802_11AuthModeShared)
+                Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        } else {
+            /* iwconfig ethX key [n]
+             * iwconfig ethX key on 
+             * Do we want to just set the transmit key index ? 
+             */
+
+            if (index < 0 || index > 3) {
+                PRINTM(INFO, "*** iwconfig ethX key on ***\n");
+                index = Adapter->CurrentWepKeyIndex;
+            } else {
+                PRINTM(INFO, "*** iwconfig ethX key [x=%d] ***\n", index);
+                Adapter->CurrentWepKeyIndex = index;
+            }
+
+            /* Copy the required key as the current key */
+            pWep = &Adapter->WepKey[index];
+
+            if (!pWep->KeyLength) {
+                PRINTM(INFO, "Key not set,so cannot enable it\n");
+                LEAVE();
+                return -EPERM;
+            }
+
+            Adapter->SecInfo.WEPStatus = Wlan802_11WEPEnabled;
+
+            HEXDUMP("KeyMaterial", (u8 *) pWep->KeyMaterial, pWep->KeyLength);
+        }
+    }
+
+    if (pWep->KeyLength) {
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_SET_WEP,
+                               HostCmd_ACT_ADD, HostCmd_OPTION_WAITFORRSP,
+                               0, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
+        Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE;
+    } else {
+        Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_MAC_CONTROL,
+                           0, HostCmd_OPTION_WAITFORRSP,
+                           0, &Adapter->CurrentPacketFilter);
+
+    if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+        /* iwconfig ethX restricted key [1] */
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
+        PRINTM(INFO, "Auth mode restricted!\n");
+    } else if (dwrq->flags & IW_ENCODE_OPEN) {
+        /* iwconfig ethX key [2] open */
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        PRINTM(INFO, "Auth mode open!\n");
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set RX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param Mode			RF antenna mode
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_rx_antenna(wlan_private * priv, int Mode)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Mode != RF_ANTENNA_1 && Mode != RF_ANTENNA_2
+        && Mode != RF_ANTENNA_AUTO) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    Adapter->RxAntennaMode = Mode;
+
+    PRINTM(INFO, "SET RX Antenna Mode to 0x%04x\n", Adapter->RxAntennaMode);
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                           HostCmd_ACT_SET_RX, HostCmd_OPTION_WAITFORRSP,
+                           0, &Adapter->RxAntennaMode);
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief Set TX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param Mode			RF antenna mode
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_tx_antenna(wlan_private * priv, int Mode)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if ((Mode != RF_ANTENNA_1) && (Mode != RF_ANTENNA_2)
+        && (Mode != RF_ANTENNA_AUTO)) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    Adapter->TxAntennaMode = Mode;
+
+    PRINTM(INFO, "SET TX Antenna Mode to 0x%04x\n", Adapter->TxAntennaMode);
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                           HostCmd_ACT_SET_TX, HostCmd_OPTION_WAITFORRSP,
+                           0, &Adapter->TxAntennaMode);
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief Get RX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param buf			A pointer to recieve antenna mode
+ *  @return 	   		length of buf 
+ */
+static int
+wlan_get_rx_antenna(wlan_private * priv, char *buf)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    // clear it, so we will know if the value 
+    // returned below is correct or not.
+    Adapter->RxAntennaMode = 0;
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                           HostCmd_ACT_GET_RX, HostCmd_OPTION_WAITFORRSP,
+                           0, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    PRINTM(INFO, "Get Rx Antenna Mode:0x%04x\n", Adapter->RxAntennaMode);
+
+    LEAVE();
+
+    return sprintf(buf, "0x%04x", Adapter->RxAntennaMode) + 1;
+}
+
+/** 
+ *  @brief Get TX Antenna
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param buf			A pointer to recieve antenna mode
+ *  @return 	   		length of buf 
+ */
+static int
+wlan_get_tx_antenna(wlan_private * priv, char *buf)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    // clear it, so we will know if the value 
+    // returned below is correct or not.
+    Adapter->TxAntennaMode = 0;
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RF_ANTENNA,
+                           HostCmd_ACT_GET_TX, HostCmd_OPTION_WAITFORRSP,
+                           0, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    PRINTM(INFO, "Get Tx Antenna Mode:0x%04x\n", Adapter->TxAntennaMode);
+
+    LEAVE();
+
+    return sprintf(buf, "0x%04x", Adapter->TxAntennaMode) + 1;
+}
+
+/** 
+ *  @brief Set Radio On/OFF
+ *   
+ *  @param priv  		A pointer to wlan_private structure
+ *  @param option 		Radio Option
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+wlan_radio_ioctl(wlan_private * priv, u8 option)
+{
+    int ret = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->RadioOn != option) {
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            PRINTM(MSG, "Cannot turn radio off in connected state.\n");
+            LEAVE();
+            return -EINVAL;
+        }
+
+        PRINTM(INFO, "Switching %s the Radio\n", option ? "On" : "Off");
+        Adapter->RadioOn = option;
+
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RADIO_CONTROL,
+                               HostCmd_ACT_GEN_SET,
+                               HostCmd_OPTION_WAITFORRSP, 0, NULL);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+#ifdef REASSOCIATION
+/** 
+ *  @brief Set Auto Reassociation On
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+reassociation_on(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    Adapter->Reassoc_on = TRUE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Auto Reassociation Off
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+reassociation_off(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->ReassocTimerIsSet == TRUE) {
+        wlan_cancel_timer(&Adapter->MrvDrvTimer);
+        Adapter->ReassocTimerIsSet = FALSE;
+    }
+
+    Adapter->Reassoc_on = FALSE;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+#endif /* REASSOCIATION */
+
+/** 
+ *  @brief Set Region
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param region_code		region code
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail 
+ */
+static int
+wlan_set_region(wlan_private * priv, u16 region_code)
+{
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+        // use the region code to search for the index
+        if (region_code == RegionCodeToIndex[i]) {
+            priv->adapter->RegionCode = region_code;
+            break;
+        }
+    }
+
+    // if it's unidentified region code
+    if (i >= MRVDRV_MAX_REGION_CODE) {
+        PRINTM(INFO, "Region Code not identified\n");
+        LEAVE();
+        return WLAN_STATUS_FAILURE;
+    }
+
+    if (wlan_set_regiontable(priv, priv->adapter->RegionCode,
+                             priv->adapter->config_bands)) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Copy Rates
+ *   
+ *  @param dest                 A pointer to Dest Buf
+ *  @param pos		        The position for copy
+ *  @param src		        A pointer to Src Buf
+ *  @param len                  The len of Src Buf
+ *  @return 	   	        Number of Rates copyed 
+ */
+static inline int
+wlan_copy_rates(u8 * dest, int pos, u8 * src, int len)
+{
+    int i;
+
+    ENTER();
+
+    for (i = 0; i < len && src[i]; i++, pos++) {
+        if (pos >= sizeof(WLAN_802_11_RATES))
+            break;
+        dest[pos] = src[i];
+    }
+
+    LEAVE();
+
+    return pos;
+}
+
+/** 
+ *  @brief Get active data rates
+ *   
+ *  @param Adapter          A pointer to wlan_adapter structure
+ *  @param rates            The buf to return the active rates
+ *  @return                 The number of Rates
+ */
+static int
+get_active_data_rates(wlan_adapter * Adapter, WLAN_802_11_RATES rates)
+{
+    int k = 0;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus != WlanMediaStateConnected) {
+        if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+            //Infra. mode
+            if (Adapter->config_bands & BAND_G) {
+                PRINTM(INFO, "Infra mBAND_G=%#x\n", BAND_G);
+                k = wlan_copy_rates(rates, k, SupportedRates_G,
+                                    sizeof(SupportedRates_G));
+            } else {
+                if (Adapter->config_bands & BAND_B) {
+                    PRINTM(INFO, "Infra mBAND_B=%#x\n", BAND_B);
+                    k = wlan_copy_rates(rates, k,
+                                        SupportedRates_B,
+                                        sizeof(SupportedRates_B));
+                }
+                if (Adapter->config_bands & BAND_A) {
+                    PRINTM(INFO, "Infra mBAND_A=%#x\n", BAND_A);
+                    k = wlan_copy_rates(rates, k,
+                                        SupportedRates_A,
+                                        sizeof(SupportedRates_A));
+                }
+            }
+        } else {
+            //ad-hoc mode
+            if (Adapter->config_bands & BAND_G) {
+                PRINTM(INFO, "Adhoc mBAND_G=%#x\n", BAND_G);
+                k = wlan_copy_rates(rates, k, AdhocRates_G,
+                                    sizeof(AdhocRates_G));
+            } else if (Adapter->config_bands & BAND_B) {
+                PRINTM(INFO, "Adhoc mBAND_B=%#x\n", BAND_B);
+                k = wlan_copy_rates(rates, k, AdhocRates_B,
+                                    sizeof(AdhocRates_B));
+            }
+            if (Adapter->config_bands & BAND_A) {
+                PRINTM(INFO, "Adhoc mBAND_A=%#x\n", BAND_A);
+                k = wlan_copy_rates(rates, k, AdhocRates_A,
+                                    sizeof(AdhocRates_A));
+            }
+        }
+    } else {
+        k = wlan_copy_rates(rates, 0, Adapter->CurBssParams.DataRates,
+                            Adapter->CurBssParams.NumOfRates);
+    }
+
+    LEAVE();
+
+    return k;
+}
+
+/** 
+ *  @brief Get/Set Per packet TX Control flags
+ *  
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to user data
+ *  @return         WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[3];
+    int ret;
+
+    ENTER();
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    switch (wrq->u.data.length) {
+    case 0:
+        /*
+         *  Get the Global setting for TxCtrl 
+         */
+        if (copy_to_user(wrq->u.data.pointer,
+                         &Adapter->PktTxCtrl, sizeof(u32))) {
+            PRINTM(INFO, "copy_to_user failed!\n");
+            ret = -EFAULT;
+        } else {
+            wrq->u.data.length = 1;
+        }
+        break;
+
+    case 1:
+        /*
+         *  Set the Global setting for TxCtrl
+         */
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+        } else {
+            Adapter->PktTxCtrl = data[0];
+            PRINTM(INFO, "PktTxCtrl set: 0x%08x\n", Adapter->PktTxCtrl);
+        }
+        break;
+
+    case 2:
+        /*
+         *  Get the per User Priority setting for TxCtrl for the given UP
+         */
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * 2)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+
+        } else if (data[1] >= NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
+            /* Range check the UP input from user space */
+            PRINTM(INFO, "User priority out of range\n");
+            ret = -EINVAL;
+
+        } else if (Adapter->wmm.userPriPktTxCtrl[data[1]]) {
+            data[2] = Adapter->wmm.userPriPktTxCtrl[data[1]];
+
+            /* User priority setting is valid, return it */
+            if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
+                PRINTM(INFO, "copy_to_user failed!\n");
+                ret = -EFAULT;
+            } else {
+                wrq->u.data.length = 3;
+            }
+
+        } else {
+            /* Return the global setting since the UP set is zero */
+            data[2] = Adapter->PktTxCtrl;
+
+            if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
+                PRINTM(INFO, "copy_to_user failed!\n");
+                ret = -EFAULT;
+            } else {
+                wrq->u.data.length = 3;
+            }
+        }
+        break;
+
+    case 3:
+        /*
+         *  Set the per User Priority setting for TxCtrl for the given UP
+         */
+
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * 3)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+        } else if (data[1] >= NELEMENTS(Adapter->wmm.userPriPktTxCtrl)) {
+            PRINTM(INFO, "User priority out of range\n");
+            ret = -EINVAL;
+        } else {
+            Adapter->wmm.userPriPktTxCtrl[data[1]] = data[2];
+
+            if (Adapter->wmm.userPriPktTxCtrl[data[1]] == 0) {
+                /* Return the global setting since the UP set is zero */
+                data[2] = Adapter->PktTxCtrl;
+            }
+
+            if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 3)) {
+                PRINTM(INFO, "copy_to_user failed!\n");
+                ret = -EFAULT;
+            } else {
+                wrq->u.data.length = 3;
+            }
+        }
+        break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Enable/Disable atim uapsd null package generation
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_null_pkg_gen(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    wlan_adapter *Adapter = priv->adapter;
+    int *val;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    PRINTM(INFO, "Enable UAPSD NULL PKG: %s\n",
+           (data == CMD_ENABLED) ? "Enable" : "Disable");
+    switch (data) {
+    case CMD_ENABLED:
+        Adapter->gen_null_pkg = TRUE;
+        break;
+    case CMD_DISABLED:
+        Adapter->gen_null_pkg = FALSE;
+        break;
+    default:
+        break;
+    }
+
+    data = (Adapter->gen_null_pkg == TRUE) ? CMD_ENABLED : CMD_DISABLED;
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set NULL Package generation interval
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+    ENTER();
+
+    if ((int) wrq->u.data.length == 0) {
+        data = Adapter->NullPktInterval;
+
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(MSG, "copy_to_user failed!\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    } else {
+        if ((int) wrq->u.data.length > 1) {
+            PRINTM(MSG, "ioctl too many args!\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        Adapter->NullPktInterval = data;
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Adhoc awake period 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_adhoc_awake_period(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+    ENTER();
+
+    if ((int) wrq->u.data.length == 0) {
+        data = Adapter->AdhocAwakePeriod;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(MSG, "copy_to_user failed!\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    } else {
+        if ((int) wrq->u.data.length > 1) {
+            PRINTM(MSG, "ioctl too many args!\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+#define AWAKE_PERIOD_NOCHANGE 0
+#define AWAKE_PERIOD_MIN 1
+#define AWAKE_PERIOD_MAX 31
+#define DISABLE_AWAKE_PERIOD 0xff
+        if ((((data & 0xff) >= AWAKE_PERIOD_MIN) &&
+             ((data & 0xff) <= AWAKE_PERIOD_MAX)) ||
+            ((data & 0xff) == DISABLE_AWAKE_PERIOD))
+            Adapter->AdhocAwakePeriod = (u16) data;
+        else {
+            if (data != AWAKE_PERIOD_NOCHANGE) {
+                PRINTM(INFO,
+                       "Invalid parameter, AdhocAwakePeriod not changed.\n");
+                LEAVE();
+                return -EINVAL;
+            }
+            data = Adapter->AdhocAwakePeriod;
+            if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                PRINTM(MSG, "copy_to_user failed!\n");
+                LEAVE();
+                return -EFAULT;
+            }
+        }
+    }
+    wrq->u.data.length = 1;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set bcn missing timeout 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_bcn_miss_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+    ENTER();
+
+    if ((int) wrq->u.data.length == 0) {
+        data = Adapter->BCNMissTimeOut;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(MSG, "copy_to_user failed!\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    } else {
+        if ((int) wrq->u.data.length > 1) {
+            PRINTM(MSG, "ioctl too many args!\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        if (((data >= 0) && (data <= 50)) || (data == 0xffff))
+            Adapter->BCNMissTimeOut = (u16) data;
+        else {
+            PRINTM(INFO,
+                   "Invalid parameter, BCN Missing timeout not changed.\n");
+            LEAVE();
+            return -EINVAL;
+
+        }
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set adhoc g proctection
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_adhoc_g_protection(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    int *val;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+#define ADHOC_G_PROTECTION_ON		1
+#define ADHOC_G_PROTECTION_OFF		0
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+    switch (data) {
+    case CMD_DISABLED:
+        Adapter->CurrentPacketFilter &=
+            ~HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+        break;
+    case CMD_ENABLED:
+        Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+        break;
+
+    case CMD_GET:
+        if (Adapter->
+            CurrentPacketFilter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)
+            data = ADHOC_G_PROTECTION_ON;
+        else
+            data = ADHOC_G_PROTECTION_OFF;
+        break;
+
+    default:
+        LEAVE();
+        return -EINVAL;
+    }
+
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+#ifdef DEBUG_LEVEL1
+/** 
+ *  @brief Get/Set the bit mask of driver debug message control
+ *  @param priv			A pointer to wlan_private structure
+ *  @param wrq			A pointer to wrq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_drv_dbg(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[4];
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0) {
+        data[0] = drvdbg;
+        data[1] = ifdbg;
+        /* Return the current driver debug bit masks */
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+            goto drvdbgexit;
+        }
+        wrq->u.data.length = 2;
+    } else if (wrq->u.data.length < 3) {
+        /* Get the driver debug bit masks */
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+            goto drvdbgexit;
+        }
+        drvdbg = data[0];
+        if (wrq->u.data.length == 2)
+            ifdbg = data[1];
+    } else {
+        PRINTM(INFO, "Invalid parameter number\n");
+        goto drvdbgexit;
+    }
+
+    printk(KERN_ALERT "drvdbg = 0x%x\n", drvdbg);
+#ifdef DEBUG_LEVEL2
+    printk(KERN_ALERT "INFO  (%08x) %s\n", DBG_INFO,
+           (drvdbg & DBG_INFO) ? "X" : "");
+    printk(KERN_ALERT "WARN  (%08x) %s\n", DBG_WARN,
+           (drvdbg & DBG_WARN) ? "X" : "");
+    printk(KERN_ALERT "ENTRY (%08x) %s\n", DBG_ENTRY,
+           (drvdbg & DBG_ENTRY) ? "X" : "");
+#endif
+    printk(KERN_ALERT "FW_D  (%08x) %s\n", DBG_FW_D,
+           (drvdbg & DBG_FW_D) ? "X" : "");
+    printk(KERN_ALERT "CMD_D (%08x) %s\n", DBG_CMD_D,
+           (drvdbg & DBG_CMD_D) ? "X" : "");
+    printk(KERN_ALERT "DAT_D (%08x) %s\n", DBG_DAT_D,
+           (drvdbg & DBG_DAT_D) ? "X" : "");
+    printk(KERN_ALERT "INTR  (%08x) %s\n", DBG_INTR,
+           (drvdbg & DBG_INTR) ? "X" : "");
+    printk(KERN_ALERT "EVENT (%08x) %s\n", DBG_EVENT,
+           (drvdbg & DBG_EVENT) ? "X" : "");
+    printk(KERN_ALERT "CMND  (%08x) %s\n", DBG_CMND,
+           (drvdbg & DBG_CMND) ? "X" : "");
+    printk(KERN_ALERT "DATA  (%08x) %s\n", DBG_DATA,
+           (drvdbg & DBG_DATA) ? "X" : "");
+    printk(KERN_ALERT "ERROR (%08x) %s\n", DBG_ERROR,
+           (drvdbg & DBG_ERROR) ? "X" : "");
+    printk(KERN_ALERT "FATAL (%08x) %s\n", DBG_FATAL,
+           (drvdbg & DBG_FATAL) ? "X" : "");
+    printk(KERN_ALERT "MSG   (%08x) %s\n", DBG_MSG,
+           (drvdbg & DBG_MSG) ? "X" : "");
+    printk(KERN_ALERT "ifdbg = 0x%x\n", ifdbg);
+    printk(KERN_ALERT "IF_D  (%08x) %s\n", DBG_IF_D,
+           (ifdbg & DBG_IF_D) ? "X" : "");
+
+  drvdbgexit:
+    LEAVE();
+    return ret;
+}
+#endif
+
+/** 
+ *  @brief Get/Set module type config
+ *  @param priv			A pointer to wlan_private structure
+ *  @param wrq			A pointer to wrq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_module_type_config(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_MODULE_TYPE_CONFIG moduletypecfg;
+    int data = 0;
+    u16 action;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0) {
+        action = HostCmd_ACT_GEN_GET;
+    } else if (wrq->u.data.length > 1) {
+        PRINTM(MSG, "ioctl too many args!\n");
+        ret = -EFAULT;
+        goto mtexit;
+    } else {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+            goto mtexit;
+        }
+        action = HostCmd_ACT_GEN_SET;
+    }
+    moduletypecfg.Action = action;
+    moduletypecfg.Module = (u16) data;
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_MODULE_TYPE_CONFIG,
+                           action, HostCmd_OPTION_WAITFORRSP,
+                           0, (void *) &moduletypecfg);
+
+    if (!ret && action == HostCmd_ACT_GEN_GET) {
+        data = (int) moduletypecfg.Module;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+            goto mtexit;
+        }
+        wrq->u.data.length = 1;
+    }
+
+  mtexit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Commit handler: called after a bunch of SET operations
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_config_commit(struct net_device *dev,
+                   struct iw_request_info *info, char *cwrq, char *extra)
+{
+    ENTER();
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get protocol name 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+              char *cwrq, char *extra)
+{
+    const char *cp;
+    char comm[6] = { "COMM-" };
+    char mrvl[6] = { "MRVL-" };
+    int cnt;
+
+    ENTER();
+
+    strcpy(cwrq, mrvl);
+
+    cp = strstr(driver_version, comm);
+    if (cp == driver_version)   //skip leading "COMM-"
+        cp = driver_version + strlen(comm);
+    else
+        cp = driver_version;
+
+    cnt = strlen(mrvl);
+    cwrq += cnt;
+    while (cnt < 16 && (*cp != '-')) {
+        *cwrq++ = toupper(*cp++);
+        cnt++;
+    }
+    *cwrq = '\0';
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get frequency
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param fwrq 		A pointer to iw_freq structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+              struct iw_freq *fwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    CHANNEL_FREQ_POWER *cfp;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    cfp = find_cfp_by_band_and_channel(Adapter, Adapter->CurBssParams.band,
+                                       (u16) Adapter->CurBssParams.
+                                       BSSDescriptor.Channel);
+
+    if (!cfp) {
+        if (Adapter->CurBssParams.BSSDescriptor.Channel) {
+            PRINTM(INFO, "Invalid channel=%d\n",
+                   Adapter->CurBssParams.BSSDescriptor.Channel);
+        }
+        LEAVE();
+        return -EINVAL;
+    }
+
+    fwrq->m = (long) cfp->Freq * 100000;
+    fwrq->e = 1;
+
+    PRINTM(INFO, "freq=%u\n", fwrq->m);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get current BSSID
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param awrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+             struct sockaddr *awrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        memcpy(awrq->sa_data,
+               Adapter->CurBssParams.BSSDescriptor.MacAddress, ETH_ALEN);
+    } else {
+        memset(awrq->sa_data, 0, ETH_ALEN);
+    }
+    awrq->sa_family = ARPHRD_ETHER;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Adapter Node Name
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /*
+     * Check the size of the string 
+     */
+
+    if (dwrq->length > 16) {
+        LEAVE();
+        return -E2BIG;
+    }
+
+    memset(Adapter->nodeName, 0, sizeof(Adapter->nodeName));
+    memcpy(Adapter->nodeName, extra, dwrq->length);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Adapter Node Name
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    /*
+     * Get the Nick Name saved 
+     */
+
+    strncpy(extra, Adapter->nodeName, 16);
+
+    extra[16] = '\0';
+
+    /*
+     * If none, we may want to get the one that was set 
+     */
+
+    /*
+     * Push it out ! 
+     */
+    dwrq->length = strlen(extra) + 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set RTS threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+             struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int rthr = vwrq->value;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    if (vwrq->disabled) {
+        Adapter->RTSThsd = rthr = MRVDRV_RTS_MAX_VALUE;
+    } else {
+        if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) {
+            LEAVE();
+            return -EINVAL;
+        }
+        Adapter->RTSThsd = rthr;
+    }
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                           HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP,
+                           RtsThresh_i, &rthr);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get RTS threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+             struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    Adapter->RTSThsd = 0;
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                           HostCmd_ACT_GEN_GET, HostCmd_OPTION_WAITFORRSP,
+                           RtsThresh_i, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    vwrq->value = Adapter->RTSThsd;
+    vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+                      || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+    vwrq->fixed = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Fragment threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    int fthr = vwrq->value;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    if (vwrq->disabled) {
+        Adapter->FragThsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+    } else {
+        if (fthr < MRVDRV_FRAG_MIN_VALUE || fthr > MRVDRV_FRAG_MAX_VALUE) {
+            LEAVE();
+            return -EINVAL;
+        }
+        Adapter->FragThsd = fthr;
+    }
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                           HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP,
+                           FragThresh_i, &fthr);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get Fragment threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    Adapter->FragThsd = 0;
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_GET,
+                           HostCmd_OPTION_WAITFORRSP, FragThresh_i, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    vwrq->value = Adapter->FragThsd;
+    vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+                      || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+    vwrq->fixed = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get Wlan Mode
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_mode(struct net_device *dev,
+              struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    switch (adapter->InfrastructureMode) {
+    case Wlan802_11IBSS:
+        *uwrq = IW_MODE_ADHOC;
+        break;
+
+    case Wlan802_11Infrastructure:
+        *uwrq = IW_MODE_INFRA;
+        break;
+
+    default:
+    case Wlan802_11AutoUnknown:
+        *uwrq = IW_MODE_AUTO;
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Encryption key
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_encode(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, u8 * extra)
+{
+
+    wlan_private *priv = dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+    int index = (dwrq->flags & IW_ENCODE_INDEX);
+
+    ENTER();
+
+    PRINTM(INFO, "flags=0x%x index=%d length=%d CurrentWepKeyIndex=%d\n",
+           dwrq->flags, index, dwrq->length, adapter->CurrentWepKeyIndex);
+    if (index < 0 || index > 4) {
+        PRINTM(INFO, "Key index #%d out of range.\n", index);
+        LEAVE();
+        return -EINVAL;
+    }
+    if (adapter->CurrentWepKeyIndex >= MRVL_NUM_WEP_KEY)
+        adapter->CurrentWepKeyIndex = 0;
+    dwrq->flags = 0;
+
+    /*
+     * Check encryption mode 
+     */
+
+    switch (adapter->SecInfo.AuthenticationMode) {
+    case Wlan802_11AuthModeOpen:
+        dwrq->flags = IW_ENCODE_OPEN;
+        break;
+
+    case Wlan802_11AuthModeShared:
+    case Wlan802_11AuthModeNetworkEAP:
+        dwrq->flags = IW_ENCODE_RESTRICTED;
+        break;
+    default:
+        dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+        break;
+    }
+
+    if ((adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)
+        || (adapter->SecInfo.WEPStatus == Wlan802_11WEPKeyAbsent)
+        || adapter->SecInfo.WPAEnabled || adapter->SecInfo.WPA2Enabled) {
+        dwrq->flags &= ~IW_ENCODE_DISABLED;
+    } else {
+        dwrq->flags |= IW_ENCODE_DISABLED;
+    }
+
+    memset(extra, 0, 16);
+
+    if (!index) {
+        /* Handle current key request   */
+        if ((adapter->WepKey[adapter->CurrentWepKeyIndex].KeyLength) &&
+            (adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)) {
+            index = adapter->WepKey[adapter->CurrentWepKeyIndex].KeyIndex;
+            memcpy(extra, adapter->WepKey[index].KeyMaterial,
+                   adapter->WepKey[index].KeyLength);
+            dwrq->length = adapter->WepKey[index].KeyLength;
+            /* return current key */
+            dwrq->flags |= (index + 1);
+            /* return WEP enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else if ((adapter->SecInfo.WPAEnabled)
+                   || (adapter->SecInfo.WPA2Enabled)
+            ) {
+            /* return WPA enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else {
+            dwrq->flags |= IW_ENCODE_DISABLED;
+        }
+    } else {
+        /* Handle specific key requests */
+        index--;
+        if (adapter->WepKey[index].KeyLength) {
+            memcpy(extra, adapter->WepKey[index].KeyMaterial,
+                   adapter->WepKey[index].KeyLength);
+            dwrq->length = adapter->WepKey[index].KeyLength;
+            /* return current key */
+            dwrq->flags |= (index + 1);
+            /* return WEP enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else if ((adapter->SecInfo.WPAEnabled)
+                   || (adapter->SecInfo.WPA2Enabled)
+            ) {
+            /* return WPA enabled */
+            dwrq->flags &= ~IW_ENCODE_DISABLED;
+        } else {
+            dwrq->flags |= IW_ENCODE_DISABLED;
+        }
+    }
+
+    dwrq->flags |= IW_ENCODE_NOKEY;
+
+    PRINTM(INFO, "Key:%02x:%02x:%02x:%02x:%02x:%02x KeyLen=%d\n",
+           extra[0], extra[1], extra[2],
+           extra[3], extra[4], extra[5], dwrq->length);
+
+    PRINTM(INFO, "Return flags=0x%x\n", dwrq->flags);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get TX Power
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_txpow(struct net_device *dev,
+               struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_RF_TX_POWER,
+                           HostCmd_ACT_GEN_GET,
+                           HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    PRINTM(INFO, "TXPOWER GET %d dbm.\n", Adapter->TxPowerLevel);
+    vwrq->value = Adapter->TxPowerLevel;
+    vwrq->fixed = 1;
+    if (Adapter->RadioOn) {
+        vwrq->disabled = 0;
+        vwrq->flags = IW_TXPOW_DBM;
+    } else {
+        vwrq->disabled = 1;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set TX Retry Count
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    if (vwrq->flags == IW_RETRY_LIMIT) {
+        /* The MAC has a 4-bit Total_Tx_Count register
+           Total_Tx_Count = 1 + Tx_Retry_Count */
+#define TX_RETRY_MIN 0
+#define TX_RETRY_MAX 14
+        if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) {
+            LEAVE();
+            return -EINVAL;
+        }
+        /* Set Tx retry count */
+        adapter->TxRetryCount = vwrq->value;
+
+        ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
+                               HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP,
+                               ShortRetryLim_i, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    } else {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get TX Retry Count
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    Adapter->TxRetryCount = 0;
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_GET,
+                           HostCmd_OPTION_WAITFORRSP, ShortRetryLim_i, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+    vwrq->disabled = 0;
+    if (!vwrq->flags) {
+        vwrq->flags = IW_RETRY_LIMIT;
+        /* Get Tx retry count */
+        vwrq->value = Adapter->TxRetryCount;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Sort Channels
+ *   
+ *  @param freq 		A pointer to iw_freq structure
+ *  @param num		        number of Channels
+ *  @return 	   		NA
+ */
+static inline void
+sort_channels(struct iw_freq *freq, int num)
+{
+    int i, j;
+    struct iw_freq temp;
+
+    ENTER();
+
+    for (i = 0; i < num; i++)
+        for (j = i + 1; j < num; j++)
+            if (freq[i].i > freq[j].i) {
+                temp.i = freq[i].i;
+                temp.m = freq[i].m;
+
+                freq[i].i = freq[j].i;
+                freq[i].m = freq[j].m;
+
+                freq[j].i = temp.i;
+                freq[j].m = temp.m;
+            }
+
+    LEAVE();
+}
+
+/* data rate listing
+	MULTI_BANDS:
+		abg		a	b	b/g
+   Infra 	G(12)		A(8)	B(4)	G(12)
+   Adhoc 	A+B(12)		A(8)	B(4)	B(4)
+
+	non-MULTI_BANDS:
+		   		 	b	b/g
+   Infra 	     		    	B(4)	G(12)
+   Adhoc 	      		    	B(4)	B(4)
+ */
+/** 
+ *  @brief Get Range Info
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *dwrq, char *extra)
+{
+    int i, j;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct iw_range *range = (struct iw_range *) extra;
+    CHANNEL_FREQ_POWER *cfp;
+    WLAN_802_11_RATES rates;
+
+    ENTER();
+
+    dwrq->length = sizeof(struct iw_range);
+    memset(range, 0, sizeof(struct iw_range));
+
+    range->min_nwid = 0;
+    range->max_nwid = 0;
+
+    memset(rates, 0, sizeof(rates));
+    range->num_bitrates = get_active_data_rates(Adapter, rates);
+    if (range->num_bitrates > sizeof(rates))
+        range->num_bitrates = sizeof(rates);
+
+    for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+         i++) {
+        range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+    }
+    range->num_bitrates = i;
+    PRINTM(INFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+           range->num_bitrates);
+
+    range->num_frequency = 0;
+    if (wlan_get_state_11d(priv) == ENABLE_11D &&
+        Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        u8 chan_no;
+        u8 band;
+
+        parsed_region_chan_11d_t *parsed_region_chan =
+            &Adapter->parsed_region_chan;
+
+        band = parsed_region_chan->band;
+        PRINTM(INFO, "band=%d NoOfChan=%d\n", band,
+               parsed_region_chan->NoOfChan);
+
+        for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+             && (i < parsed_region_chan->NoOfChan); i++) {
+            chan_no = parsed_region_chan->chanPwr[i].chan;
+            PRINTM(INFO, "chan_no=%d\n", chan_no);
+            range->freq[range->num_frequency].i = (long) chan_no;
+            range->freq[range->num_frequency].m =
+                (long) chan_2_freq(chan_no, band) * 100000;
+            range->freq[range->num_frequency].e = 1;
+            range->num_frequency++;
+        }
+    } else {
+        for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+             && (j < sizeof(Adapter->region_channel)
+                 / sizeof(Adapter->region_channel[0])); j++) {
+            cfp = Adapter->region_channel[j].CFP;
+            for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+                 && Adapter->region_channel[j].Valid
+                 && cfp && (i < Adapter->region_channel[j].NrCFP); i++) {
+                range->freq[range->num_frequency].i = (long) cfp->Channel;
+                range->freq[range->num_frequency].m =
+                    (long) cfp->Freq * 100000;
+                range->freq[range->num_frequency].e = 1;
+                cfp++;
+                range->num_frequency++;
+            }
+        }
+    }
+
+    PRINTM(INFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+           IW_MAX_FREQUENCIES, range->num_frequency);
+
+    range->num_channels = range->num_frequency;
+
+    sort_channels(&range->freq[0], range->num_frequency);
+
+    /*
+     * Set an indication of the max TCP throughput in bit/s that we can
+     * expect using this interface 
+     */
+    if (i > 2)
+        range->throughput = 5000 * 1000;
+    else
+        range->throughput = 1500 * 1000;
+
+    range->min_rts = MRVDRV_RTS_MIN_VALUE;
+    range->max_rts = MRVDRV_RTS_MAX_VALUE;
+    range->min_frag = MRVDRV_FRAG_MIN_VALUE;
+    range->max_frag = MRVDRV_FRAG_MAX_VALUE;
+
+    range->encoding_size[0] = 5;
+    range->encoding_size[1] = 13;
+    range->num_encoding_sizes = 2;
+    range->max_encoding_tokens = 4;
+
+#define IW_POWER_PERIOD_MIN 1000000     /* 1 sec */
+#define IW_POWER_PERIOD_MAX 120000000   /* 2 min */
+#define IW_POWER_TIMEOUT_MIN 1000       /* 1 ms  */
+#define IW_POWER_TIMEOUT_MAX 1000000    /* 1 sec */
+
+    /* Power Management duration & timeout */
+    range->min_pmp = IW_POWER_PERIOD_MIN;
+    range->max_pmp = IW_POWER_PERIOD_MAX;
+    range->min_pmt = IW_POWER_TIMEOUT_MIN;
+    range->max_pmt = IW_POWER_TIMEOUT_MAX;
+    range->pmp_flags = IW_POWER_PERIOD;
+    range->pmt_flags = IW_POWER_TIMEOUT;
+    range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+    /*
+     * Minimum version we recommend 
+     */
+    range->we_version_source = 15;
+
+    /*
+     * Version we are compiled with 
+     */
+    range->we_version_compiled = WIRELESS_EXT;
+
+    range->retry_capa = IW_RETRY_LIMIT;
+    range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+    range->min_retry = TX_RETRY_MIN;
+    range->max_retry = TX_RETRY_MAX;
+
+    /*
+     * Set the qual, level and noise range values 
+     */
+    /*
+     * need to put the right values here 
+     */
+#define IW_MAX_QUAL_PERCENT 100
+#define IW_AVG_QUAL_PERCENT 70
+    range->max_qual.qual = IW_MAX_QUAL_PERCENT;
+    range->max_qual.level = 0;
+    range->max_qual.noise = 0;
+
+    range->avg_qual.qual = IW_AVG_QUAL_PERCENT;
+    range->avg_qual.level = 0;
+    range->avg_qual.noise = 0;
+
+    range->sensitivity = 0;
+    /*
+     * Setup the supported power level ranges 
+     */
+    memset(range->txpower, 0, sizeof(range->txpower));
+    range->txpower[0] = Adapter->MinTxPowerLevel;
+    range->txpower[1] = Adapter->MaxTxPowerLevel;
+    range->num_txpower = 2;
+    range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
+
+	if (FW_IS_WPA_ENABLED(Adapter)) {
+		range->enc_capa = IW_ENC_CAPA_WPA
+			| IW_ENC_CAPA_WPA2
+			| IW_ENC_CAPA_CIPHER_TKIP
+			| IW_ENC_CAPA_CIPHER_CCMP;
+	}
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Set power management 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    /* PS is currently supported only in Infrastructure Mode 
+     * Remove this check if it is to be supported in IBSS mode also 
+     */
+
+    if (vwrq->disabled) {
+        Adapter->PSMode = Wlan802_11PowerModeCAM;
+        if (Adapter->PSState != PS_STATE_FULL_POWER) {
+            wlan_exit_ps(priv, HostCmd_OPTION_WAITFORRSP);
+        }
+
+        LEAVE();
+        return 0;
+    }
+
+    if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+        PRINTM(INFO, "Setting power timeout command is not supported\n");
+        LEAVE();
+        return -EINVAL;
+    } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+        PRINTM(INFO, "Setting power period command is not supported\n");
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (Adapter->PSMode != Wlan802_11PowerModeCAM) {
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    Adapter->PSMode = Wlan802_11PowerModeMAX_PSP;
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        wlan_enter_ps(priv, HostCmd_OPTION_WAITFORRSP);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Get power management 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int mode;
+
+    ENTER();
+
+    mode = Adapter->PSMode;
+
+    if ((vwrq->disabled = (mode == Wlan802_11PowerModeCAM))
+        || Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    vwrq->value = 0;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Set sensitivity threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_sens(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    ENTER();
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Get sensitivity threshold
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_FAILURE
+ */
+static int
+wlan_get_sens(struct net_device *dev,
+              struct iw_request_info *info, struct iw_param *vwrq,
+              char *extra)
+{
+    ENTER();
+    LEAVE();
+    return WLAN_STATUS_FAILURE;
+}
+
+/** 
+ *  @brief  Append/Reset IE buffer. 
+ *   
+ *  Pass an opaque block of data, expected to be IEEE IEs, to the driver 
+ *    for eventual passthrough to the firmware in an associate/join 
+ *    (and potentially start) command.  This function is the main body
+ *    for both wlan_set_gen_ie_ioctl and wlan_set_gen_ie
+ *
+ *  Data is appended to an existing buffer and then wrapped in a passthrough
+ *    TLV in the command API to the firmware.  The firmware treats the data
+ *    as a transparent passthrough to the transmitted management frame.
+ *
+ *  @param Adapter      A pointer to wlan_private structure
+ *  @param ie_data_ptr  A pointer to iwreq structure
+ *  @param ie_len       Length of the IE or IE block passed in ie_data_ptr
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie_helper(wlan_private * priv, u8 * ie_data_ptr, u16 ie_len)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    IEEEtypes_VendorHeader_t *pVendorIe;
+    const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+
+    ENTER();
+    /* If the passed length is zero, reset the buffer */
+    if (ie_len == 0) {
+        Adapter->genIeBufferLen = 0;
+
+    } else if (ie_data_ptr == NULL) {
+        /* NULL check */
+        ret = -EINVAL;
+    } else {
+
+        pVendorIe = (IEEEtypes_VendorHeader_t *) ie_data_ptr;
+
+        /* Test to see if it is a WPA IE, if not, then it is a gen IE */
+        if ((pVendorIe->ElementId == RSN_IE)
+            || ((pVendorIe->ElementId == WPA_IE)
+                && (memcmp(pVendorIe->Oui, wpa_oui, sizeof(wpa_oui)) == 0))) {
+
+            /* IE is a WPA/WPA2 IE so call set_wpa function */
+            ret = wlan_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+        } else {
+            /* 
+             * Verify that the passed length is not larger than the available 
+             *   space remaining in the buffer
+             */
+            if (ie_len < (sizeof(Adapter->genIeBuffer)
+                          - Adapter->genIeBufferLen)) {
+
+                /* Append the passed data to the end of the genIeBuffer */
+                if (copy_from_user((Adapter->genIeBuffer
+                                    + Adapter->genIeBufferLen),
+                                   ie_data_ptr, ie_len)) {
+                    PRINTM(INFO, "Copy from user failed\n");
+                    ret = -EFAULT;
+
+                } else {
+                    /* Increment the stored buffer length by the size passed */
+                    Adapter->genIeBufferLen += ie_len;
+                }
+
+            } else {
+                /* Passed data does not fit in the remaining buffer space */
+                ret = WLAN_STATUS_FAILURE;
+            }
+        }
+    }
+
+    /* Return WLAN_STATUS_SUCCESS, or < 0 for error case */
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief  Get IE buffer from driver 
+ *   
+ *  Used to pass an opaque block of data, expected to be IEEE IEs,
+ *    back to the application.  Currently the data block passed
+ *    back to the application is the saved association response retrieved 
+ *    from the firmware.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param ie_data_ptr  A pointer to the IE or IE block
+ *  @param ie_len_ptr   In/Out parameter pointer for the buffer length passed 
+ *                      in ie_data_ptr and the resulting data length copied
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_gen_ie_helper(wlan_private * priv,
+                       u8 * ie_data_ptr, u16 * ie_len_ptr)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    IEEEtypes_AssocRsp_t *pAssocRsp;
+    int copySize;
+
+    ENTER();
+
+    pAssocRsp = (IEEEtypes_AssocRsp_t *) Adapter->assocRspBuffer;
+
+    /*
+     * Set the amount to copy back to the application as the minimum of the 
+     *   available IE data or the buffer provided by the application
+     */
+    copySize = (Adapter->assocRspSize - sizeof(pAssocRsp->Capability) -
+                -sizeof(pAssocRsp->StatusCode) - sizeof(pAssocRsp->AId));
+    copySize = MIN(copySize, *ie_len_ptr);
+
+    /* Copy the IEEE TLVs in the assoc response back to the application */
+    if (copy_to_user(ie_data_ptr, (u8 *) pAssocRsp->IEBuffer, copySize)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    /* Returned copy length */
+    *ie_len_ptr = copySize;
+
+    /* No error on return */
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+#if (WIRELESS_EXT >= 18)
+/** 
+ *  @brief  Set IE 
+ *
+ *  Calls main function set_gen_ie_fuct that adds the inputted IE
+ *    to the genie buffer
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    ret = wlan_set_gen_ie_helper(dev->priv, dwrq->pointer, dwrq->length);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief  Get IE 
+ *
+ *  Calls main function get_gen_ie_fuct that retrieves expected IEEE IEs
+ *    and places then in the iw_point structure
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_gen_ie(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    ret = wlan_get_gen_ie_helper(dev->priv, dwrq->pointer, &dwrq->length);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setauthalg(wlan_private * priv, int alg)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, "auth alg is %#x\n", alg);
+
+    switch (alg) {
+    case IW_AUTH_ALG_SHARED_KEY:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
+        break;
+    case IW_AUTH_ALG_LEAP:
+        //clear WPA IE
+        wlan_set_wpa_ie_helper(priv, NULL, 0);
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeNetworkEAP;
+        break;
+    case IW_AUTH_ALG_OPEN_SYSTEM:
+    default:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief set authentication mode params
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_auth(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+    switch (vwrq->flags & IW_AUTH_INDEX) {
+    case IW_AUTH_CIPHER_PAIRWISE:
+    case IW_AUTH_CIPHER_GROUP:
+        if (vwrq->value & IW_AUTH_CIPHER_NONE)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_NONE;
+        else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_WEP40;
+        else if (vwrq->value & IW_AUTH_CIPHER_TKIP)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_TKIP;
+        else if (vwrq->value & IW_AUTH_CIPHER_CCMP)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_CCMP;
+        else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
+            priv->adapter->SecInfo.EncryptionMode = CIPHER_WEP104;
+        break;
+    case IW_AUTH_80211_AUTH_ALG:
+        wlan_setauthalg(priv, vwrq->value);
+        break;
+    case IW_AUTH_WPA_ENABLED:
+        if (vwrq->value == FALSE)
+            wlan_set_wpa_ie_helper(priv, NULL, 0);
+        break;
+    case IW_AUTH_WPA_VERSION:
+    case IW_AUTH_KEY_MGMT:
+    case IW_AUTH_TKIP_COUNTERMEASURES:
+    case IW_AUTH_DROP_UNENCRYPTED:
+    case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+    case IW_AUTH_ROAMING_CONTROL:
+    case IW_AUTH_PRIVACY_INVOKED:
+    default:
+        break;
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  get authentication mode params 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_auth(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+    ENTER();
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+    switch (vwrq->flags & IW_AUTH_INDEX) {
+    case IW_AUTH_CIPHER_PAIRWISE:
+    case IW_AUTH_CIPHER_GROUP:
+        if (priv->adapter->SecInfo.EncryptionMode == CIPHER_NONE)
+            vwrq->value = IW_AUTH_CIPHER_NONE;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_WEP40)
+            vwrq->value = IW_AUTH_CIPHER_WEP40;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_TKIP)
+            vwrq->value = IW_AUTH_CIPHER_TKIP;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_CCMP)
+            vwrq->value = IW_AUTH_CIPHER_CCMP;
+        else if (priv->adapter->SecInfo.EncryptionMode == CIPHER_WEP104)
+            vwrq->value = IW_AUTH_CIPHER_WEP104;
+        break;
+    case IW_AUTH_80211_AUTH_ALG:
+        if (Adapter->SecInfo.AuthenticationMode == Wlan802_11AuthModeShared)
+            vwrq->value = IW_AUTH_ALG_SHARED_KEY;
+        else if (Adapter->SecInfo.AuthenticationMode ==
+                 Wlan802_11AuthModeNetworkEAP)
+            vwrq->value = IW_AUTH_ALG_LEAP;
+        else
+            vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+        break;
+    case IW_AUTH_WPA_ENABLED:
+        if (Adapter->Wpa_ie_len > 0)
+            vwrq->value = TRUE;
+        else
+            vwrq->value = FALSE;
+        break;
+    case IW_AUTH_WPA_VERSION:
+    case IW_AUTH_KEY_MGMT:
+    case IW_AUTH_TKIP_COUNTERMEASURES:
+    case IW_AUTH_DROP_UNENCRYPTED:
+    case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+    case IW_AUTH_ROAMING_CONTROL:
+    case IW_AUTH_PRIVACY_INVOKED:
+    default:
+        ret = -EOPNOTSUPP;
+        break;
+    }
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief  Request MLME operation 
+ *
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_mlme(struct net_device *dev,
+              struct iw_request_info *info,
+              struct iw_point *dwrq, char *extra)
+{
+    struct iw_mlme *mlme = (struct iw_mlme *) extra;
+    wlan_private *priv = dev->priv;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+    if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
+        wlan_disconnect(priv);
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Extended version of encoding configuration 
+ *
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode_ext(struct net_device *dev,
+                    struct iw_request_info *info,
+                    struct iw_point *dwrq, char *extra)
+{
+    struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+    wlan_private *priv = dev->priv;
+    WLAN_802_11_KEY *pkey;
+    int keyindex;
+    u8 *pKeyMaterial = NULL;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+    keyindex = dwrq->flags & IW_ENCODE_INDEX;
+    if (keyindex > 4) {
+        LEAVE();
+        return -EINVAL;
+    }
+    if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
+        LEAVE();
+        return -EINVAL;
+    }
+    pKeyMaterial = (u8 *) (ext + 1);
+    //Disable Key
+    if ((dwrq->flags & IW_ENCODE_DISABLED) && (ext->key_len == 0)) {
+        dwrq->length = 0;
+        wlan_set_encode_nonwpa(dev, info, dwrq, extra);
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+    //Set WEP key
+    if (ext->key_len <= MAX_WEP_KEY_SIZE) {
+        dwrq->length = ext->key_len;
+        wlan_set_encode_nonwpa(dev, info, dwrq, pKeyMaterial);
+        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+            dwrq->length = 0;
+            wlan_set_encode_nonwpa(dev, info, dwrq, extra);
+        }
+    } else {
+        pkey = kmalloc(sizeof(WLAN_802_11_KEY) + ext->key_len, GFP_KERNEL);
+        if (!pkey) {
+            PRINTM(INFO, "allocate key buffer failed!\n");
+            LEAVE();
+            return -ENOMEM;
+        }
+        memset(pkey, 0, sizeof(WLAN_802_11_KEY) + ext->key_len);
+        memcpy((u8 *) pkey->BSSID, (u8 *) ext->addr.sa_data, ETH_ALEN);
+        pkey->KeyLength = ext->key_len;
+        memcpy(pkey->KeyMaterial, pKeyMaterial, ext->key_len);
+        pkey->KeyIndex = keyindex - 1;
+        if (pkey->KeyIndex == 0)
+            pkey->KeyIndex = 0x40000000;
+        if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+            memcpy((u8 *) & pkey->KeyRSC, ext->rx_seq,
+                   IW_ENCODE_SEQ_MAX_SIZE);
+        pkey->Length = sizeof(WLAN_802_11_KEY) + ext->key_len;
+        wlan_set_encode_wpa(dev, info, dwrq, (u8 *) pkey);
+        kfree(pkey);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief  Extended version of encoding configuration 
+ *
+ *   
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_encode_ext(struct net_device *dev,
+                    struct iw_request_info *info,
+                    struct iw_point *dwrq, char *extra)
+{
+    ENTER();
+    LEAVE();
+    return -EOPNOTSUPP;
+}
+#endif /* #if (WIRELESS_EXT >= 18) */
+
+/** 
+ *  @brief  Append/Reset IE buffer. 
+ *   
+ *  Pass an opaque block of data, expected to be IEEE IEs, to the driver 
+ *    for eventual passthrough to the firmware in an associate/join 
+ *    (and potentially start) command.
+ *
+ *  Data is appended to an existing buffer and then wrapped in a passthrough
+ *    TLV in the command API to the firmware.  The firmware treats the data
+ *    as a transparent passthrough to the transmitted management frame.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure    
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_gen_ie_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    ret = wlan_set_gen_ie_helper(priv,
+                                 wrq->u.data.pointer, wrq->u.data.length);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief  Get IE buffer from driver 
+ *   
+ *  Used to pass an opaque block of data, expected to be IEEE IEs,
+ *    back to the application.  Currently the data block passed
+ *    back to the application is the saved association response retrieved 
+ *    from the firmware.
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure
+ *
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_gen_ie_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    ret = wlan_get_gen_ie_helper(priv,
+                                 wrq->u.data.pointer, &wrq->u.data.length);
+    LEAVE();
+    return ret;
+}
+
+/*
+ * iwconfig settable callbacks 
+ */
+static const iw_handler wlan_handler[] = {
+    (iw_handler) wlan_config_commit,    /* SIOCSIWCOMMIT */
+    (iw_handler) wlan_get_name, /* SIOCGIWNAME */
+    (iw_handler) NULL,          /* SIOCSIWNWID */
+    (iw_handler) NULL,          /* SIOCGIWNWID */
+    (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
+    (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
+    (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
+    (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
+    (iw_handler) wlan_set_sens, /* SIOCSIWSENS */
+    (iw_handler) wlan_get_sens, /* SIOCGIWSENS */
+    (iw_handler) NULL,          /* SIOCSIWRANGE */
+    (iw_handler) wlan_get_range,        /* SIOCGIWRANGE */
+    (iw_handler) NULL,          /* SIOCSIWPRIV */
+    (iw_handler) NULL,          /* SIOCGIWPRIV */
+    (iw_handler) NULL,          /* SIOCSIWSTATS */
+    (iw_handler) NULL,          /* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+    iw_handler_set_spy,         /* SIOCSIWSPY */
+    iw_handler_get_spy,         /* SIOCGIWSPY */
+    iw_handler_set_thrspy,      /* SIOCSIWTHRSPY */
+    iw_handler_get_thrspy,      /* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
+#ifdef WIRELESS_SPY
+    (iw_handler) wlan_set_spy,  /* SIOCSIWSPY */
+    (iw_handler) wlan_get_spy,  /* SIOCGIWSPY */
+#else /* WIRELESS_SPY */
+    (iw_handler) NULL,          /* SIOCSIWSPY */
+    (iw_handler) NULL,          /* SIOCGIWSPY */
+#endif /* WIRELESS_SPY */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) NULL,          /* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
+    (iw_handler) wlan_set_wap,  /* SIOCSIWAP */
+    (iw_handler) wlan_get_wap,  /* SIOCGIWAP */
+#if WIRELESS_EXT >= 18
+    (iw_handler) wlan_set_mlme, /* SIOCSIWMLME  */
+#else
+    (iw_handler) NULL,          /* -- hole -- */
+#endif
+    //(iw_handler) wlan_get_aplist,         /* SIOCGIWAPLIST */
+    NULL,                       /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+    (iw_handler) wlan_set_scan, /* SIOCSIWSCAN */
+    (iw_handler) wlan_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+    (iw_handler) NULL,          /* SIOCSIWSCAN */
+    (iw_handler) NULL,          /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+    (iw_handler) wlan_set_essid,        /* SIOCSIWESSID */
+    (iw_handler) wlan_get_essid,        /* SIOCGIWESSID */
+    (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
+    (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
+    (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
+    (iw_handler) wlan_set_rts,  /* SIOCSIWRTS */
+    (iw_handler) wlan_get_rts,  /* SIOCGIWRTS */
+    (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
+    (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
+    (iw_handler) wlan_set_txpow,        /* SIOCSIWTXPOW */
+    (iw_handler) wlan_get_txpow,        /* SIOCGIWTXPOW */
+    (iw_handler) wlan_set_retry,        /* SIOCSIWRETRY */
+    (iw_handler) wlan_get_retry,        /* SIOCGIWRETRY */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) wlan_get_encode,       /* SIOCGIWENCODE */
+    (iw_handler) wlan_set_power,        /* SIOCSIWPOWER */
+    (iw_handler) wlan_get_power,        /* SIOCGIWPOWER */
+#if (WIRELESS_EXT >= 18)
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) NULL,          /* -- hole -- */
+    (iw_handler) wlan_set_gen_ie,       /* SIOCSIWGENIE */
+    (iw_handler) wlan_get_gen_ie,       /* SIOCGIWGENIE */
+    (iw_handler) wlan_set_auth, /* SIOCSIWAUTH  */
+    (iw_handler) wlan_get_auth, /* SIOCGIWAUTH  */
+    (iw_handler) wlan_set_encode_ext,   /* SIOCSIWENCODEEXT */
+    (iw_handler) wlan_get_encode_ext,   /* SIOCGIWENCODEEXT */
+#endif /* WIRELESSS_EXT >= 18 */
+};
+
+/*
+ * iwpriv settable callbacks 
+ */
+
+static const iw_handler wlan_private_handler[] = {
+    NULL,                       /* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_priv_args wlan_private_args[] = {
+    /*
+     * { cmd, set_args, get_args, name } 
+     */
+    {
+     WLANEXTSCAN,
+     IW_PRIV_TYPE_INT,
+     IW_PRIV_TYPE_CHAR | 2,
+     "extscan"},
+    {
+     WLANHOSTCMD,
+     IW_PRIV_TYPE_BYTE | 2047,
+     IW_PRIV_TYPE_BYTE | 2047,
+     "hostcmd"},
+    {
+     WLANARPFILTER,
+     IW_PRIV_TYPE_BYTE | 2047,
+     IW_PRIV_TYPE_BYTE | 2047,
+     "arpfilter"},
+    {
+     WLANREGRDWR,
+     IW_PRIV_TYPE_CHAR | 256,
+     IW_PRIV_TYPE_CHAR | 256,
+     "regrdwr"},
+    {
+     WLANCMD52RDWR,
+     IW_PRIV_TYPE_BYTE | 7,
+     IW_PRIV_TYPE_BYTE | 7,
+     "sdcmd52rw"},
+    {
+     WLANCMD53RDWR,
+     IW_PRIV_TYPE_CHAR | CMD53BUFLEN,
+     IW_PRIV_TYPE_CHAR | CMD53BUFLEN,
+     "sdcmd53rw"},
+    {
+     WLAN_SETCONF_GETCONF,
+     IW_PRIV_TYPE_BYTE | MAX_SETGET_CONF_SIZE,
+     IW_PRIV_TYPE_BYTE | MAX_SETGET_CONF_SIZE,
+     "setgetconf"},
+    {
+     WLANCISDUMP,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_BYTE | 512,
+     "getcis"},
+    {
+     WLANSCAN_TYPE,
+     IW_PRIV_TYPE_CHAR | 8,
+     IW_PRIV_TYPE_CHAR | 8,
+     "scantype"},
+    {
+     WLAN_SETADDR_GETNONE,
+     IW_PRIV_TYPE_ADDR | 1,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLANDEAUTH,
+     IW_PRIV_TYPE_ADDR | 1,
+     IW_PRIV_TYPE_NONE,
+     "deauth"},
+    {
+     WLAN_SETINT_GETINT,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     ""},
+    {
+     WLANNF,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getNF"},
+    {
+     WLANRSSI,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getRSSI"},
+    {
+     WLANBGSCAN,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "bgscan"},
+    {
+     WLANENABLE11D,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "enable11d"},
+    {
+     WLANADHOCGRATE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "adhocgrate"},
+    {
+     WLANSDIOCLOCK,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "sdioclock"},
+    {
+     WLANWMM_ENABLE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "wmm"},
+    {
+     WLANNULLGEN,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "uapsdnullgen"},
+    {
+     WLANADHOCCSET,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "setcoalescing"},
+    {
+     WLAN_ADHOC_G_PROT,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "adhocgprot"},
+    {
+     WLAN_SETONEINT_GETONEINT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     ""},
+    {
+     WLAN_11H_SETLOCALPOWER,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "setpowercons"},
+    {
+     WLAN_WMM_QOSINFO,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "wmm_qosinfo"},
+    {
+     WLAN_LISTENINTRVL,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "lolisteninter"},
+    {
+     WLAN_FW_WAKEUP_METHOD,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "fwwakeupmethod"},
+    {
+     WLAN_NULLPKTINTERVAL,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "psnullinterval"},
+    {
+     WLAN_BCN_MISS_TIMEOUT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "bcnmisto"},
+    {
+     WLAN_ADHOC_AWAKE_PERIOD,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "adhocawakepd"},
+    {
+     WLAN_MODULE_TYPE,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "moduletype"},
+    {
+     WLAN_AUTODEEPSLEEP,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "autodeepsleep"},
+    {
+     WLAN_ENHANCEDPS,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "enhanceps"},
+    {
+     WLAN_WAKEUP_MT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_INT | 1,
+     "wakeupmt"},
+
+    /* Using iwpriv sub-command feature */
+    {
+     WLAN_SETONEINT_GETNONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLAN_SUBCMD_SETRXANTENNA,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setrxant"},
+    {
+     WLAN_SUBCMD_SETTXANTENNA,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "settxant"},
+    {
+     WLANSETAUTHALG,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "authalgs",
+     },
+    {
+     WLANSETENCRYPTIONMODE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "encryptionmode",
+     },
+    {
+     WLANSETREGION,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setregioncode"},
+    {
+     WLAN_SET_LISTEN_INTERVAL,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setlisteninter"},
+    {
+     WLAN_SET_MULTIPLE_DTIM,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setmultipledtim"},
+    {
+     WLANSETBCNAVG,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setbcnavg"},
+    {
+     WLANSETDATAAVG,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "setdataavg"},
+    {
+     WLANASSOCIATE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     IW_PRIV_TYPE_NONE,
+     "associate"},
+    {
+     WLAN_SETNONE_GETONEINT,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     ""},
+    {
+     WLANGETREGION,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getregioncode"},
+    {
+     WLAN_GET_LISTEN_INTERVAL,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getlisteninter"},
+    {
+     WLAN_GET_MULTIPLE_DTIM,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getmultipledtim"},
+    {
+     WLAN_GET_TX_RATE,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "gettxrate"},
+    {
+     WLANGETBCNAVG,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getbcnavg"},
+    {
+     WLANGETDATAAVG,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+     "getdataavg"},
+    {
+     WLAN_SETNONE_GETTWELVE_CHAR,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     ""},
+    {
+     WLAN_SUBCMD_GETRXANTENNA,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "getrxant"},
+    {
+     WLAN_SUBCMD_GETTXANTENNA,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "gettxant"},
+    {
+     WLAN_GET_TSF,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "gettsf"},
+    {
+     WLAN_WPS_SESSION,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 12,
+     "wpssession"},
+    {
+     WLANDEEPSLEEP,
+     IW_PRIV_TYPE_CHAR | 1,
+     IW_PRIV_TYPE_CHAR | 6,
+     "deepsleep"},
+    {
+     WLAN_SETNONE_GETNONE,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLANADHOCSTOP,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "adhocstop"},
+    {
+     WLANRADIOON,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "radioon"},
+    {
+     WLANRADIOOFF,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "radiooff"},
+    {
+     WLANREMOVEADHOCAES,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "rmaeskey"},
+    {
+     WLANCRYPTOTEST,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "crypto_test"},
+#ifdef REASSOCIATION
+    {
+     WLANREASSOCIATIONAUTO,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "reasso-on"},
+    {
+     WLANREASSOCIATIONUSER,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "reasso-off"},
+#endif /* REASSOCIATION */
+    {
+     WLANWLANIDLEON,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "wlanidle-on"},
+    {
+     WLANWLANIDLEOFF,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_NONE,
+     "wlanidle-off"},
+    {
+     WLAN_SET64CHAR_GET64CHAR,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     ""},
+    {
+     WLANSLEEPPARAMS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "sleepparams"},
+
+    {
+     WLAN_11H_REQUESTTPC,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "requesttpc"},
+    {
+     WLAN_11H_SETPOWERCAP,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "powercap"},
+    {
+     WLAN_MEASREQ,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "measreq"},
+    {
+     WLAN_BCA_TIMESHARE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "bca-ts"},
+    {
+     WLANSCAN_MODE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "scanmode"},
+    {
+     WLAN_GET_ADHOC_STATUS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "getadhocstatus"},
+    {
+     WLAN_SET_GEN_IE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "setgenie"},
+    {
+     WLAN_GET_GEN_IE,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "getgenie"},
+    {
+     WLAN_WMM_QUEUE_STATUS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "qstatus"},
+    {
+     WLAN_WMM_TS_STATUS,
+     IW_PRIV_TYPE_CHAR | 64,
+     IW_PRIV_TYPE_CHAR | 64,
+     "ts_status"},
+    {
+     WLAN_SETWORDCHAR_GETNONE,
+     IW_PRIV_TYPE_CHAR | 32,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLANSETADHOCAES,
+     IW_PRIV_TYPE_CHAR | 32,
+     IW_PRIV_TYPE_NONE,
+     "setaeskey"},
+    {
+     WLAN_SETONEINT_GETWORDCHAR,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     ""},
+    {
+     WLANGETADHOCAES,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     "getaeskey"},
+    {
+     WLANVERSION,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     "version"},
+    {
+     WLANVEREXT,
+     IW_PRIV_TYPE_INT | 1,
+     IW_PRIV_TYPE_CHAR | 128,
+     "verext"},
+    {
+     WLANSETWPAIE,
+     IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+     IW_PRIV_TYPE_NONE,
+     "setwpaie"},
+    {
+     WLAN_SETTENCHAR_GETNONE,
+     IW_PRIV_TYPE_CHAR | 10,
+     IW_PRIV_TYPE_NONE,
+     ""},
+    {
+     WLAN_SET_BAND,
+     IW_PRIV_TYPE_CHAR | 10,
+     IW_PRIV_TYPE_NONE,
+     "setband"},
+    {
+     WLAN_SET_ADHOC_CH,
+     IW_PRIV_TYPE_CHAR | 10,
+     IW_PRIV_TYPE_NONE,
+     "setadhocch"},
+    {
+     WLAN_11H_CHANSWANN,
+     IW_PRIV_TYPE_CHAR | 10,
+     IW_PRIV_TYPE_NONE,
+     "chanswann"},
+    {
+     WLAN_SETNONE_GETTENCHAR,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 10,
+     ""},
+    {
+     WLAN_GET_BAND,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 10,
+     "getband"},
+    {
+     WLAN_GET_ADHOC_CH,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | 10,
+     "getadhocch"},
+    {
+     WLANGETLOG,
+     IW_PRIV_TYPE_NONE,
+     IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+     "getlog"},
+    {
+     WLAN_SET_GET_SIXTEEN_INT,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     ""},
+    {
+     WLAN_TPCCFG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "tpccfg"},
+    {
+     WLAN_SCANPROBES,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "scanprobes"},
+    {
+     WLAN_LED_GPIO_CTRL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "ledgpio"},
+    {
+     WLAN_SLEEP_PERIOD,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "sleeppd"},
+    {
+     WLAN_ADAPT_RATESET,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "rateadapt"},
+
+    {
+     WLAN_INACTIVITY_TIMEOUT,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "inactivityto"},
+    {
+     WLANSNR,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "getSNR"},
+    {
+     WLAN_GET_RATE,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "getrate"},
+    {
+     WLAN_GET_RXINFO,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "getrxinfo"},
+    {
+     WLAN_SET_ATIM_WINDOW,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "atimwindow"},
+    {
+     WLAN_BEACON_INTERVAL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "bcninterval"},
+    {
+     WLAN_SDIO_PULL_CTRL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "sdiopullctrl"},
+    {
+     WLAN_SCAN_TIME,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "scantime"},
+    {
+     WLAN_ECL_SYS_CLOCK,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "sysclock"},
+    {
+     WLAN_TXCONTROL,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "txcontrol"},
+    {
+     WLANHSCFG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "hscfg"},
+    {
+     WLANHSSETPARA,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "hssetpara"},
+    {
+     WLANDBGSCFG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "dbgscfg"},
+#ifdef DEBUG_LEVEL1
+    {
+     WLAN_DRV_DBG,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "drvdbg"},
+#endif
+    {
+     WLAN_DRV_DELAY_MAX,
+     IW_PRIV_TYPE_INT | 16,
+     IW_PRIV_TYPE_INT | 16,
+     "drvdelaymax"},
+    {
+     WLAN_SET_GET_2K,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     ""},
+    {
+     WLAN_SET_USER_SCAN,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "setuserscan"},
+    {
+     WLAN_GET_SCAN_TABLE,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getscantable"},
+    {
+     WLAN_SET_MRVL_TLV,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "setmrvltlv"},
+    {
+     WLAN_GET_ASSOC_RSP,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getassocrsp"},
+    {
+     WLAN_ADDTS_REQ,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "addts"},
+    {
+     WLAN_DELTS_REQ,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "delts"},
+    {
+     WLAN_QUEUE_CONFIG,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "qconfig"},
+    {
+     WLAN_QUEUE_STATS,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "qstats"},
+    {
+     WLAN_TX_PKT_STATS,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "txpktstats"},
+    {
+     WLAN_GET_CFP_TABLE,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getcfptable"},
+    {
+     WLAN_MEF_CFG,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "mefcfg"},
+    {
+     WLAN_GET_MEM,
+     IW_PRIV_TYPE_BYTE | 2000,
+     IW_PRIV_TYPE_BYTE | 2000,
+     "getmem"},
+};
+
+/** wlan_handler_def */
+struct iw_handler_def wlan_handler_def = {
+  num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
+  num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
+  num_private_args:sizeof(wlan_private_args) /
+        sizeof(struct iw_priv_args),
+  standard:(iw_handler *) wlan_handler,
+  private:(iw_handler *) wlan_private_handler,
+  private_args:(struct iw_priv_args *) wlan_private_args,
+#if WIRELESS_EXT > 20
+  get_wireless_stats:wlan_get_wireless_stats,
+#endif
+};
+
+/** 
+ *  @brief wlan hostcmd ioctl handler
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param req		        A pointer to ifreq structure
+ *  @param cmd			command 
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_hostcmd_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+    u8 *tempResponseBuffer;
+    CmdCtrlNode *pCmdNode;
+    HostCmd_DS_GEN *pCmdPtr;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    u16 wait_option = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    if ((wrq->u.data.pointer == NULL) || (wrq->u.data.length < S_DS_GEN)) {
+        PRINTM(INFO,
+               "wlan_hostcmd_ioctl() corrupt data: pointer=%p, length=%d\n",
+               wrq->u.data.pointer, wrq->u.data.length);
+        LEAVE();
+        return -EFAULT;
+    }
+
+    /*
+     * Get a free command control node 
+     */
+    if (!(pCmdNode = wlan_get_cmd_node(priv))) {
+        PRINTM(INFO, "Failed wlan_get_cmd_node\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+
+    if (!
+        (tempResponseBuffer =
+         kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
+        PRINTM(INFO, "ERROR: Failed to allocate response buffer!\n");
+        wlan_insert_cmd_to_free_q(priv, pCmdNode);
+        LEAVE();
+        return -ENOMEM;
+    }
+
+    wait_option |= HostCmd_OPTION_WAITFORRSP;
+
+    wlan_init_cmd_node(priv, pCmdNode, 0, wait_option, NULL);
+    init_waitqueue_head(&pCmdNode->cmdwait_q);
+
+    pCmdPtr = (HostCmd_DS_GEN *) pCmdNode->BufVirtualAddr;
+
+    /*
+     * Copy the whole command into the command buffer 
+     */
+    if (copy_from_user(pCmdPtr, wrq->u.data.pointer, wrq->u.data.length)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(tempResponseBuffer);
+        wlan_insert_cmd_to_free_q(priv, pCmdNode);
+        LEAVE();
+        return -EFAULT;
+    }
+
+    if (pCmdPtr->Size < S_DS_GEN) {
+        PRINTM(INFO, "wlan_hostcmd_ioctl() invalid cmd size: Size=%d\n",
+               pCmdPtr->Size);
+        kfree(tempResponseBuffer);
+        wlan_insert_cmd_to_free_q(priv, pCmdNode);
+        LEAVE();
+        return -EFAULT;
+    }
+
+    pCmdNode->pdata_buf = tempResponseBuffer;
+    pCmdNode->CmdFlags |= CMD_F_HOSTCMD;
+
+    pCmdPtr->Result = 0;
+
+    PRINTM(INFO, "HOSTCMD Command: 0x%04x Size: %d\n",
+           pCmdPtr->Command, pCmdPtr->Size);
+    HEXDUMP("Command Data", (u8 *) (pCmdPtr), MIN(32, pCmdPtr->Size));
+    PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n",
+           req->ifr_data, pCmdPtr);
+
+    pCmdNode->CmdWaitQWoken = FALSE;
+    pCmdPtr->Command = wlan_cpu_to_le16(pCmdPtr->Command);
+    pCmdPtr->Size = wlan_cpu_to_le16(pCmdPtr->Size);
+    wlan_insert_cmd_to_pending_q(Adapter, pCmdNode, TRUE);
+    wake_up_interruptible(&priv->MainThread.waitQ);
+
+    if (wait_option & HostCmd_OPTION_WAITFORRSP) {
+        /* Sleep until response is generated by FW */
+        wait_event_interruptible(pCmdNode->cmdwait_q,
+                                 pCmdNode->CmdWaitQWoken);
+    }
+
+    /* Copy the response back to user space */
+    pCmdPtr = (HostCmd_DS_GEN *) tempResponseBuffer;
+
+    if (copy_to_user(wrq->u.data.pointer, tempResponseBuffer, pCmdPtr->Size))
+        PRINTM(INFO, "ERROR: copy_to_user failed!\n");
+    wrq->u.data.length = pCmdPtr->Size;
+    kfree(tempResponseBuffer);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief wlan arpfilter ioctl handler
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param req		        A pointer to ifreq structure
+ *  @param cmd			command 
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_arpfilter_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+    wlan_private *priv = dev->priv;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypesHeader_t hdr;
+
+    ENTER();
+
+    if ((wrq->u.data.pointer == NULL)
+        || (wrq->u.data.length < sizeof(MrvlIEtypesHeader_t))
+        || (wrq->u.data.length > sizeof(Adapter->ArpFilter))) {
+        PRINTM(INFO,
+               "wlan_arpfilter_ioctl() corrupt data: pointer=%p, length=%d\n",
+               wrq->u.data.pointer, wrq->u.data.length);
+        LEAVE();
+        return -EFAULT;
+    }
+
+    if (copy_from_user(&hdr, wrq->u.data.pointer, sizeof(hdr))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    if (hdr.Len == 0) {
+        Adapter->ArpFilterSize = 0;
+        memset(Adapter->ArpFilter, 0, sizeof(Adapter->ArpFilter));
+    } else {
+        Adapter->ArpFilterSize = wrq->u.data.length;
+
+        PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n",
+               wrq->u.data.pointer, Adapter->ArpFilter);
+        if (copy_from_user(Adapter->ArpFilter, wrq->u.data.pointer,
+                           Adapter->ArpFilterSize)) {
+            Adapter->ArpFilterSize = 0;
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        HEXDUMP("ArpFilter", Adapter->ArpFilter, Adapter->ArpFilterSize);
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Rx Info 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success
+ */
+static int
+wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[2];
+    ENTER();
+    data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+    data[1] = Adapter->RxPDRate;
+    if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+    wrq->u.data.length = 2;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get SNR 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    int data[4];
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        PRINTM(INFO, "Can not get SNR in disconnected state\n");
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    memset(data, 0, sizeof(data));
+    if (wrq->u.data.length) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer,
+             MIN(wrq->u.data.length, 4) * sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+    if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RSSI,
+                               0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    if (wrq->u.data.length == 0) {
+        data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+        data[1] = Adapter->SNR[TYPE_BEACON][TYPE_AVG];
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            data[2] = 0;
+        else
+            data[2] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+        data[3] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = 4;
+    } else if (data[0] == 0) {
+        data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else if (data[0] == 1) {
+        data[0] = Adapter->SNR[TYPE_BEACON][TYPE_AVG];
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else if (data[0] == 2) {
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            data[0] = 0;
+        else
+            data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else if (data[0] == 3) {
+        data[0] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    } else {
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set SDIO PULL CTRL 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_sdio_pull_ctrl(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[2];
+    HostCmd_DS_SDIO_PULL_CTRL sdio_pull_ctrl;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+    memset(&sdio_pull_ctrl, 0, sizeof(sdio_pull_ctrl));
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(data))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        PRINTM(INFO, "WLAN SET SDIO PULL CTRL: %d %d\n", data[0], data[1]);
+        sdio_pull_ctrl.Action = HostCmd_ACT_GEN_SET;
+        sdio_pull_ctrl.PullUp = data[0];
+        sdio_pull_ctrl.PullDown = data[1];
+    } else {
+        sdio_pull_ctrl.Action = HostCmd_ACT_GEN_GET;
+    }
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_SDIO_PULL_CTRL,
+                           0, HostCmd_OPTION_WAITFORRSP,
+                           0, (void *) &sdio_pull_ctrl);
+    data[0] = sdio_pull_ctrl.PullUp;
+    data[1] = sdio_pull_ctrl.PullDown;
+    wrq->u.data.length = 2;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set scan time
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_scan_time(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[3] = { 0, 0, 0 };
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0 && wrq->u.data.length <= 3) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        PRINTM(INFO,
+               "WLAN SET Scan Time: Specific %d, Active %d, Passive %d\n",
+               data[0], data[1], data[2]);
+        if (data[0]) {
+            if (data[0] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) {
+                PRINTM(MSG,
+                       "Invalid parameter, max specific scan time is %d ms\n",
+                       MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME);
+                LEAVE();
+                return -EINVAL;
+            }
+            Adapter->SpecificScanTime = data[0];
+        }
+        if (data[1]) {
+            if (data[1] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME) {
+                PRINTM(MSG,
+                       "Invalid parameter, max active scan time is %d ms\n",
+                       MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME);
+                LEAVE();
+                return -EINVAL;
+            }
+            Adapter->ActiveScanTime = data[1];
+        }
+        if (data[2]) {
+            if (data[2] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME) {
+                PRINTM(MSG,
+                       "Invalid parameter, max passive scan time is %d ms\n",
+                       MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME);
+                LEAVE();
+                return -EINVAL;
+            }
+            Adapter->PassiveScanTime = data[2];
+        }
+    }
+
+    data[0] = Adapter->SpecificScanTime;
+    data[1] = Adapter->ActiveScanTime;
+    data[2] = Adapter->PassiveScanTime;
+    wrq->u.data.length = 3;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Adhoc beacon Interval 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[2];
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        PRINTM(INFO, "WLAN SET BEACON INTERVAL: %d\n", data[0]);
+        if ((data[0] > MRVDRV_MAX_BEACON_INTERVAL) ||
+            (data[0] < MRVDRV_MIN_BEACON_INTERVAL)) {
+            LEAVE();
+            return -ENOTSUPP;
+        }
+        Adapter->BeaconPeriod = data[0];
+    }
+    data[0] = Adapter->BeaconPeriod;
+    wrq->u.data.length = 1;
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        data[1] = Adapter->CurBssParams.BSSDescriptor.BeaconPeriod;
+        wrq->u.data.length = 2;
+    }
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Adhoc ATIM Window 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_atim_window(wlan_private * priv, struct iwreq *wrq)
+{
+    int data[2];
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        PRINTM(INFO, "WLAN SET ATIM WINDOW: %d\n", data[0]);
+        Adapter->AtimWindow = data[0];
+        Adapter->AtimWindow = MIN(Adapter->AtimWindow, 50);
+    }
+    data[0] = Adapter->AtimWindow;
+    wrq->u.data.length = 1;
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        data[1] = Adapter->CurBssParams.BSSDescriptor.ATIMWindow;
+        wrq->u.data.length = 2;
+    }
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set system clock
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_ecl_sys_clock(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG cmd;
+    u16 action;
+    int data[16], len, i;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    memset(&cmd, 0, sizeof(HostCmd_DS_ECL_SYSTEM_CLOCK_CONFIG));
+    if (wrq->u.data.length > 0) {
+        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        PRINTM(INFO, "WLAN set system clock: %d\n", data[0]);
+        action = HostCmd_ACT_GEN_SET;
+        cmd.Action = action;
+        cmd.SystemClock = (u16) data[0];
+    } else {
+        action = HostCmd_ACT_GEN_GET;
+        cmd.Action = action;
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_ECL_SYSTEM_CLOCK_CONFIG,
+                           action, HostCmd_OPTION_WAITFORRSP,
+                           0, (void *) &cmd);
+
+    if (!ret && action == HostCmd_ACT_GEN_GET) {
+        data[0] = cmd.SystemClock;
+        PRINTM(INFO, "WLAN get system clock: %d\n", data[0]);
+        len = MIN(cmd.SupportedSysClockLen / sizeof(u16),
+                  sizeof(data) / sizeof(data[0]) - 1);
+        for (i = 0; i < len; i++) {
+            data[i + 1] = cmd.SupportedSysClock[i];
+        }
+        wrq->u.data.length = 1 + len;
+
+        if (copy_to_user
+            (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get RSSI 
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    int temp;
+    int data = 0;
+    int *val;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        PRINTM(INFO, "Can not get RSSI in disconnected state\n");
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    if ((data == 0) || (data == 1)) {
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RSSI,
+                               0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    switch (data) {
+    case 0:
+
+        temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+                        Adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+        break;
+    case 1:
+        temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG],
+                        Adapter->NF[TYPE_BEACON][TYPE_AVG]);
+        break;
+    case 2:
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            temp = 0;
+        else
+            temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+                            Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+        break;
+    case 3:
+        temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+                        Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+        break;
+    default:
+        LEAVE();
+        return -ENOTSUPP;
+    }
+    val = (int *) wrq->u.name;
+    *val = temp;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get NF
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wreq		        A pointer to iwreq structure 
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+    int temp;
+    int data = 0;
+    int *val;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) {
+        PRINTM(INFO, "Can not get NF in disconnected state\n");
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    if ((data == 0) || (data == 1)) {
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RSSI,
+                               0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+    }
+
+    switch (data) {
+    case 0:
+        temp = Adapter->NF[TYPE_BEACON][TYPE_NOAVG];
+        break;
+    case 1:
+        temp = Adapter->NF[TYPE_BEACON][TYPE_AVG];
+        break;
+    case 2:
+        if ((jiffies - Adapter->RxPDAge) > HZ)  //data expired after 1 second
+            temp = 0;
+        else
+            temp = Adapter->NF[TYPE_RXPD][TYPE_NOAVG];
+        break;
+    case 3:
+        temp = Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+        break;
+    default:
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    temp = CAL_NF(temp);
+
+    PRINTM(INFO, "***temp = %d\n", temp);
+    val = (int *) wrq->u.name;
+    *val = temp;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Remove AES key
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_remove_aes(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_KEY key;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS ||
+        Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+    Adapter->AdhocAESEnabled = FALSE;
+
+    memset(&key, 0, sizeof(WLAN_802_11_KEY));
+    PRINTM(INFO, "WPA2: DISABLE AES_KEY\n");
+    key.KeyLength = WPA_AES_KEY_LEN;
+    key.KeyIndex = 0x40000000;
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_KEY_MATERIAL,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP,
+                           !(KEY_INFO_ENABLED), &key);
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief Get Support Rates
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_getrate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_RATES rates;
+    int rate[sizeof(rates)];
+    int i;
+
+    ENTER();
+
+    memset(rates, 0, sizeof(rates));
+    memset(rate, 0, sizeof(rate));
+    wrq->u.data.length = get_active_data_rates(Adapter, rates);
+    if (wrq->u.data.length > sizeof(rates))
+        wrq->u.data.length = sizeof(rates);
+
+    for (i = 0; i < wrq->u.data.length; i++) {
+        rates[i] &= ~0x80;
+        rate[i] = rates[i];
+    }
+
+    if (copy_to_user
+        (wrq->u.data.pointer, rate, wrq->u.data.length * sizeof(int))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get TxRate
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int *pdata;
+    struct iwreq *wrq = (struct iwreq *) req;
+    int ret = WLAN_STATUS_SUCCESS;
+    ENTER();
+    Adapter->TxRate = 0;
+    PRINTM(INFO, "wlan_get_txrate_ioctl\n");
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                           HostCmd_ACT_GEN_GET, HostCmd_OPTION_WAITFORRSP,
+                           0, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+    pdata = (int *) wrq->u.name;
+    *pdata = (int) Adapter->TxRate;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Adhoc Status
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    char status[64];
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    memset(status, 0, sizeof(status));
+
+    switch (Adapter->InfrastructureMode) {
+    case Wlan802_11IBSS:
+        if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+            switch (Adapter->AdhocState) {
+            case ADHOC_STARTED:
+                strcpy(status, "AdhocStarted");
+                break;
+            case ADHOC_JOINED:
+                strcpy(status, "AdhocJoined");
+                break;
+            case ADHOC_COALESCED:
+                strcpy(status, "AdhocCoalesced");
+                break;
+            default:
+                strcpy(status, "InvalidAdhocState");
+                break;
+            }
+        } else {
+            strcpy(status, "AdhocIdle");
+        }
+        break;
+    case Wlan802_11Infrastructure:
+        strcpy(status, "InfraMode");
+        break;
+    default:
+        strcpy(status, "AutoUnknownMode");
+        break;
+    }
+
+    PRINTM(INFO, "Status = %s\n", status);
+    wrq->u.data.length = strlen(status) + 1;
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &status, wrq->u.data.length)) {
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Driver Version
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_version_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int len;
+    char buf[128];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    get_version(priv->adapter, buf, sizeof(buf) - 1);
+
+    len = strlen(buf);
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, buf, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = len;
+    }
+
+    PRINTM(INFO, "wlan version: %s\n", buf);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Driver and FW version
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_verext_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_VERSION_EXT versionExtCmd;
+    int len;
+
+    ENTER();
+
+    memset(&versionExtCmd, 0x00, sizeof(versionExtCmd));
+
+    if (wrq->u.data.flags == 0) {
+        //from iwpriv subcmd
+        versionExtCmd.versionStrSel =
+            *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    } else {
+        if (copy_from_user(&versionExtCmd.versionStrSel,
+                           wrq->u.data.pointer,
+                           sizeof(versionExtCmd.versionStrSel))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    wlan_prepare_cmd(priv,
+                     HostCmd_CMD_VERSION_EXT, 0,
+                     HostCmd_OPTION_WAITFORRSP, 0, &versionExtCmd);
+
+    len = strlen(versionExtCmd.versionStr) + 1;
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, versionExtCmd.versionStr, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = len;
+    }
+
+    PRINTM(INFO, "Version: %s\n", versionExtCmd.versionStr);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Read/Write adapter registers
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_regrdwr_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    wlan_ioctl_regrdwr regrdwr;
+    wlan_offset_value offval;
+    u8 *pRdeeprom;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (copy_from_user(&regrdwr, req->ifr_data, sizeof(regrdwr))) {
+        PRINTM(INFO,
+               "copy of regrdwr for wlan_regrdwr_ioctl from user failed \n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    if (regrdwr.WhichReg == REG_EEPROM) {
+        PRINTM(INFO, "Inside RDEEPROM\n");
+        pRdeeprom =
+            (char *) kmalloc((regrdwr.NOB + sizeof(regrdwr)), GFP_KERNEL);
+        if (!pRdeeprom) {
+            PRINTM(INFO, "allocate memory for EEPROM read failed\n");
+            LEAVE();
+            return -ENOMEM;
+        }
+        memcpy(pRdeeprom, &regrdwr, sizeof(regrdwr));
+        PRINTM(INFO, "Action: %d, Offset: %x, NOB: %02x\n",
+               regrdwr.Action, regrdwr.Offset, regrdwr.NOB);
+
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_EEPROM_ACCESS,
+                               regrdwr.Action, HostCmd_OPTION_WAITFORRSP,
+                               0, pRdeeprom);
+
+        /*
+         * Return the result back to the user 
+         */
+        if (!ret && regrdwr.Action == HostCmd_ACT_GEN_READ) {
+            if (copy_to_user
+                (req->ifr_data, pRdeeprom, sizeof(regrdwr) + regrdwr.NOB)) {
+                PRINTM(INFO,
+                       "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n");
+                ret = -EFAULT;
+            }
+        }
+
+        kfree(pRdeeprom);
+
+        LEAVE();
+        return ret;
+    }
+
+    offval.offset = regrdwr.Offset;
+    offval.value = (regrdwr.Action) ? regrdwr.Value : 0x00;
+
+    PRINTM(INFO, "RegAccess: %02x Action:%d "
+           "Offset: %04x Value: %04x\n",
+           regrdwr.WhichReg, regrdwr.Action, offval.offset, offval.value);
+
+    /*
+     * regrdwr.WhichReg should contain the command that
+     * corresponds to which register access is to be 
+     * performed HostCmd_CMD_MAC_REG_ACCESS 0x0019
+     * HostCmd_CMD_BBP_REG_ACCESS 0x001a 
+     * HostCmd_CMD_RF_REG_ACCESS 0x001b 
+     */
+    ret = wlan_prepare_cmd(priv, regrdwr.WhichReg,
+                           regrdwr.Action, HostCmd_OPTION_WAITFORRSP,
+                           0, &offval);
+
+    /*
+     * Return the result back to the user 
+     */
+    if (!ret && regrdwr.Action == HostCmd_ACT_GEN_READ) {
+        regrdwr.Value = offval.value;
+        if (copy_to_user(req->ifr_data, &regrdwr, sizeof(regrdwr))) {
+            PRINTM(INFO,
+                   "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n");
+            ret = -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Cmd52 read/write register
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_cmd52rdwr_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 buf[7];
+    u8 rw, func, dat = 0xff;
+    u32 reg;
+
+    ENTER();
+
+    if (copy_from_user(buf, req->ifr_data, sizeof(buf))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    rw = buf[0];
+    func = buf[1];
+    reg = buf[5];
+    reg = (reg << 8) + buf[4];
+    reg = (reg << 8) + buf[3];
+    reg = (reg << 8) + buf[2];
+
+    if (rw != 0)
+        dat = buf[6];
+
+    PRINTM(INFO, "rw=%d func=%d reg=0x%08X dat=0x%02X\n", rw, func, reg, dat);
+
+    if (rw == 0) {
+        if (sbi_read_ioreg(priv, reg, &dat) < 0) {
+            PRINTM(INFO, "sdio_read_ioreg: reading register 0x%X failed\n",
+                   reg);
+            dat = 0xff;
+        }
+    } else {
+        if (sbi_write_ioreg(priv, reg, dat) < 0) {
+            PRINTM(INFO, "sdio_read_ioreg: writing register 0x%X failed\n",
+                   reg);
+            dat = 0xff;
+        }
+    }
+    if (copy_to_user(req->ifr_data, &dat, sizeof(dat))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Cmd53 read/write register
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_cmd53rdwr_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 buf[11];
+    u8 rw, func, mode;
+    u16 blklen = 0, blknum = 0;
+    u32 reg = 0;
+    u8 data[CMD53BUFLEN];
+
+    ENTER();
+
+    if (copy_from_user(buf, req->ifr_data, sizeof(buf))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        return -EFAULT;
+    }
+
+    rw = buf[0];                // read/write (0/1)
+    func = buf[1];              // func (0/1/2)
+    reg = buf[5];               // address
+    reg = (reg << 8) + buf[4];
+    reg = (reg << 8) + buf[3];
+    reg = (reg << 8) + buf[2];
+    mode = buf[6];              // byte mode/block mode (0/1)
+    blklen = buf[8];            // block size
+    blklen = (blklen << 8) + buf[7];
+    blknum = buf[10];           // block number or byte number
+    blknum = (blknum << 8) + buf[9];
+
+    PRINTM(INFO, "CMD53 read, func = %d, addr = %#x, mode = %d, "
+           "block size = %d, block(byte) number = %d\n",
+           func, reg, mode, blklen, blknum);
+
+    if (rw == 0) {
+	/* modified by feng */
+        //if (sdio_read_iomem(priv->wlan_dev.card, func, reg, mode,
+        //                   FIXED_ADDRESS, blknum, blklen, data) < 0) {
+        if (sbi_read_iomem(priv, data, reg, blknum * blklen) < 0) { 
+		PRINTM(ERROR, "sbi_read_iomem: reading memory 0x%x failed\n",
+			reg);
+        }
+    }
+
+    if (copy_to_user(req->ifr_data, data, sizeof(data))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief crypto test
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_crypto_test(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    u8 *buf = NULL;
+    HostCmd_DS_802_11_CRYPTO *cmd = NULL;
+    MrvlIEtypes_Data_t *data;
+    u16 len = 0;
+
+    ENTER();
+
+#define CRYPTO_TEST_BUF_LEN	1024
+    if (!(buf = kmalloc(CRYPTO_TEST_BUF_LEN, GFP_KERNEL))) {
+        PRINTM(INFO, "kmalloc failed!\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+    memset(buf, 0, CRYPTO_TEST_BUF_LEN);
+    cmd = (HostCmd_DS_802_11_CRYPTO *) buf;
+
+    if (wrq->u.data.length < CRYPTO_TEST_BUF_LEN) {
+        if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+            goto crypto_exit;
+        }
+    }
+
+    data = (MrvlIEtypes_Data_t *) (buf + sizeof(HostCmd_DS_802_11_CRYPTO));
+    HEXDUMP("crypton", (u8 *) cmd, wrq->u.data.length);
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_CRYPTO,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, 0, cmd);
+    len = data->Header.Len;
+    wrq->u.data.length =
+        sizeof(HostCmd_DS_802_11_CRYPTO) + sizeof(MrvlIEtypesHeader_t) + len;
+    if (copy_to_user
+        (wrq->u.data.pointer, cmd,
+         sizeof(HostCmd_DS_802_11_CRYPTO) + sizeof(MrvlIEtypesHeader_t) +
+         len)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        ret = -EFAULT;
+    }
+
+  crypto_exit:
+    kfree(buf);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Convert ascii string to Hex integer
+ *     
+ *  @param d                    A pointer to integer buf
+ *  @param s			A pointer to ascii string 
+ *  @param dlen			the length o fascii string
+ *  @return 	   	        number of integer  
+ */
+static int
+ascii2hex(u8 * d, char *s, u32 dlen)
+{
+    int i;
+    u8 n;
+
+    ENTER();
+
+    memset(d, 0x00, dlen);
+
+    for (i = 0; i < dlen * 2; i++) {
+        if ((s[i] >= 48) && (s[i] <= 57))
+            n = s[i] - 48;
+        else if ((s[i] >= 65) && (s[i] <= 70))
+            n = s[i] - 55;
+        else if ((s[i] >= 97) && (s[i] <= 102))
+            n = s[i] - 87;
+        else
+            break;
+        if ((i % 2) == 0)
+            n = n * 16;
+        d[i / 2] += n;
+    }
+
+    LEAVE();
+
+    return i;
+}
+
+/** 
+ *  @brief Set adhoc aes key
+ *   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setadhocaes_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 key_ascii[32];
+    u8 key_hex[16];
+    int ret = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    WLAN_802_11_KEY key;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS) {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+    if (copy_from_user(key_ascii, wrq->u.data.pointer, sizeof(key_ascii))) {
+        PRINTM(INFO, "wlan_setadhocaes_ioctl copy from user failed \n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    Adapter->AdhocAESEnabled = TRUE;
+    ascii2hex(key_hex, key_ascii, sizeof(key_hex));
+
+    HEXDUMP("wlan_setadhocaes_ioctl", key_hex, sizeof(key_hex));
+
+    PRINTM(INFO, "WPA2: ENABLE AES_KEY\n");
+    key.KeyLength = WPA_AES_KEY_LEN;
+    key.KeyIndex = 0x40000000;
+    memcpy(key.KeyMaterial, key_hex, key.KeyLength);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_KEY_MATERIAL,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, KEY_INFO_ENABLED, &key);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get adhoc aes key   
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_getadhocaes_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    u8 *tmp;
+    u8 key_ascii[33];
+    u8 key_hex[16];
+    int i, ret = 0;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+    WLAN_802_11_KEY key;
+
+    ENTER();
+
+    memset(key_hex, 0x00, sizeof(key_hex));
+
+    PRINTM(INFO, "WPA2: ENABLE AES_KEY\n");
+    key.KeyLength = WPA_AES_KEY_LEN;
+    key.KeyIndex = 0x40000000;
+    memcpy(key.KeyMaterial, key_hex, key.KeyLength);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_KEY_MATERIAL,
+                           HostCmd_ACT_GEN_GET,
+                           HostCmd_OPTION_WAITFORRSP, KEY_INFO_ENABLED, &key);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    memcpy(key_hex, Adapter->aeskey.KeyParamSet.Key, sizeof(key_hex));
+
+    HEXDUMP("wlan_getadhocaes_ioctl", key_hex, sizeof(key_hex));
+
+    wrq->u.data.length = sizeof(key_ascii) + 1;
+
+    memset(key_ascii, 0x00, sizeof(key_ascii));
+    tmp = key_ascii;
+
+    for (i = 0; i < sizeof(key_hex); i++)
+        tmp += sprintf(tmp, "%02x", key_hex[i]);
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &key_ascii, sizeof(key_ascii))) {
+            PRINTM(INFO, "copy_to_user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set multiple dtim
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    struct iwreq *wrq = (struct iwreq *) req;
+    u32 mdtim;
+    int idata;
+    int ret = -EINVAL;
+
+    ENTER();
+
+    idata = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    mdtim = (u32) idata;
+    if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) &&
+         (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+        || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+        priv->adapter->MultipleDtim = mdtim;
+        ret = WLAN_STATUS_SUCCESS;
+    }
+    if (ret)
+        PRINTM(INFO, "Invalid parameter, MultipleDtim not changed.\n");
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int alg;
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wrq->u.data.flags == 0) {
+        //from iwpriv subcmd
+        alg = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    } else {
+        //from wpa_supplicant subcmd
+        if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    PRINTM(INFO, "auth alg is %#x\n", alg);
+
+    switch (alg) {
+    case AUTH_ALG_SHARED_KEY:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared;
+        break;
+    case AUTH_ALG_NETWORK_EAP:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeNetworkEAP;
+        break;
+    case AUTH_ALG_OPEN_SYSTEM:
+    default:
+        Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+        break;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Encryption mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int mode;
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    if (wrq->u.data.flags == 0) {
+        //from iwpriv subcmd
+        mode = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    } else {
+        //from wpa_supplicant subcmd
+        if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+    PRINTM(INFO, "encryption mode is %#x\n", mode);
+    priv->adapter->SecInfo.EncryptionMode = mode;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Rx antenna
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int len;
+    char buf[8];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    PRINTM(INFO, "WLAN_SUBCMD_GETRXANTENNA\n");
+    len = wlan_get_rx_antenna(priv, buf);
+
+    wrq->u.data.length = len;
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get Tx antenna
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int len;
+    char buf[8];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    PRINTM(INFO, "WLAN_SUBCMD_GETTXANTENNA\n");
+    len = wlan_get_tx_antenna(priv, buf);
+
+    wrq->u.data.length = len;
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+            PRINTM(INFO, "CopyToUser failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get the MAC TSF value from the firmware
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure containing buffer
+ *                      space to store a TSF value retrieved from the firmware
+ *
+ *  @return             0 if successful; IOCTL error code otherwise
+ */
+static int
+wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    u64 tsfVal = 0;
+    int ret;
+
+    ENTER();
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_GET_TSF,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, &tsfVal);
+
+    PRINTM(INFO, "IOCTL: Get TSF = 0x%016llx\n", tsfVal);
+
+    if (ret != WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "IOCTL: Get TSF; Command exec failed\n");
+        ret = -EFAULT;
+    } else {
+        if (copy_to_user(wrq->u.data.pointer,
+                         &tsfVal,
+                         MIN(wrq->u.data.length, sizeof(tsfVal))) != 0) {
+
+            PRINTM(INFO, "IOCTL: Get TSF; Copy to user failed\n");
+            ret = -EFAULT;
+        } else {
+            ret = 0;
+        }
+    }
+
+    LEAVE();
+
+    return ret;
+}
+
+/** 
+ *  @brief  Control WPS Session Enable/Disable
+ *  @param priv         A pointer to wlan_private structure
+ *  @param req          A pointer to ifreq structure
+ *  @return             WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_wps_session_ioctl(wlan_private * priv, struct iwreq *req)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    char buf[8];
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    PRINTM(INFO, "WLAN_WPS_SESSION\n");
+
+    memset(buf, 0, sizeof(buf));
+    if (copy_from_user(buf, wrq->u.data.pointer,
+                       MIN(sizeof(buf) - 1, wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    if (buf[0] == 1)
+        Adapter->wps.SessionEnable = TRUE;
+    else
+        Adapter->wps.SessionEnable = FALSE;
+
+    PRINTM(INFO, "Adapter->wps.SessionEnable = %d\n",
+           Adapter->wps.SessionEnable);
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set DeepSleep mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_deepsleep_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    char status[128];
+    struct iwreq *wrq = (struct iwreq *) req;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        PRINTM(MSG, "Cannot enter Deep Sleep mode in connected state.\n");
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (*(char *) req->ifr_data == '0') {
+        PRINTM(INFO, "Exit Deep Sleep Mode.\n");
+        sprintf(status, "setting to off ");
+        wlan_set_deep_sleep(priv, FALSE);
+    } else if (*(char *) req->ifr_data == '1') {
+        PRINTM(INFO, "Enter Deep Sleep Mode.\n");
+        sprintf(status, "setting to on ");
+        wlan_set_deep_sleep(priv, TRUE);
+    } else if (*(char *) req->ifr_data == '2') {
+        PRINTM(INFO, "Get Deep Sleep Mode.\n");
+        if (Adapter->IsDeepSleep == TRUE) {
+            sprintf(status, "on ");
+        } else {
+            sprintf(status, "off ");
+        }
+    } else {
+        PRINTM(INFO, "unknown option = %d\n", *(u8 *) req->ifr_data);
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &status, strlen(status))) {
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = strlen(status);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Config Host Sleep parameters
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_hscfg_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[3] = { -1, 0xff, 0xff };
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length >= 1 && wrq->u.data.length <= 3) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        PRINTM(INFO,
+               "wlan_hscfg_ioctl: data[0]=%#08x, data[1]=%#02x, data[2]=%#02x\n",
+               data[0], data[1], data[2]);
+    } else {
+        PRINTM(MSG, "Invalid Argument\n");
+        LEAVE();
+        return -EINVAL;
+    }
+
+    Adapter->HSCfg.conditions = data[0];
+    if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
+        if (wrq->u.data.length == 2) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+        } else if (wrq->u.data.length == 3) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+            Adapter->HSCfg.gap = (u8) data[2];
+        }
+    }
+
+    PRINTM(INFO,
+           "hscfg: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
+           Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
+           Adapter->PSState, Adapter->HS_Activated);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_HOST_SLEEP_CFG,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, &Adapter->HSCfg);
+
+    data[0] = Adapter->HSCfg.conditions;
+    data[1] = Adapter->HSCfg.gpio;
+    data[2] = Adapter->HSCfg.gap;
+    wrq->u.data.length = 3;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set Host Sleep parameters
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_hssetpara_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data[3] = { -1, 0xff, 0xff };
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length >= 1 && wrq->u.data.length <= 3) {
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        PRINTM(INFO,
+               "wlan_hssetpara_ioctl: data[0]=%#08x, data[1]=%#02x, data[2]=%#02x\n",
+               data[0], data[1], data[2]);
+    }
+
+    Adapter->HSCfg.conditions = data[0];
+    if (Adapter->HSCfg.conditions != HOST_SLEEP_CFG_CANCEL) {
+        if (wrq->u.data.length == 2) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+        } else if (wrq->u.data.length == 3) {
+            Adapter->HSCfg.gpio = (u8) data[1];
+            Adapter->HSCfg.gap = (u8) data[2];
+        }
+    }
+
+    PRINTM(INFO,
+           "hssetpara: cond=%#x gpio=%#x gap=%#x PSState=%d HS_Activated=%d\n",
+           Adapter->HSCfg.conditions, Adapter->HSCfg.gpio, Adapter->HSCfg.gap,
+           Adapter->PSState, Adapter->HS_Activated);
+
+    data[0] = Adapter->HSCfg.conditions;
+    data[1] = Adapter->HSCfg.gpio;
+    data[2] = Adapter->HSCfg.gap;
+    wrq->u.data.length = 3;
+    if (copy_to_user
+        (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** Destination host */
+#define DESTINATION_HOST	0x01
+/** 
+ *  @brief Config Small Debug parameters
+ *   
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wreq		A pointer to iwreq structure
+ *  @return    		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_dbgs_cfg(wlan_private * priv, struct iwreq *wrq)
+{
+    int *data = NULL;
+    u8 buf[512];
+    DBGS_CFG_DATA *pDbgCfg = (DBGS_CFG_DATA *) buf;
+    DBGS_ENTRY_DATA *pEntry;
+    int ret = WLAN_STATUS_SUCCESS;
+    int i;
+
+    ENTER();
+
+#define MAX_DBGS_CFG_ENTRIES	0x7F
+    if (wrq->u.data.length < 3 ||
+        wrq->u.data.length > 3 + MAX_DBGS_CFG_ENTRIES * 2) {
+        PRINTM(MSG, "Invalid parameter number\n");
+        ret = -EFAULT;
+        goto dbgs_exit;
+    }
+
+    if (!(data = kmalloc(sizeof(int) * wrq->u.data.length, GFP_KERNEL))) {
+        PRINTM(INFO, "Allocate memory failed\n");
+        ret = -ENOMEM;
+        goto dbgs_exit;
+    }
+    memset(data, 0, sizeof(int) * wrq->u.data.length);
+    memset(buf, 0, sizeof(buf));
+
+    if (copy_from_user
+        (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        ret = -EFAULT;
+        goto dbgs_exit;
+    }
+    if (wrq->u.data.length < (3 + (data[2] & 0x7f) * 2)) {
+        PRINTM(MSG, "Invalid parameter number\n");
+        ret = -EFAULT;
+        goto dbgs_exit;
+    }
+
+    pDbgCfg->data.Destination = (u8) data[0];
+#ifdef	DEBUG_LEVEL1
+    if (pDbgCfg->data.Destination & DESTINATION_HOST)
+        drvdbg |= DBG_FW_D;
+    else
+        drvdbg &= ~DBG_FW_D;
+#endif
+    pDbgCfg->data.ToAirChan = (u8) data[1];
+    pDbgCfg->data.En_NumEntries = (u8) data[2];
+    pDbgCfg->size =
+        sizeof(HostCmd_DS_DBGS_CFG) +
+        (pDbgCfg->data.En_NumEntries & 0x7f) * sizeof(DBGS_ENTRY_DATA);
+    pEntry = (DBGS_ENTRY_DATA *) (buf + sizeof(DBGS_CFG_DATA));
+    for (i = 0; i < (pDbgCfg->data.En_NumEntries & 0x7f); i++) {
+        pEntry->ModeAndMaskorID = (u16) data[3 + i * 2];
+        pEntry->BaseOrID = (u16) data[3 + i * 2 + 1];
+        pEntry->ModeAndMaskorID = wlan_cpu_to_le16(pEntry->ModeAndMaskorID);
+        pEntry->BaseOrID = wlan_cpu_to_le16(pEntry->BaseOrID);
+        pEntry++;
+    }
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_DBGS_CFG,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, pDbgCfg);
+
+  dbgs_exit:
+    if (data)
+        kfree(data);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set Cal data ext
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_caldata_ext_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    HostCmd_DS_802_11_CAL_DATA_EXT *pCalData = NULL;
+    int ret = WLAN_STATUS_SUCCESS;
+    u16 action;
+
+    ENTER();
+
+    if (!(pCalData = kmalloc(MAX_SETGET_CONF_CMD_LEN, GFP_KERNEL))) {
+        PRINTM(INFO, "Allocate memory failed\n");
+        ret = -ENOMEM;
+        goto calexit;
+    }
+    memset(pCalData, 0, MAX_SETGET_CONF_CMD_LEN);
+
+    if (copy_from_user(pCalData, req->ifr_data + SKIP_CMDNUM,
+                       MAX_SETGET_CONF_CMD_LEN)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(pCalData);
+        ret = -EFAULT;
+        goto calexit;
+    }
+
+    action = (pCalData->Action == HostCmd_ACT_GEN_SET) ?
+        HostCmd_ACT_GEN_SET : HostCmd_ACT_GEN_GET;
+
+    HEXDUMP("Cal data ext", (u8 *) pCalData, MAX_SETGET_CONF_CMD_LEN);
+
+    PRINTM(INFO, "CalData Action = 0x%0X\n", action);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_CAL_DATA_EXT,
+                           action, HostCmd_OPTION_WAITFORRSP, 0, pCalData);
+
+    if (!ret && action == HostCmd_ACT_GEN_GET) {
+        if (copy_to_user(req->ifr_data + SKIP_CMDNUM, pCalData,
+                         MAX_SETGET_CONF_CMD_LEN)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+    }
+
+    kfree(pCalData);
+  calexit:
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set band 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_do_setband_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int cnt, i;
+    char buf[16];
+    u16 tmp = 0;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+    memset(buf, '\0', sizeof(buf));
+    if (copy_from_user(buf, wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(buf) - 1))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    cnt = strlen(buf);
+
+    if (!cnt || cnt > 3) {
+        LEAVE();
+        return -EINVAL;
+    }
+    for (i = 0; i < cnt; i++) {
+        switch (buf[i]) {
+        case 'B':
+        case 'b':
+            PRINTM(INFO, "setband: BAND B\n");
+            tmp |= BAND_B;
+            break;
+        case 'G':
+        case 'g':
+            PRINTM(INFO, "setband: BAND G\n");
+            tmp |= BAND_G;
+            break;
+        case 'A':
+        case 'a':
+            PRINTM(INFO, "setband: BAND A\n");
+            tmp |= BAND_A;
+            break;
+        default:
+            PRINTM(INFO, "setband: Invalid %02x(%c)\n", buf[i], buf[i]);
+            LEAVE();
+            return -EINVAL;
+        }
+    }
+
+    PRINTM(INFO, "setband: sel=%02x, fw=%02x\n", tmp, Adapter->fw_bands);
+
+    /* Validate against FW support */
+    if ((tmp | Adapter->fw_bands) & ~Adapter->fw_bands) {
+        LEAVE();
+        return -EINVAL;
+    }
+    /* To support only <a/b/bg/abg> */
+    if (!tmp || (tmp == BAND_G) || (tmp == (BAND_A | BAND_B)) ||
+        (tmp == (BAND_A | BAND_G))) {
+        LEAVE();
+        return -EINVAL;
+    }
+    if (wlan_set_regiontable(priv, Adapter->RegionCode, tmp)) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    Adapter->config_bands = tmp;
+
+    if (Adapter->config_bands & BAND_A) {
+        Adapter->adhoc_start_band = BAND_A;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL_A;
+    } else if (Adapter->config_bands & BAND_G) {
+        Adapter->adhoc_start_band = BAND_G;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+    } else {
+        Adapter->adhoc_start_band = BAND_B;
+        Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL;
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set adhoc channel 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_setadhocch_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    /* iwpriv ethX setaddocchannel "a nnn" */
+    u32 vals[2];
+    u16 band;
+    u8 chan;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS) {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+    if (copy_from_user(vals, wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(vals)))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+
+    }
+    switch (vals[0]) {          /* 1st byte is band */
+    case 'B':
+    case 'b':
+        band = BAND_B;
+        break;
+    case 'G':
+    case 'g':
+        band = BAND_G;
+        break;
+    case 'A':
+    case 'a':
+        band = BAND_A;
+        break;
+    default:
+        LEAVE();
+        return -EINVAL;
+    }
+
+    /* Validate against FW support */
+    if ((band | Adapter->fw_bands) & ~Adapter->fw_bands) {
+        LEAVE();
+        return -EINVAL;
+    }
+    chan = vals[1];
+
+    if (!find_cfp_by_band_and_channel(Adapter, band, (u16) chan)) {
+        PRINTM(INFO, "Invalid channel number %d\n", chan);
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (wlan_change_adhoc_chan(priv, chan) != WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "Fail to change adhoc channel number %d\n", chan);
+        LEAVE();
+        return -EINVAL;
+    }
+    Adapter->adhoc_start_band = band;
+    Adapter->AdhocChannel = chan;
+    Adapter->AdhocAutoSel = FALSE;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get band 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_get_band_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    char status[10], *ptr;
+    u16 val = priv->adapter->config_bands;
+
+    ENTER();
+
+    memset(status, 0, sizeof(status));
+    ptr = status;
+
+    if (val & BAND_A)
+        *ptr++ = 'a';
+
+    if (val & BAND_B)
+        *ptr++ = 'b';
+
+    if (val & BAND_G)
+        *ptr++ = 'g';
+
+    *ptr = '\0';
+
+    PRINTM(INFO, "Status = %s\n", status);
+    wrq->u.data.length = strlen(status) + 1;
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, &status, wrq->u.data.length)) {
+            LEAVE();
+            return -EFAULT;
+        }
+    }
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get adhoc channel 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_get_adhocch_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    u32 status[2];
+    wlan_adapter *Adapter = priv->adapter;
+    u16 band = Adapter->adhoc_start_band;
+
+    ENTER();
+
+    if (band & BAND_A) {
+        status[0] = 'a';
+    } else if (band & BAND_B) {
+        status[0] = 'b';
+    } else if (band & BAND_G) {
+        status[0] = 'g';
+    }
+
+    status[1] = Adapter->AdhocChannel;
+
+    if (wrq->u.data.pointer) {
+        wrq->u.data.length = sizeof(status);
+
+        if (copy_to_user(wrq->u.data.pointer, status, wrq->u.data.length))
+            return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set sleep period 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_sleep_period(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    int data;
+    wlan_adapter *Adapter = priv->adapter;
+    HostCmd_DS_802_11_SLEEP_PERIOD sleeppd;
+
+    ENTER();
+
+    if (wrq->u.data.length > 1) {
+        LEAVE();
+        return -ENOTSUPP;
+    }
+    memset(&sleeppd, 0, sizeof(sleeppd));
+    memset(&Adapter->sleep_period, 0, sizeof(SleepPeriod));
+
+    if (wrq->u.data.length == 0) {
+        sleeppd.Action = HostCmd_ACT_GEN_GET;
+    } else {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        /* sleep period is 0 or 10~60 in milliseconds */
+#define MIN_SLEEP_PERIOD		10
+#define MAX_SLEEP_PERIOD		60
+#define SLEEP_PERIOD_RESERVED_FF	0xFF
+        if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) ||
+            (data == 0)
+            || (data == SLEEP_PERIOD_RESERVED_FF)       /* for UPSD certification tests */
+            ) {
+            sleeppd.Action = HostCmd_ACT_GEN_SET;
+            sleeppd.Period = data;
+        } else {
+            LEAVE();
+            return -EINVAL;
+        }
+    }
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SLEEP_PERIOD,
+                           0, HostCmd_OPTION_WAITFORRSP,
+                           0, (void *) &sleeppd);
+
+    data = (int) Adapter->sleep_period.period;
+    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set adapt rate 
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    int data[4];
+    int rateindex;
+
+    ENTER();
+    memset(data, 0, sizeof(data));
+    if (!wrq->u.data.length) {
+        PRINTM(INFO, "Get ADAPT RATE SET\n");
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                               HostCmd_ACT_GEN_GET, HostCmd_OPTION_WAITFORRSP,
+                               0, NULL);
+        data[0] = Adapter->HWRateDropMode;
+        data[2] = Adapter->Threshold;
+        data[3] = Adapter->FinalRate;
+        wrq->u.data.length = 4;
+        data[1] = Adapter->RateBitmap;
+        if (copy_to_user
+            (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+    } else {
+        PRINTM(INFO, "Set ADAPT RATE SET\n");
+        if (wrq->u.data.length > 4) {
+            LEAVE();
+            return -EINVAL;
+        }
+        if (copy_from_user
+            (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
+            LEAVE();
+            PRINTM(INFO, "Copy from user failed\n");
+            return -EFAULT;
+        }
+
+        if (data[0] > HW_SINGLE_RATE_DROP) {
+            LEAVE();
+            return -EINVAL;
+        }
+        Adapter->HWRateDropMode = data[0];
+        Adapter->Threshold = data[2];
+        Adapter->FinalRate = data[3];
+        Adapter->RateBitmap = data[1];
+        Adapter->Is_DataRate_Auto = wlan_is_rate_auto(priv);
+        if (Adapter->Is_DataRate_Auto)
+            Adapter->DataRate = 0;
+        else {
+            rateindex = wlan_get_rate_index(priv);
+            Adapter->DataRate = index_to_data_rate(rateindex);
+        }
+        PRINTM(INFO, "RateBitmap=%x,IsRateAuto=%d,DataRate=%d\n",
+               Adapter->RateBitmap, Adapter->Is_DataRate_Auto,
+               Adapter->DataRate);
+        ret =
+            wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                             HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP,
+                             0, NULL);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set inactivity timeout
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    int data = 0;
+    u16 timeout = 0;
+
+    ENTER();
+    if (wrq->u.data.length > 1) {
+        LEAVE();
+        return -ENOTSUPP;
+    }
+    if (wrq->u.data.length == 0) {
+        /* Get */
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_INACTIVITY_TIMEOUT,
+                               HostCmd_ACT_GEN_GET, HostCmd_OPTION_WAITFORRSP,
+                               0, &timeout);
+        data = timeout;
+        if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+    } else {
+        /* Set */
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        timeout = data;
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_INACTIVITY_TIMEOUT,
+                               HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP,
+                               0, &timeout);
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get LOG
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    char *buf = NULL;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    PRINTM(INFO, " GET STATS\n");
+
+    if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL))) {
+        PRINTM(INFO, "kmalloc failed!\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG,
+                           0, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (!ret && wrq->u.data.pointer) {
+        sprintf(buf, "\n"
+                "mcasttxframe     %u\n"
+                "failed           %u\n"
+                "retry            %u\n"
+                "multiretry       %u\n"
+                "framedup         %u\n"
+                "rtssuccess       %u\n"
+                "rtsfailure       %u\n"
+                "ackfailure       %u\n"
+                "rxfrag           %u\n"
+                "mcastrxframe     %u\n"
+                "fcserror         %u\n"
+                "txframe          %u\n",
+                Adapter->LogMsg.mcasttxframe,
+                Adapter->LogMsg.failed,
+                Adapter->LogMsg.retry,
+                Adapter->LogMsg.multiretry,
+                Adapter->LogMsg.framedup,
+                Adapter->LogMsg.rtssuccess,
+                Adapter->LogMsg.rtsfailure,
+                Adapter->LogMsg.ackfailure,
+                Adapter->LogMsg.rxfrag,
+                Adapter->LogMsg.mcastrxframe,
+                Adapter->LogMsg.fcserror, Adapter->LogMsg.txframe);
+        wrq->u.data.length = strlen(buf) + 1;
+        if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+    }
+
+    kfree(buf);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief config sleep parameters
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_sleep_params_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_sleep_params_config sp;
+
+    ENTER();
+
+    memset(&sp, 0, sizeof(sp));
+
+    if (!wrq->u.data.pointer) {
+        LEAVE();
+        return -EFAULT;
+    }
+    if (copy_from_user(&sp, wrq->u.data.pointer,
+                       MIN(sizeof(sp), wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    memcpy(&Adapter->sp, &sp.Error, sizeof(SleepParams));
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SLEEP_PARAMS,
+                           sp.Action, HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+    if (!ret && !sp.Action) {
+        memcpy(&sp.Error, &Adapter->sp, sizeof(SleepParams));
+        if (copy_to_user(wrq->u.data.pointer, &sp, sizeof(sp))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = sizeof(sp);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Read the CIS Table
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_do_getcis_ioctl(wlan_private * priv, struct ifreq *req)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    struct iwreq *wrq = (struct iwreq *) req;
+    char *cisinfo;
+#define MAX_CIS_INFO_LEN (512)
+    int cislen = MAX_CIS_INFO_LEN;
+
+    ENTER();
+
+    cisinfo = (char *) kmalloc(cislen, GFP_KERNEL);
+    if (!cisinfo) {
+        PRINTM(ERROR, "Memory allocation for cisinfo failed!\n");
+        ret = WLAN_STATUS_FAILURE;
+        goto done;
+    }
+
+    memset(cisinfo, 0, cislen);
+    ret = sbi_get_cis_info(priv, (void *) cisinfo, &cislen);
+    if (ret != WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "Failed to get CIS information from card\n");
+        ret = -EFAULT;
+        goto done;
+    }
+
+    if (wrq->u.data.pointer) {
+        if (copy_to_user(wrq->u.data.pointer, cisinfo, cislen)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+            goto done;
+        }
+        wrq->u.data.length = cislen;
+    }
+
+  done:
+    if (cisinfo)
+        kfree(cisinfo);
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set BCA timeshare
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_bca_timeshare_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int ret;
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_bca_timeshare_config bca_ts;
+
+    ENTER();
+
+    memset(&bca_ts, 0, sizeof(HostCmd_DS_802_11_BCA_TIMESHARE));
+
+    if (!wrq->u.data.pointer) {
+        LEAVE();
+        return -EFAULT;
+    }
+    if (copy_from_user(&bca_ts, wrq->u.data.pointer,
+                       MIN(sizeof(bca_ts), wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    PRINTM(INFO, "TrafficType=%x TimeShareInterva=%x BTTime=%x\n",
+           bca_ts.TrafficType, bca_ts.TimeShareInterval, bca_ts.BTTime);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_BCA_CONFIG_TIMESHARE,
+                           bca_ts.Action, HostCmd_OPTION_WAITFORRSP,
+                           0, &bca_ts);
+
+    if (!ret && !bca_ts.Action) {
+        if (copy_to_user(wrq->u.data.pointer, &Adapter->bca_ts,
+                         sizeof(bca_ts))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = sizeof(HostCmd_DS_802_11_BCA_TIMESHARE);
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set scan type
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    u8 buf[12];
+    u8 *option[] = { "active", "passive", "get", };
+    int i, max_options = (sizeof(option) / sizeof(option[0]));
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (wlan_get_state_11d(priv) == ENABLE_11D) {
+        PRINTM(INFO, "11D: Cannot set scantype when 11D enabled\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    memset(buf, 0, sizeof(buf));
+
+    if (copy_from_user(buf, wrq->u.data.pointer, MIN(sizeof(buf),
+                                                     wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    PRINTM(INFO, "Scan Type Option = %s\n", buf);
+
+    buf[sizeof(buf) - 1] = '\0';
+
+    for (i = 0; i < max_options; i++) {
+        if (!strcmp(buf, option[i]))
+            break;
+    }
+
+    switch (i) {
+    case 0:
+        Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE;
+        break;
+    case 1:
+        Adapter->ScanType = HostCmd_SCAN_TYPE_PASSIVE;
+        break;
+    case 2:
+        wrq->u.data.length = strlen(option[Adapter->ScanType]) + 1;
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         option[Adapter->ScanType], wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+
+        break;
+    default:
+        PRINTM(INFO, "Invalid Scan Type Ioctl Option\n");
+        ret = -EINVAL;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Set scan mode
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u8 buf[12];
+    u8 *option[] = { "bss", "ibss", "any", "get" };
+    int i, max_options = (sizeof(option) / sizeof(option[0]));
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    memset(buf, 0, sizeof(buf));
+
+    if (copy_from_user(buf, wrq->u.data.pointer, MIN(sizeof(buf),
+                                                     wrq->u.data.length))) {
+        PRINTM(INFO, "Copy from user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    PRINTM(INFO, "Scan Mode Option = %s\n", buf);
+
+    buf[sizeof(buf) - 1] = '\0';
+
+    for (i = 0; i < max_options; i++) {
+        if (!strcmp(buf, option[i]))
+            break;
+    }
+
+    switch (i) {
+
+    case 0:
+        Adapter->ScanMode = HostCmd_BSS_TYPE_BSS;
+        break;
+    case 1:
+        Adapter->ScanMode = HostCmd_BSS_TYPE_IBSS;
+        break;
+    case 2:
+        Adapter->ScanMode = HostCmd_BSS_TYPE_ANY;
+        break;
+    case 3:
+
+        wrq->u.data.length = strlen(option[Adapter->ScanMode - 1]) + 1;
+
+        PRINTM(INFO, "Get Scan Mode Option = %s\n",
+               option[Adapter->ScanMode - 1]);
+
+        PRINTM(INFO, "Scan Mode Length %d\n", wrq->u.data.length);
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         option[Adapter->ScanMode - 1], wrq->u.data.length)) {
+            PRINTM(INFO, "Copy to user failed\n");
+            ret = -EFAULT;
+        }
+        PRINTM(INFO, "GET Scan Type Option after copy = %s\n",
+               (char *) wrq->u.data.pointer);
+
+        break;
+
+    default:
+        PRINTM(INFO, "Invalid Scan Mode Ioctl Option\n");
+        ret = -EINVAL;
+        break;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set Adhoc G Rate
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data, data1;
+    int *val;
+
+    ENTER();
+
+    data1 = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+    switch (data1) {
+    case 0:
+        Adapter->adhoc_grate_enabled = FALSE;
+        break;
+    case 1:
+        Adapter->adhoc_grate_enabled = TRUE;
+        break;
+    case 2:
+        break;
+    default:
+        LEAVE();
+        return -EINVAL;
+    }
+    data = Adapter->adhoc_grate_enabled;
+    val = (int *) wrq->u.name;
+    *val = data;
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Firmware wakeup method
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_cmd_fw_wakeup_method(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u16 action;
+    u16 method;
+    int ret;
+    int data;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
+        action = HostCmd_ACT_GEN_GET;
+        method = Adapter->fwWakeupMethod;
+    } else {
+        action = HostCmd_ACT_GEN_SET;
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        switch (data) {
+        case 0:
+            method = WAKEUP_FW_UNCHANGED;
+            break;
+        case 1:
+            method = WAKEUP_FW_THRU_INTERFACE;
+            break;
+        case 2:
+            method = WAKEUP_FW_THRU_GPIO;
+            break;
+        default:
+            LEAVE();
+            return -EINVAL;
+        }
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_FW_WAKE_METHOD, action,
+                           HostCmd_OPTION_WAITFORRSP, 0, &method);
+
+    if (action == HostCmd_ACT_GEN_GET) {
+        method = Adapter->fwWakeupMethod;
+        if (copy_to_user(wrq->u.data.pointer, &method, sizeof(method))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+        wrq->u.data.length = 1;
+    }
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get/Set Auto Deep Sleep mode
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_auto_deep_sleep(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0 && wrq->u.data.pointer) {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        switch (data) {
+        case 0:
+            if (Adapter->IsAutoDeepSleepEnabled) {
+                Adapter->IsAutoDeepSleepEnabled = FALSE;
+                /* Try to exit DS if auto DS disabled */
+                wlan_set_deep_sleep(priv, FALSE);
+            }
+            break;
+        case 1:
+            if (!Adapter->IsAutoDeepSleepEnabled) {
+                Adapter->IsAutoDeepSleepEnabled = TRUE;
+                /* Wakeup main thread to enter DS if auto DS enabled */
+                wake_up_interruptible(&priv->MainThread.waitQ);
+            }
+            break;
+        default:
+            LEAVE();
+            return -EINVAL;
+        }
+    }
+
+    data = Adapter->IsAutoDeepSleepEnabled;
+    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get/Set Enhanced PS mode
+ *  
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+static int
+wlan_enhanced_ps(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int data;
+
+    ENTER();
+
+    if (wrq->u.data.length > 0 && wrq->u.data.pointer) {
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            LEAVE();
+            return -EFAULT;
+        }
+
+        switch (data) {
+        case 0:
+            Adapter->IsEnhancedPSEnabled = FALSE;
+            break;
+        case 1:
+            Adapter->IsEnhancedPSEnabled = TRUE;
+            break;
+        default:
+            LEAVE();
+            return -EINVAL;
+        }
+    }
+
+    data = Adapter->IsEnhancedPSEnabled;
+    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(data))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Set MEF cfg 
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to iwreq structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_mef_cfg(wlan_private * priv, struct iwreq *wrq)
+{
+    u8 *tempResponseBuffer = NULL;
+    MEF_CFG_DATA *pMefData = NULL;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if ((wrq->u.data.pointer == NULL) ||
+        (wrq->u.data.length < sizeof(HostCmd_DS_MEF_CFG))) {
+        PRINTM(INFO, "wlan_set_mef_cfg corrupt data: pointer=%p, length=%d\n",
+               wrq->u.data.pointer, wrq->u.data.length);
+        LEAVE();
+        return -EFAULT;
+    }
+    if (!
+        (tempResponseBuffer =
+         kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
+        PRINTM(INFO, "ERROR: Failed to allocate response buffer!\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+    pMefData = (MEF_CFG_DATA *) tempResponseBuffer;
+
+    /*
+     * Copy the whole command into the command buffer 
+     */
+    if (copy_from_user
+        ((u8 *) & pMefData->data, wrq->u.data.pointer, wrq->u.data.length)) {
+        PRINTM(INFO, "Copy from user failed\n");
+        kfree(tempResponseBuffer);
+        LEAVE();
+        return -EFAULT;
+    }
+    pMefData->size = wrq->u.data.length;
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_MEF_CFG, 0,
+                           HostCmd_OPTION_WAITFORRSP, 0, tempResponseBuffer);
+    kfree(tempResponseBuffer);
+    LEAVE();
+    return ret;
+
+}
+
+/**
+ *  @brief Get the CFP table based on the region code
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to iwreq structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_cfp_table_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    pwlan_ioctl_cfp_table ioctl_cfp;
+    CHANNEL_FREQ_POWER *cfp;
+    int cfp_no;
+    int regioncode;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
+        ret = -EINVAL;
+        goto cfpexit;
+    }
+
+    ioctl_cfp = (pwlan_ioctl_cfp_table) wrq->u.data.pointer;
+
+    if (copy_from_user(&regioncode, &ioctl_cfp->region, sizeof(int))) {
+        PRINTM(INFO, "Get CFP table: copy from user failed\n");
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    if (!regioncode)
+        regioncode = Adapter->RegionCode;
+
+    cfp =
+        wlan_get_region_cfp_table((u8) regioncode, (u8) Adapter->config_bands,
+                                  &cfp_no);
+
+    if (cfp == NULL) {
+        PRINTM(MSG, "No related CFP table found, region code = 0x%x\n",
+               regioncode);
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    if (copy_to_user(&ioctl_cfp->cfp_no, &cfp_no, sizeof(int))) {
+        PRINTM(INFO, "Get CFP table: copy to user failed\n");
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    if (copy_to_user
+        (ioctl_cfp->cfp, cfp, sizeof(CHANNEL_FREQ_POWER) * cfp_no)) {
+        PRINTM(INFO, "Get CFP table: copy to user failed\n");
+        ret = -EFAULT;
+        goto cfpexit;
+    }
+
+    wrq->u.data.length =
+        sizeof(int) * 2 + sizeof(CHANNEL_FREQ_POWER) * cfp_no;
+
+  cfpexit:
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Get firmware memory
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to iwreq structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_firmware_mem(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_GET_MEM *pGetMem;
+    u8 *buf = NULL;
+    FW_MEM_DATA *pFwData;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if ((wrq->u.data.length < sizeof(HostCmd_DS_GET_MEM)) ||
+        !wrq->u.data.pointer) {
+        ret = -EINVAL;
+        LEAVE();
+        return ret;
+    }
+    if (!(buf = kmalloc(MRVDRV_SIZE_OF_CMD_BUFFER, GFP_KERNEL))) {
+        PRINTM(INFO, "allocate  buffer failed!\n");
+        LEAVE();
+        return -ENOMEM;
+    }
+    memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+    pFwData = (FW_MEM_DATA *) buf;
+    pGetMem = &pFwData->data;
+
+    if (copy_from_user
+        (pGetMem, wrq->u.data.pointer, sizeof(HostCmd_DS_GET_MEM))) {
+        PRINTM(INFO, "Get Mem: copy from user failed\n");
+        ret = -EFAULT;
+        goto memexit;
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_GET_MEM, 0,
+                           HostCmd_OPTION_WAITFORRSP, 0, buf);
+    if (!ret) {
+        wrq->u.data.length = pFwData->size;
+        if (copy_to_user
+            (wrq->u.data.pointer, (u8 *) pGetMem, wrq->u.data.length)) {
+            PRINTM(INFO, "Get Mem: copy to user failed\n");
+            ret = -EFAULT;
+            goto memexit;
+        }
+    }
+  memexit:
+    kfree(buf);
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief  Retrieve transmit packet statistics from the firmware
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param wrq      A pointer to iwreq structure
+ *
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_tx_pkt_stats_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    HostCmd_DS_TX_PKT_STATS txPktStats;
+    int ret;
+
+    ENTER();
+
+    if (wrq->u.data.length == 0 || !wrq->u.data.pointer) {
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (wrq->u.data.length < sizeof(txPktStats)) {
+        LEAVE();
+        return -E2BIG;
+    }
+
+    memset(&txPktStats, 0x00, sizeof(txPktStats));
+
+    if ((ret = wlan_prepare_cmd(priv,
+                                HostCmd_CMD_TX_PKT_STATS, 0,
+                                HostCmd_OPTION_WAITFORRSP, 0, &txPktStats))) {
+        LEAVE();
+        return ret;
+    }
+
+    if (copy_to_user(wrq->u.data.pointer,
+                     (u8 *) & txPktStats, sizeof(txPktStats))) {
+        PRINTM(INFO, "TxPktStats: copy to user failed\n");
+        LEAVE();
+        return -EFAULT;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/********************************************************
+		Global Functions
+********************************************************/
+/** 
+ *  @brief ioctl function - entry point
+ *  
+ *  @param dev		A pointer to net_device structure
+ *  @param req	   	A pointer to ifreq structure
+ *  @param cmd 		command
+ *  @return 	   	WLAN_STATUS_SUCCESS--success, otherwise fail
+ */
+int
+wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+    int subcmd = 0;
+    int idata = 0;
+    int *pdata;
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    struct iwreq *wrq = (struct iwreq *) req;
+
+    ENTER();
+
+    if (Adapter->bHostSleepConfigured) {
+        BOOLEAN cmd_allowed = FALSE;
+        int count = sizeof(Commands_Allowed_In_HostSleep)
+            / sizeof(Commands_Allowed_In_HostSleep[0]);
+
+        if (cmd == WLAN_SET_GET_SIXTEEN_INT &&
+            ((int) wrq->u.data.flags == WLANHSCFG)) {
+            u32 cond;
+            if (copy_from_user(&cond, wrq->u.data.pointer, sizeof(cond))) {
+                PRINTM(INFO, "Copy from user failed\n");
+                LEAVE();
+                return -EFAULT;
+            }
+
+            if (cond == HOST_SLEEP_CFG_CANCEL) {
+                cmd_allowed = TRUE;
+                if (Adapter->IsDeepSleep) {
+                    wlan_set_deep_sleep(priv, FALSE);
+                }
+            }
+        } else
+            if (wlan_is_cmd_allowed_in_ds_hs
+                (req, cmd, Commands_Allowed_In_HostSleep, count)) {
+            cmd_allowed = TRUE;
+        }
+        if (!cmd_allowed) {
+            PRINTM(MSG, "%s IOCTLS called when WLAN access is blocked\n",
+                   __FUNCTION__);
+            LEAVE();
+            return -EBUSY;
+        }
+    }
+
+    if (!Adapter->IsAutoDeepSleepEnabled) {
+        if (Adapter->IsDeepSleep) {
+            int count = sizeof(Commands_Allowed_In_DeepSleep)
+                / sizeof(Commands_Allowed_In_DeepSleep[0]);
+
+            if (!wlan_is_cmd_allowed_in_ds_hs
+                (req, cmd, Commands_Allowed_In_DeepSleep, count)) {
+                PRINTM(MSG,
+                       "():%s IOCTLS called when station is"
+                       " in DeepSleep\n", __FUNCTION__);
+                LEAVE();
+                return -EBUSY;
+            }
+        }
+    } else {
+        int count = sizeof(Commands_DisAllowed_In_AutoDeepSleep) /
+            sizeof(Commands_DisAllowed_In_AutoDeepSleep[0]);
+        if (wlan_is_cmd_disallowed_in_ads(req, cmd,
+                                          Commands_DisAllowed_In_AutoDeepSleep,
+                                          count)) {
+            PRINTM(MSG, "Command is not allowed in AutoDeepSleep mode\n");
+            LEAVE();
+            return -EBUSY;
+        }
+    }
+
+    PRINTM(INFO, "wlan_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+    switch (cmd) {
+    case WLANEXTSCAN:
+        ret = wlan_extscan_ioctl(priv, req);
+        break;
+    case WLANHOSTCMD:
+        ret = wlan_hostcmd_ioctl(dev, req, cmd);
+        break;
+    case WLANARPFILTER:
+        ret = wlan_arpfilter_ioctl(dev, req, cmd);
+        break;
+
+    case WLANCISDUMP:          /* Read CIS Table  */
+        ret = wlan_do_getcis_ioctl(priv, req);
+        break;
+
+    case WLANSCAN_TYPE:
+        PRINTM(INFO, "Scan Type Ioctl\n");
+        ret = wlan_scan_type_ioctl(priv, wrq);
+        break;
+
+    case WLAN_SETADDR_GETNONE:
+        switch (wrq->u.data.flags) {
+        case WLANDEAUTH:
+            {
+                struct sockaddr saddr;
+
+                PRINTM(INFO, "Deauth\n");
+
+                if (wrq->u.data.length) {
+                    if (copy_from_user(&saddr,
+                                       wrq->u.data.pointer, sizeof(saddr))) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+                    wmm_stop_queue(priv);
+                    ret =
+                        wlan_prepare_cmd(priv,
+                                         HostCmd_CMD_802_11_DEAUTHENTICATE, 0,
+                                         HostCmd_OPTION_WAITFORRSP, 0,
+                                         &saddr);
+
+                    if (Adapter->MediaConnectStatus ==
+                        WlanMediaStateConnected) {
+                        wmm_start_queue(priv);
+                        os_carrier_on(priv);
+                        os_start_queue(priv);
+                    }
+                } else {
+                    ret = wlan_disconnect(priv);
+                }
+                break;
+            }
+
+        default:
+            ret = -EOPNOTSUPP;
+            break;
+        }
+        break;
+
+#ifdef MFG_CMD_SUPPORT
+    case WLANMANFCMD:
+        PRINTM(INFO, "Entering the Manufacturing ioctl SIOCCFMFG\n");
+        ret = wlan_mfg_command(priv, wrq);
+
+        PRINTM(INFO, "Manufacturing Ioctl %s\n",
+               (ret) ? "failed" : "success");
+        break;
+#endif
+
+    case WLANREGRDWR:          /* Register read write command */
+        ret = wlan_regrdwr_ioctl(priv, req);
+        break;
+
+    case WLANCMD52RDWR:        /* CMD52 read/write command */
+        ret = wlan_cmd52rdwr_ioctl(priv, req);
+        break;
+
+    case WLANCMD53RDWR:        /* CMD53 read/write command */
+        ret = wlan_cmd53rdwr_ioctl(priv, req);
+        break;
+
+    case SIOCSIWENCODE:        /* set encoding token & mode for WPA */
+        ret = wlan_set_encode(dev, NULL, &(wrq->u.data), wrq->u.data.pointer);
+        break;
+    case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
+        switch (wrq->u.data.flags) {
+        case WLANADHOCSTOP:
+            PRINTM(INFO, "Adhoc stop\n");
+            ret = wlan_do_adhocstop_ioctl(priv);
+            break;
+
+        case WLANRADIOON:
+            wlan_radio_ioctl(priv, RADIO_ON);
+            break;
+
+        case WLANRADIOOFF:
+            ret = wlan_radio_ioctl(priv, RADIO_OFF);
+            break;
+        case WLANREMOVEADHOCAES:
+            ret = wlan_remove_aes(priv);
+            break;
+        case WLANCRYPTOTEST:
+            ret = wlan_crypto_test(priv, wrq);
+            break;
+#ifdef REASSOCIATION
+        case WLANREASSOCIATIONAUTO:
+            reassociation_on(priv);
+            break;
+        case WLANREASSOCIATIONUSER:
+            reassociation_off(priv);
+            break;
+#endif /* REASSOCIATION */
+        case WLANWLANIDLEON:
+            wlanidle_on(priv);
+            break;
+        case WLANWLANIDLEOFF:
+            wlanidle_off(priv);
+            break;
+        }                       /* End of switch */
+        break;
+
+    case WLAN_SETWORDCHAR_GETNONE:
+        switch (wrq->u.data.flags) {
+        case WLANSETADHOCAES:
+            ret = wlan_setadhocaes_ioctl(priv, req);
+            break;
+        }
+        break;
+
+    case WLAN_SETONEINT_GETWORDCHAR:
+        switch (wrq->u.data.flags) {
+        case WLANGETADHOCAES:
+            ret = wlan_getadhocaes_ioctl(priv, req);
+            break;
+        case WLANVERSION:      /* Get driver version */
+            ret = wlan_version_ioctl(priv, req);
+            break;
+        case WLANVEREXT:
+            ret = wlan_verext_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLANSETWPAIE:
+        ret = wlan_set_wpa_ie_ioctl(priv, req);
+        break;
+    case WLAN_SETINT_GETINT:
+        /* The first 4 bytes of req->ifr_data is sub-ioctl number
+         * after 4 bytes sits the payload.
+         */
+        subcmd = (int) req->ifr_data;   //from iwpriv subcmd
+        switch (subcmd) {
+        case WLANNF:
+            ret = wlan_get_nf(priv, wrq);
+            break;
+        case WLANRSSI:
+            ret = wlan_get_rssi(priv, wrq);
+            break;
+        case WLANBGSCAN:
+            {
+                int data, data1;
+                int *val;
+                data1 = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+                switch (data1) {
+                case CMD_DISABLED:
+                    PRINTM(INFO, "Background scan is set to disable\n");
+                    ret = wlan_bg_scan_enable(priv, FALSE);
+                    val = (int *) wrq->u.name;
+                    *val = data1;
+                    break;
+                case CMD_ENABLED:
+                    PRINTM(INFO, "Background scan is set to enable\n");
+                    ret = wlan_bg_scan_enable(priv, TRUE);
+                    val = (int *) wrq->u.name;
+                    *val = data1;
+                    break;
+                case CMD_GET:
+                    data = (Adapter->bgScanConfig->Enable == TRUE) ?
+                        CMD_ENABLED : CMD_DISABLED;
+                    val = (int *) wrq->u.name;
+                    *val = data;
+                    break;
+                default:
+                    ret = -EINVAL;
+                    PRINTM(INFO, "Background scan: wrong parameter\n");
+                    break;
+                }
+            }
+            break;
+        case WLANENABLE11D:
+            ret = wlan_cmd_enable_11d(priv, wrq);
+            break;
+        case WLANADHOCGRATE:
+            ret = wlan_do_set_grate_ioctl(priv, wrq);
+            break;
+        case WLANSDIOCLOCK:
+            {
+                int data;
+                int *val;
+                data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+                switch (data) {
+                case CMD_DISABLED:
+                    PRINTM(INFO, "SDIO clock is turned off\n");
+                    ret = sbi_set_bus_clock(priv, FALSE);
+                    break;
+                case CMD_ENABLED:
+                    PRINTM(INFO, "SDIO clock is turned on\n");
+                    ret = sbi_set_bus_clock(priv, TRUE);
+                    break;
+                case CMD_GET:  /* need an API in sdio.c to get STRPCL */
+                default:
+                    ret = -EINVAL;
+                    PRINTM(INFO, "sdioclock: wrong parameter\n");
+                    break;
+                }
+                val = (int *) wrq->u.name;
+                *val = data;
+            }
+            break;
+        case WLANWMM_ENABLE:
+            ret = wlan_wmm_enable_ioctl(priv, wrq);
+            break;
+        case WLANNULLGEN:
+            ret = wlan_null_pkg_gen(priv, wrq);
+            /* enable/disable null pkg generation */
+            break;
+        case WLANADHOCCSET:
+            ret = wlan_set_coalescing_ioctl(priv, wrq);
+            break;
+        case WLAN_ADHOC_G_PROT:
+            ret = wlan_adhoc_g_protection(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLAN_SETONEINT_GETONEINT:
+        switch (wrq->u.data.flags) {
+        case WLAN_11H_SETLOCALPOWER:
+            ret = wlan_11h_ioctl_get_local_power(priv, wrq);
+            break;
+
+        case WLAN_WMM_QOSINFO:
+            {
+                int data;
+                if (wrq->u.data.length == 1) {
+                    if (copy_from_user
+                        (&data, wrq->u.data.pointer, sizeof(int))) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+                    Adapter->wmm.qosinfo = (u8) data;
+                } else {
+                    data = (int) Adapter->wmm.qosinfo;
+                    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                        PRINTM(INFO, "Copy to user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+                    wrq->u.data.length = 1;
+                }
+            }
+            break;
+        case WLAN_LISTENINTRVL:
+            if (!wrq->u.data.length) {
+                int data;
+                PRINTM(INFO, "Get LocalListenInterval Value\n");
+#define GET_ONE_INT	1
+                data = Adapter->LocalListenInterval;
+                if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                    PRINTM(INFO, "Copy to user failed\n");
+                    LEAVE();
+                    return -EFAULT;
+                }
+
+                wrq->u.data.length = GET_ONE_INT;
+            } else {
+                int data;
+                if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+                    PRINTM(INFO, "Copy from user failed\n");
+                    LEAVE();
+                    return -EFAULT;
+                }
+
+                PRINTM(INFO, "Set LocalListenInterval = %d\n", data);
+#define MAX_U16_VAL	65535
+                if (data > MAX_U16_VAL) {
+                    PRINTM(INFO, "Exceeds U16 value\n");
+                    LEAVE();
+                    return -EINVAL;
+                }
+                Adapter->LocalListenInterval = data;
+            }
+            break;
+        case WLAN_FW_WAKEUP_METHOD:
+            ret = wlan_cmd_fw_wakeup_method(priv, wrq);
+            break;
+        case WLAN_NULLPKTINTERVAL:
+            ret = wlan_null_pkt_interval(priv, wrq);
+            break;
+        case WLAN_BCN_MISS_TIMEOUT:
+            ret = wlan_bcn_miss_timeout(priv, wrq);
+            break;
+        case WLAN_ADHOC_AWAKE_PERIOD:
+            ret = wlan_adhoc_awake_period(priv, wrq);
+            break;
+        case WLAN_MODULE_TYPE:
+            ret = wlan_module_type_config(priv, wrq);
+            break;
+        case WLAN_AUTODEEPSLEEP:
+            ret = wlan_auto_deep_sleep(priv, wrq);
+            break;
+        case WLAN_ENHANCEDPS:
+            ret = wlan_enhanced_ps(priv, wrq);
+            break;
+        case WLAN_WAKEUP_MT:
+            if (wrq->u.data.length > 0)
+                Adapter->IntCounter++;
+            wake_up_interruptible(&priv->MainThread.waitQ);
+            break;
+        default:
+            ret = -EOPNOTSUPP;
+            break;
+        }
+        break;
+
+    case WLAN_SETONEINT_GETNONE:
+        /* The first 4 bytes of req->ifr_data is sub-ioctl number
+         * after 4 bytes sits the payload.
+         */
+        subcmd = wrq->u.data.flags;     //from wpa_supplicant subcmd
+
+        if (!subcmd)
+            subcmd = (int) req->ifr_data;       //from iwpriv subcmd
+
+        idata = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+        switch (subcmd) {
+        case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */
+            ret = wlan_set_rx_antenna(priv, idata);
+            break;
+        case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */
+            ret = wlan_set_tx_antenna(priv, idata);
+            break;
+
+        case WLANSETBCNAVG:
+            if (idata == 0)
+                Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+            else if (idata > MAX_BCN_AVG_FACTOR || idata < MIN_BCN_AVG_FACTOR) {
+                PRINTM(MSG, "The value '%u' is out of the range (0-%u).\n",
+                       idata, MAX_BCN_AVG_FACTOR);
+                LEAVE();
+                return -EINVAL;
+            } else
+                Adapter->bcn_avg_factor = idata;
+            break;
+        case WLANSETDATAAVG:
+            if (idata == 0)
+                Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+            else if (idata > MAX_DATA_AVG_FACTOR
+                     || idata < MIN_DATA_AVG_FACTOR) {
+                PRINTM(MSG, "The value '%u' is out of the range (0-%u).\n",
+                       idata, MAX_DATA_AVG_FACTOR);
+                LEAVE();
+                return -EINVAL;
+            } else
+                Adapter->data_avg_factor = idata;
+            memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR));
+            memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF));
+            Adapter->nextSNRNF = 0;
+            Adapter->numSNRNF = 0;
+            break;
+        case WLANASSOCIATE:
+            ret = wlan_associate_to_table_idx(priv, idata);
+            break;
+
+        case WLANSETREGION:
+            ret = wlan_set_region(priv, (u16) idata);
+            break;
+
+        case WLAN_SET_LISTEN_INTERVAL:
+            Adapter->ListenInterval = (u16) idata;
+            break;
+
+        case WLAN_SET_MULTIPLE_DTIM:
+            ret = wlan_set_multiple_dtim_ioctl(priv, req);
+            break;
+
+        case WLANSETAUTHALG:
+            ret = wlan_setauthalg_ioctl(priv, req);
+            break;
+
+        case WLANSETENCRYPTIONMODE:
+            ret = wlan_setencryptionmode_ioctl(priv, req);
+            break;
+
+        default:
+            ret = -EOPNOTSUPP;
+            break;
+        }
+
+        break;
+
+    case WLAN_SETNONE_GETTWELVE_CHAR:  /* Get Antenna settings */
+        /* 
+         * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+         * in flags of iwreq structure, otherwise it will be in
+         * mode member of iwreq structure.
+         */
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */
+            ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
+            break;
+
+        case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */
+            ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
+            break;
+
+        case WLAN_GET_TSF:
+            ret = wlan_get_tsf_ioctl(priv, wrq);
+            break;
+
+        case WLAN_WPS_SESSION:
+            ret = wlan_do_wps_session_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLANDEEPSLEEP:
+        ret = wlan_deepsleep_ioctl(priv, req);
+        break;
+
+    case WLAN_SET64CHAR_GET64CHAR:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_11H_REQUESTTPC:
+            ret = wlan_11h_ioctl_request_tpc(priv, wrq);
+            break;
+        case WLAN_11H_SETPOWERCAP:
+            ret = wlan_11h_ioctl_set_power_cap(priv, wrq);
+            break;
+        case WLAN_MEASREQ:
+            ret = wlan_meas_ioctl_send_req(priv, wrq);
+            break;
+
+        case WLANSLEEPPARAMS:
+            ret = wlan_sleep_params_ioctl(priv, wrq);
+            break;
+
+        case WLAN_BCA_TIMESHARE:
+            ret = wlan_bca_timeshare_ioctl(priv, wrq);
+            break;
+        case WLANSCAN_MODE:
+            PRINTM(INFO, "Scan Mode Ioctl\n");
+            ret = wlan_scan_mode_ioctl(priv, wrq);
+            break;
+
+        case WLAN_GET_ADHOC_STATUS:
+            ret = wlan_get_adhoc_status_ioctl(priv, wrq);
+            break;
+        case WLAN_SET_GEN_IE:
+            ret = wlan_set_gen_ie_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_GEN_IE:
+            ret = wlan_get_gen_ie_ioctl(priv, wrq);
+            break;
+        case WLAN_WMM_QUEUE_STATUS:
+            ret = wlan_wmm_queue_status_ioctl(priv, wrq);
+            break;
+        case WLAN_WMM_TS_STATUS:
+            ret = wlan_wmm_ts_status_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLAN_SETCONF_GETCONF:
+        PRINTM(INFO, "The WLAN_SETCONF_GETCONF=0x%x is %d\n",
+               WLAN_SETCONF_GETCONF, *(u8 *) req->ifr_data);
+        switch (*(u8 *) req->ifr_data) {
+        case CAL_DATA_EXT_CONFIG:
+            ret = wlan_do_caldata_ext_ioctl(priv, req);
+            break;
+        case BG_SCAN_CONFIG:
+            ret = wlan_do_bg_scan_config_ioctl(priv, req);
+            break;
+        case BG_SCAN_CFG:
+            ret = wlan_do_bgscfg_ioctl(priv, req);
+            break;
+        }
+        break;
+
+    case WLAN_SETNONE_GETONEINT:
+        switch ((int) req->ifr_data) {
+        case WLANGETBCNAVG:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->bcn_avg_factor;
+            break;
+
+        case WLANGETDATAAVG:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->data_avg_factor;
+            break;
+
+        case WLANGETREGION:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->RegionCode;
+            break;
+
+        case WLAN_GET_LISTEN_INTERVAL:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->ListenInterval;
+            break;
+
+        case WLAN_GET_MULTIPLE_DTIM:
+            pdata = (int *) wrq->u.name;
+            *pdata = (int) Adapter->MultipleDtim;
+            break;
+        case WLAN_GET_TX_RATE:
+            ret = wlan_get_txrate_ioctl(priv, req);
+            break;
+        default:
+            ret = -EOPNOTSUPP;
+
+        }
+
+        break;
+
+    case WLAN_SETTENCHAR_GETNONE:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_SET_BAND:
+            ret = wlan_do_setband_ioctl(priv, wrq);
+            break;
+
+        case WLAN_SET_ADHOC_CH:
+            ret = wlan_do_setadhocch_ioctl(priv, wrq);
+            break;
+
+        case WLAN_11H_CHANSWANN:
+            ret = wlan_11h_ioctl_chan_sw_ann(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLAN_SETNONE_GETTENCHAR:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_GET_BAND:
+            ret = wlan_do_get_band_ioctl(priv, wrq);
+            break;
+
+        case WLAN_GET_ADHOC_CH:
+            ret = wlan_do_get_adhocch_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLANGETLOG:
+        ret = wlan_do_getlog_ioctl(priv, wrq);
+        break;
+
+    case WLAN_SET_GET_SIXTEEN_INT:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_TPCCFG:
+            {
+                int data[5];
+                HostCmd_DS_802_11_TPC_CFG cfg;
+                memset(&cfg, 0, sizeof(cfg));
+                if ((wrq->u.data.length > 1) && (wrq->u.data.length != 5)) {
+                    LEAVE();
+                    return WLAN_STATUS_FAILURE;
+                }
+                if (wrq->u.data.length == 0) {
+                    cfg.Action = HostCmd_ACT_GEN_GET;
+                } else {
+                    if (copy_from_user(data,
+                                       wrq->u.data.pointer,
+                                       sizeof(int) * 5)) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+
+                    cfg.Action = HostCmd_ACT_GEN_SET;
+                    cfg.Enable = data[0];
+                    cfg.UseSNR = data[1];
+#define TPC_DATA_NO_CHANG	0x7f
+                    if (wrq->u.data.length == 1) {
+                        cfg.P0 = TPC_DATA_NO_CHANG;
+                        cfg.P1 = TPC_DATA_NO_CHANG;
+                        cfg.P2 = TPC_DATA_NO_CHANG;
+                    } else {
+                        cfg.P0 = data[2];
+                        cfg.P1 = data[3];
+                        cfg.P2 = data[4];
+                    }
+                }
+
+                ret = wlan_prepare_cmd(priv,
+                                       HostCmd_CMD_802_11_TPC_CFG, 0,
+                                       HostCmd_OPTION_WAITFORRSP, 0,
+                                       (void *) &cfg);
+
+                data[0] = cfg.Enable;
+                data[1] = cfg.UseSNR;
+                data[2] = cfg.P0;
+                data[3] = cfg.P1;
+                data[4] = cfg.P2;
+                if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 5)) {
+                    PRINTM(INFO, "Copy to user failed\n");
+                    LEAVE();
+                    return -EFAULT;
+                }
+
+                wrq->u.data.length = 5;
+            }
+            break;
+
+        case WLAN_SCANPROBES:
+            {
+                int data;
+                if (wrq->u.data.length > 0) {
+                    if (copy_from_user
+                        (&data, wrq->u.data.pointer, sizeof(int))) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+
+                    Adapter->ScanProbes = data;
+                } else {
+                    data = Adapter->ScanProbes;
+                    if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+                        PRINTM(INFO, "Copy to user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+                }
+                wrq->u.data.length = 1;
+            }
+            break;
+        case WLAN_LED_GPIO_CTRL:
+            {
+                int i;
+                int data[MAX_LEDS * 2];
+                HostCmd_DS_802_11_LED_CTRL ctrl;
+                MrvlIEtypes_LedGpio_t *gpio;
+
+                gpio = (MrvlIEtypes_LedGpio_t *) & ctrl.LedGpio;
+
+                if ((wrq->u.data.length > MAX_LEDS * 2) ||
+                    (wrq->u.data.length % 2) != 0) {
+                    PRINTM(MSG, "invalid ledgpio parameters\n");
+                    LEAVE();
+                    return -EINVAL;
+                }
+
+                memset(&ctrl, 0, sizeof(ctrl));
+                if (wrq->u.data.length == 0) {
+                    ctrl.Action = HostCmd_ACT_GEN_GET;
+                } else {
+                    if (copy_from_user(data, wrq->u.data.pointer,
+                                       sizeof(int) * wrq->u.data.length)) {
+                        PRINTM(INFO, "Copy from user failed\n");
+                        LEAVE();
+                        return -EFAULT;
+                    }
+
+                    ctrl.Action = HostCmd_ACT_GEN_SET;
+                    ctrl.LedNums = 0;
+                    gpio->Header.Type = TLV_TYPE_LED_GPIO;
+                    gpio->Header.Len = wrq->u.data.length;
+                    for (i = 0; i < wrq->u.data.length; i += 2) {
+                        gpio->LedGpio[i / 2].LedNum = data[i];
+                        gpio->LedGpio[i / 2].GpioNum = data[i + 1];
+                    }
+                }
+                ret = wlan_prepare_cmd(priv,
+                                       HostCmd_CMD_802_11_LED_CONTROL, 0,
+                                       HostCmd_OPTION_WAITFORRSP,
+                                       0, (void *) &ctrl);
+
+                for (i = 0; i < gpio->Header.Len; i += 2) {
+                    data[i] = gpio->LedGpio[i / 2].LedNum;
+                    data[i + 1] = gpio->LedGpio[i / 2].GpioNum;
+                }
+                if (copy_to_user(wrq->u.data.pointer, data,
+                                 sizeof(int) * gpio->Header.Len)) {
+                    PRINTM(INFO, "Copy to user failed\n");
+                    LEAVE();
+                    return -EFAULT;
+                }
+
+                wrq->u.data.length = gpio->Header.Len;
+            }
+            break;
+        case WLAN_SLEEP_PERIOD:
+            ret = wlan_sleep_period(priv, wrq);
+            break;
+        case WLAN_ADAPT_RATESET:
+            ret = wlan_adapt_rateset(priv, wrq);
+            break;
+        case WLAN_INACTIVITY_TIMEOUT:
+            ret = wlan_inactivity_timeout(priv, wrq);
+            break;
+        case WLANSNR:
+            ret = wlan_get_snr(priv, wrq);
+            break;
+        case WLAN_GET_RATE:
+            ret = wlan_getrate_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_RXINFO:
+            ret = wlan_get_rxinfo(priv, wrq);
+            break;
+        case WLAN_SET_ATIM_WINDOW:
+            ret = wlan_atim_window(priv, wrq);
+            break;
+        case WLAN_BEACON_INTERVAL:
+            ret = wlan_beacon_interval(priv, wrq);
+            break;
+        case WLAN_SDIO_PULL_CTRL:
+            ret = wlan_sdio_pull_ctrl(priv, wrq);
+            break;
+        case WLAN_SCAN_TIME:
+            ret = wlan_scan_time(priv, wrq);
+            break;
+        case WLAN_ECL_SYS_CLOCK:
+            ret = wlan_ecl_sys_clock(priv, wrq);
+            break;
+        case WLAN_TXCONTROL:
+            ret = wlan_txcontrol(priv, wrq);
+            break;
+        case WLANHSCFG:
+            ret = wlan_hscfg_ioctl(priv, wrq);
+            break;
+        case WLANHSSETPARA:
+            ret = wlan_hssetpara_ioctl(priv, wrq);
+            break;
+        case WLANDBGSCFG:
+            ret = wlan_dbgs_cfg(priv, wrq);
+            break;
+#ifdef DEBUG_LEVEL1
+        case WLAN_DRV_DBG:
+            ret = wlan_drv_dbg(priv, wrq);
+            break;
+#endif
+        case WLAN_DRV_DELAY_MAX:
+            ret = wlan_wmm_drv_delay_max_ioctl(priv, wrq);
+            break;
+        }
+        break;
+
+    case WLAN_SET_GET_2K:
+        switch ((int) wrq->u.data.flags) {
+        case WLAN_SET_USER_SCAN:
+            ret = wlan_set_user_scan_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_SCAN_TABLE:
+            ret = wlan_get_scan_table_ioctl(priv, wrq);
+            break;
+        case WLAN_SET_MRVL_TLV:
+            ret = wlan_set_mrvl_tlv_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_ASSOC_RSP:
+            ret = wlan_get_assoc_rsp_ioctl(priv, wrq);
+            break;
+        case WLAN_ADDTS_REQ:
+            ret = wlan_wmm_addts_req_ioctl(priv, wrq);
+            break;
+        case WLAN_DELTS_REQ:
+            ret = wlan_wmm_delts_req_ioctl(priv, wrq);
+            break;
+        case WLAN_QUEUE_CONFIG:
+            ret = wlan_wmm_queue_config_ioctl(priv, wrq);
+            break;
+        case WLAN_QUEUE_STATS:
+            ret = wlan_wmm_queue_stats_ioctl(priv, wrq);
+            break;
+        case WLAN_TX_PKT_STATS:
+            ret = wlan_tx_pkt_stats_ioctl(priv, wrq);
+            break;
+        case WLAN_GET_CFP_TABLE:
+            ret = wlan_get_cfp_table_ioctl(priv, wrq);
+            break;
+        case WLAN_MEF_CFG:
+            ret = wlan_set_mef_cfg(priv, wrq);
+            break;
+        case WLAN_GET_MEM:
+            ret = wlan_get_firmware_mem(priv, wrq);
+            break;
+        default:
+            ret = -EOPNOTSUPP;
+        }
+        break;
+
+    default:
+        ret = -EINVAL;
+        break;
+    }
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get wireless statistics
+ *
+ *  NOTE: If wlan_prepare_cmd() with wait option is issued 
+ *    in this function, a kernel dump (scheduling while atomic) 
+ *    issue may happen on some versions of kernels.
+ *
+ *  @param dev		A pointer to net_device structure
+ *  @return 	   	A pointer to iw_statistics buf
+ */
+struct iw_statistics *
+wlan_get_wireless_stats(struct net_device *dev)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return NULL;
+    }
+
+    priv->wstats.status = Adapter->InfrastructureMode;
+    priv->wstats.discard.retries = priv->stats.tx_errors;
+
+    /* send RSSI command to get beacon RSSI/NF, valid only if associated */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+        ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_RSSI, 0, 0, 0, NULL);
+    }
+
+    priv->wstats.qual.level =
+        CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG],
+                 Adapter->NF[TYPE_BEACON][TYPE_AVG]);
+    if (Adapter->NF[TYPE_BEACON][TYPE_AVG] == 0
+        && Adapter->MediaConnectStatus == WlanMediaStateConnected)
+        priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+    else
+        priv->wstats.qual.noise = CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_AVG]);
+    priv->wstats.qual.qual = 0;
+
+    PRINTM(INFO, "Signal Level = %#x\n", priv->wstats.qual.level);
+    PRINTM(INFO, "Noise = %#x\n", priv->wstats.qual.noise);
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_GET_LOG, 0, 0, 0, NULL);
+
+    if (!ret) {
+        priv->wstats.discard.code = 0;
+        priv->wstats.discard.fragment = Adapter->LogMsg.fcserror;
+        priv->wstats.discard.retries = Adapter->LogMsg.retry;
+        priv->wstats.discard.misc = Adapter->LogMsg.ackfailure;
+    }
+
+    LEAVE();
+
+    return &priv->wstats;
+}
+
+static int
+wlan_set_coalescing_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    int data;
+    int *val;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    data = *((int *) (wrq->u.name + SUBCMD_OFFSET));
+
+    switch (data) {
+    case CMD_DISABLED:
+    case CMD_ENABLED:
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                               HostCmd_ACT_GEN_SET,
+                               HostCmd_OPTION_WAITFORRSP, 0, &data);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+        break;
+
+    case CMD_GET:
+        ret = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+                               HostCmd_ACT_GEN_GET,
+                               HostCmd_OPTION_WAITFORRSP, 0, &data);
+        if (ret) {
+            LEAVE();
+            return ret;
+        }
+        break;
+
+    default:
+        LEAVE();
+        return -EINVAL;
+    }
+
+    val = (int *) wrq->u.name;
+    *val = data;
+
+    LEAVE();
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set frequency
+ *   
+ *  @param dev 			A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure 
+ *  @param fwrq			A pointer to iw_freq structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS--success, otherwise--fail
+ */
+int
+wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+              struct iw_freq *fwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int rc = -EINPROGRESS;      /* Call commit handler */
+    CHANNEL_FREQ_POWER *cfp;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+    if (Adapter->InfrastructureMode != Wlan802_11IBSS) {
+        LEAVE();
+        return -EOPNOTSUPP;
+    }
+    if (Adapter->is_multiband) {
+        PRINTM(MSG, "SIOCSIWFREQ: IOCTLS call not supported in "
+               "MultiBands mode, use private command "
+               "'setadhocch' instead.\n");
+        LEAVE();
+        return -ENOTSUPP;
+    }
+
+    /*
+     * If setting by frequency, convert to a channel 
+     */
+    if (fwrq->e == 1) {
+
+        long f = fwrq->m / 100000;
+        int c = 0;
+
+        cfp = find_cfp_by_band_and_freq(Adapter, 0, f);
+        if (!cfp) {
+            PRINTM(INFO, "Invalid freq=%ld\n", f);
+            LEAVE();
+            return -EINVAL;
+        }
+
+        c = (int) cfp->Channel;
+
+        if (c < 0) {
+            LEAVE();
+            return -EINVAL;
+        }
+        fwrq->e = 0;
+        fwrq->m = c;
+    }
+
+    /*
+     * Setting by channel number 
+     */
+    if (fwrq->m > 1000 || fwrq->e > 0) {
+        rc = -EOPNOTSUPP;
+    } else {
+        int channel = fwrq->m;
+
+        cfp = find_cfp_by_band_and_channel(Adapter, 0, (u16) channel);
+        if (!cfp) {
+            rc = -EINVAL;
+        } else {
+            rc = wlan_change_adhoc_chan(priv, channel);
+            /*  If station is WEP enabled, send the 
+             *  command to set WEP in firmware
+             */
+            if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) {
+                PRINTM(INFO, "set_freq: WEP Enabled\n");
+                ret = wlan_prepare_cmd(priv,
+                                       HostCmd_CMD_802_11_SET_WEP,
+                                       HostCmd_ACT_ADD,
+                                       HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+                if (ret) {
+                    LEAVE();
+                    return ret;
+                }
+                Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE;
+
+                wlan_prepare_cmd(priv,
+                                 HostCmd_CMD_MAC_CONTROL,
+                                 0, HostCmd_OPTION_WAITFORRSP,
+                                 0, &Adapter->CurrentPacketFilter);
+            }
+        }
+    }
+
+    LEAVE();
+    return rc;
+}
+
+/** 
+ *  @brief Set Deep Sleep 
+ *   
+ *  @param priv 	A pointer to wlan_private structure
+ *  @param bDeepSleep	TRUE--enalbe deepsleep, FALSE--disable deepsleep
+ *  @return 	   	WLAN_STATUS_SUCCESS-success, otherwise fail
+ */
+
+int
+wlan_set_deep_sleep(wlan_private * priv, BOOLEAN bDeepSleep)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    if (bDeepSleep == TRUE) {
+        if (Adapter->IsDeepSleep != TRUE) {
+            PRINTM(INFO, "Deep Sleep: sleep\n");
+
+            // note: the command could be queued and executed later
+            //       if there is command in prigressing.
+            ret = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_802_11_DEEP_SLEEP, 0,
+                                   HostCmd_OPTION_WAITFORRSP, 0, NULL);
+
+            if (ret) {
+                LEAVE();
+                return ret;
+            }
+            wmm_stop_queue(priv);
+            os_stop_queue(priv);
+            os_carrier_off(priv);
+        }
+    } else {
+        if (Adapter->IsDeepSleep == TRUE) {
+            PRINTM(CMND, "Deep Sleep: wakeup\n");
+
+            if (Adapter->IntCounterSaved) {
+                Adapter->IntCounter = Adapter->IntCounterSaved;
+                Adapter->IntCounterSaved = 0;
+            }
+
+            if (sbi_exit_deep_sleep(priv))
+                PRINTM(ERROR, "Deep Sleep : wakeup failed\n");
+
+            if (Adapter->IsDeepSleep == TRUE) {
+
+                if (os_wait_interruptible_timeout(Adapter->ds_awake_q,
+                                                  !Adapter->IsDeepSleep,
+                                                  MRVDRV_DEEP_SLEEP_EXIT_TIMEOUT)
+                    == 0) {
+                    PRINTM(MSG, "ds_awake_q: timer expired\n");
+                }
+            }
+
+            if (Adapter->IntCounter)
+                wake_up_interruptible(&priv->MainThread.waitQ);
+        }
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief use index to get the data rate
+ *   
+ *  @param index                The index of data rate
+ *  @return 	   		data rate or 0 
+ */
+u32
+index_to_data_rate(u8 index)
+{
+    ENTER();
+    if (index >= sizeof(WlanDataRates))
+        index = 0;
+
+    LEAVE();
+    return WlanDataRates[index];
+}
+
+/** 
+ *  @brief use rate to get the index
+ *   
+ *  @param rate                 data rate
+ *  @return 	   		index or 0 
+ */
+u8
+data_rate_to_index(u32 rate)
+{
+    u8 *ptr;
+
+    ENTER();
+    if (rate)
+        if ((ptr = wlan_memchr(WlanDataRates, (u8) rate,
+                               sizeof(WlanDataRates)))) {
+            LEAVE();
+            return (ptr - WlanDataRates);
+        }
+    LEAVE();
+    return 0;
+}
+
+/** 
+ *  @brief set data rate
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+
+int
+wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    u32 data_rate;
+    int ret = WLAN_STATUS_SUCCESS;
+    WLAN_802_11_RATES rates;
+    u8 *rate;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    PRINTM(INFO, "Vwrq->value = %d\n", vwrq->value);
+
+    if (vwrq->value == -1) {
+        Adapter->DataRate = 0;
+        Adapter->RateBitmap = 0;
+        memset(rates, 0, sizeof(rates));
+        get_active_data_rates(Adapter, rates);
+        rate = rates;
+        while (*rate) {
+            Adapter->RateBitmap |= 1 << (data_rate_to_index(*rate & 0x7f));
+            rate++;
+        }
+        Adapter->Is_DataRate_Auto = TRUE;
+    } else {
+        if ((vwrq->value % 500000)) {
+            LEAVE();
+            return -EINVAL;
+        }
+
+        data_rate = vwrq->value / 500000;
+
+        memset(rates, 0, sizeof(rates));
+        get_active_data_rates(Adapter, rates);
+        rate = rates;
+        while (*rate) {
+            PRINTM(INFO, "Rate=0x%X  Wanted=0x%X\n", *rate, data_rate);
+            if ((*rate & 0x7f) == (data_rate & 0x7f))
+                break;
+            rate++;
+        }
+        if (!*rate) {
+            PRINTM(MSG, "The fixed data rate 0x%X is out "
+                   "of range.\n", data_rate);
+            LEAVE();
+            return -EINVAL;
+        }
+
+        Adapter->DataRate = data_rate;
+        Adapter->RateBitmap = 1 << (data_rate_to_index(Adapter->DataRate));
+        Adapter->Is_DataRate_Auto = FALSE;
+    }
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_RATE_ADAPT_RATESET,
+                           HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP,
+                           0, NULL);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief get data rate
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+              struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    if (Adapter->Is_DataRate_Auto)
+        vwrq->fixed = 0;
+    else
+        vwrq->fixed = 1;
+
+    Adapter->TxRate = 0;
+
+    ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,
+                           HostCmd_ACT_GEN_GET, HostCmd_OPTION_WAITFORRSP,
+                           0, NULL);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+    vwrq->value = index_to_data_rate(Adapter->TxRate) * 500000;
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief set wireless mode 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param uwrq 		Wireless mode to set
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_mode(struct net_device *dev,
+              struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+    int ret = WLAN_STATUS_SUCCESS;
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+
+    WLAN_802_11_NETWORK_INFRASTRUCTURE WantedMode;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    switch (*uwrq) {
+    case IW_MODE_ADHOC:
+        PRINTM(INFO, "Wanted Mode is ad-hoc: current DataRate=%#x\n",
+               Adapter->DataRate);
+        WantedMode = Wlan802_11IBSS;
+        break;
+
+    case IW_MODE_INFRA:
+        PRINTM(INFO, "Wanted Mode is Infrastructure\n");
+        WantedMode = Wlan802_11Infrastructure;
+        break;
+
+    case IW_MODE_AUTO:
+        PRINTM(INFO, "Wanted Mode is Auto\n");
+        WantedMode = Wlan802_11AutoUnknown;
+        break;
+
+    default:
+        PRINTM(INFO, "Wanted Mode is Unknown: 0x%x\n", *uwrq);
+        LEAVE();
+        return -EINVAL;
+    }
+
+    if (Adapter->InfrastructureMode == WantedMode ||
+        WantedMode == Wlan802_11AutoUnknown) {
+        PRINTM(INFO, "Already set to required mode! No change!\n");
+
+        Adapter->InfrastructureMode = WantedMode;
+
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) {
+        if (Adapter->PSState != PS_STATE_FULL_POWER) {
+            wlan_exit_ps(priv, HostCmd_OPTION_WAITFORRSP);
+        }
+        Adapter->PSMode = Wlan802_11PowerModeCAM;
+    }
+
+    ret = wlan_disconnect(priv);
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen;
+
+    Adapter->InfrastructureMode = WantedMode;
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_SNMP_MIB,
+                           0, HostCmd_OPTION_WAITFORRSP,
+                           DesiredBssType_i, NULL);
+
+    if (ret) {
+        LEAVE();
+        return ret;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Set Encryption key
+ *   
+ *  @param dev      A pointer to net_device structure
+ *  @param info     A pointer to iw_request_info structure
+ *  @param dwrq     A pointer to iw_point structure
+ *  @param extra    A pointer to extra data buf
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+static int
+wlan_set_encode(struct net_device *dev,
+                struct iw_request_info *info,
+                struct iw_point *dwrq, char *extra)
+{
+
+    WLAN_802_11_KEY *pKey = NULL;
+    int retval = -EINVAL;
+
+    ENTER();
+
+    if (dwrq->length > MAX_WEP_KEY_SIZE) {
+        pKey = (WLAN_802_11_KEY *) extra;
+        if (pKey->KeyLength <= MAX_WEP_KEY_SIZE) {
+            //dynamic WEP
+            dwrq->length = pKey->KeyLength;
+            dwrq->flags = pKey->KeyIndex + 1;
+            retval = wlan_set_encode_nonwpa(dev, info, dwrq,
+                                            pKey->KeyMaterial);
+        } else {
+            //WPA
+            retval = wlan_set_encode_wpa(dev, info, dwrq, extra);
+        }
+    } else {
+        //static WEP
+        PRINTM(INFO, "Setting WEP\n");
+        retval = wlan_set_encode_nonwpa(dev, info, dwrq, extra);
+    }
+
+    LEAVE();
+
+    return retval;
+}
+
+/** 
+ *  @brief set tx power 
+ *   
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+               struct iw_param *vwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int ret = WLAN_STATUS_SUCCESS;
+
+    u16 dbm;
+
+    ENTER();
+
+    if (!wlan_is_cmd_allowed(priv)) {
+        PRINTM(MSG, "%s: not allowed\n", __FUNCTION__);
+        LEAVE();
+        return -EBUSY;
+    }
+
+    if (vwrq->disabled) {
+        wlan_radio_ioctl(priv, RADIO_OFF);
+        LEAVE();
+        return WLAN_STATUS_SUCCESS;
+    }
+
+    wlan_radio_ioctl(priv, RADIO_ON);
+
+    dbm = (u16) vwrq->value;
+
+    if ((dbm < Adapter->MinTxPowerLevel) || (dbm > Adapter->MaxTxPowerLevel)) {
+        PRINTM(MSG,
+               "The set txpower value %d dBm is out of range (%d dBm-%d dBm)!\n",
+               dbm, Adapter->MinTxPowerLevel, Adapter->MaxTxPowerLevel);
+        LEAVE();
+        return -EINVAL;
+    }
+
+    /* auto tx power control */
+
+    if (vwrq->fixed == 0)
+        dbm = 0xffff;
+
+    PRINTM(INFO, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+    ret = wlan_prepare_cmd(priv,
+                           HostCmd_CMD_802_11_RF_TX_POWER,
+                           HostCmd_ACT_GEN_SET,
+                           HostCmd_OPTION_WAITFORRSP, 0, (void *) &dbm);
+
+    LEAVE();
+    return ret;
+}
+
+/** 
+ *  @brief Get current essid 
+ *   
+ *  @param dev      A pointer to net_device structure
+ *  @param info     A pointer to iw_request_info structure
+ *  @param dwrq     A pointer to iw_point structure
+ *  @param extra    A pointer to extra data buf
+ *  @return         WLAN_STATUS_SUCCESS --success, otherwise fail
+ */
+int
+wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+               struct iw_point *dwrq, char *extra)
+{
+    wlan_private *priv = dev->priv;
+    wlan_adapter *Adapter = priv->adapter;
+    int tblIdx = -1;
+    BSSDescriptor_t *pBSSDesc;
+
+    ENTER();
+
+    pBSSDesc = &Adapter->CurBssParams.BSSDescriptor;
+
+    /*
+     * Get the current SSID 
+     */
+    if (Adapter->MediaConnectStatus == WlanMediaStateConnected) {
+
+        tblIdx = wlan_find_ssid_in_list(Adapter,
+                                        &pBSSDesc->Ssid,
+                                        pBSSDesc->MacAddress,
+                                        Adapter->InfrastructureMode);
+
+        dwrq->length = MIN(dwrq->length, pBSSDesc->Ssid.SsidLength);
+        memcpy(extra, &pBSSDesc->Ssid.Ssid, dwrq->length);
+
+    } else {
+        dwrq->length = 0;
+    }
+
+    /* If the current network is in the table, return the table index */
+    if (tblIdx >= 0) {
+        dwrq->flags = (tblIdx + 1) & IW_ENCODE_INDEX;
+    } else {
+        dwrq->flags = 1;
+    }
+
+    LEAVE();
+    return WLAN_STATUS_SUCCESS;
+}
+
+/** 
+ *  @brief Get version 
+ *   
+ *  @param adapter              A pointer to wlan_adapter structure
+ *  @param version		A pointer to version buffer
+ *  @param maxlen		max length of version buffer
+ *  @return 	   		NA
+ */
+void
+get_version(wlan_adapter * adapter, char *version, int maxlen)
+{
+    union
+    {
+        u32 l;
+        u8 c[4];
+    } ver;
+    char fwver[32];
+
+    ENTER();
+
+    ver.l = adapter->FWReleaseNumber;
+    if (ver.c[3] == 0)
+        sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
+    else
+        sprintf(fwver, "%u.%u.%u.p%u",
+                ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+    snprintf(version, maxlen, driver_version, fwver);
+
+    LEAVE();
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wext.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wext.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wext.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wext.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,541 @@
+/** @file wlan_wext.h
+ * @brief This file contains definition for IOCTL call.
+ *  
+ * (c) Copyright © 2003-2007, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+	10/11/05: Add Doxygen format comments
+	12/19/05: Correct a typo in structure _wlan_ioctl_wmm_tspec
+	01/11/06: Conditionalize new scan/join ioctls
+	04/10/06: Add hostcmd generic API
+	04/18/06: Remove old Subscrive Event and add new Subscribe Event
+	          implementation through generic hostcmd API
+	06/08/06: Add definitions of custom events
+	08/29/06: Add ledgpio private command
+********************************************************/
+
+#ifndef	_WLAN_WEXT_H_
+#define	_WLAN_WEXT_H_
+
+/** Offset for subcommand */
+#define SUBCMD_OFFSET			4
+/** PRIVATE CMD ID */
+#define	WLANIOCTL			0x8BE0
+
+/** Private command ID to set WPA IE */
+#define WLANSETWPAIE			(WLANIOCTL + 0)
+/** Private command ID to set CIS dump */
+#define WLANCISDUMP 			(WLANIOCTL + 1)
+#ifdef MFG_CMD_SUPPORT
+#define	WLANMANFCMD			(WLANIOCTL + 2)
+#endif
+/** Private command ID to read/write register */
+#define	WLANREGRDWR			(WLANIOCTL + 3)
+/** Maximum EEPROM data */
+#define MAX_EEPROM_DATA     			256
+/** Private command ID to Host command */
+#define	WLANHOSTCMD			(WLANIOCTL + 4)
+
+/** Private command ID for ARP filter */
+#define WLANARPFILTER			(WLANIOCTL + 6)
+
+/** Private command ID to set/get int */
+#define WLAN_SETINT_GETINT		(WLANIOCTL + 7)
+/** Private command ID to get Noise Floor value */
+#define WLANNF					1
+/** Private command ID to get RSSI */
+#define WLANRSSI				2
+/** Private command ID to set/get BG scan */
+#define WLANBGSCAN				4
+/** Private command ID to enabled 11d support */
+#define WLANENABLE11D				5
+/** Private command ID to set/get AdHoc G rate */
+#define WLANADHOCGRATE				6
+/** Private command ID to set/get SDIO clock */
+#define WLANSDIOCLOCK				7
+/** Private command ID to enable WMM */
+#define WLANWMM_ENABLE				8
+/** Private command ID to set Null packet generation */
+#define WLANNULLGEN				10
+/** Private command ID to set AdHoc */
+#define WLANADHOCCSET				11
+/** Private command ID to set AdHoc G protection */
+#define WLAN_ADHOC_G_PROT			12
+
+/** Private command ID to set/get none */
+#define WLAN_SETNONE_GETNONE	        (WLANIOCTL + 8)
+/** Private command ID to turn on radio */
+#define WLANRADIOON                 		1
+/** Private command ID to turn off radio */
+#define WLANRADIOOFF                		2
+/** Private command ID to Remove AdHoc AES key */
+#define WLANREMOVEADHOCAES          		3
+/** Private command ID to stop AdHoc mode */
+#define WLANADHOCSTOP               		4
+/** Private command ID to set WLAN crypto test */
+#define WLANCRYPTOTEST				6
+#ifdef REASSOCIATION
+/** Private command ID to set reassociation to auto mode */
+#define WLANREASSOCIATIONAUTO			7
+/** Private command ID to set reassociation to user mode */
+#define WLANREASSOCIATIONUSER			8
+#endif /* REASSOCIATION */
+/** Private command ID to turn on wlan idle */
+#define WLANWLANIDLEON				9
+/** Private command ID to turn off wlan idle */
+#define WLANWLANIDLEOFF				10
+
+/** Private command ID to get log */
+#define WLANGETLOG                  	(WLANIOCTL + 9)
+
+/** Private command ID to set/get configurations */
+#define WLAN_SETCONF_GETCONF		(WLANIOCTL + 10)
+
+/** BG scan configuration */
+#define BG_SCAN_CONFIG				1
+/** BG scan configuration */
+#define BG_SCAN_CFG   				3
+/** Calibration data ext configuration */
+#define CAL_DATA_EXT_CONFIG         2
+
+/** Private command ID to set scan type */
+#define WLANSCAN_TYPE			(WLANIOCTL + 11)
+
+/** Private command ID to set a wext address variable */
+#define WLAN_SETADDR_GETNONE  (WLANIOCTL + 12)
+/** Private command ID to send deauthentication */
+#define WLANDEAUTH                  		1
+
+/** Private command ID to set/get 2k */
+#define WLAN_SET_GET_2K         (WLANIOCTL + 13)
+/** Private command ID to start scan */
+#define WLAN_SET_USER_SCAN              1
+/** Private command ID to get the scan table */
+#define WLAN_GET_SCAN_TABLE             2
+/** Private command ID to set Marvell TLV */
+#define WLAN_SET_MRVL_TLV               3
+/** Private command ID to get association response */
+#define WLAN_GET_ASSOC_RSP              4
+/** Private command ID to request ADDTS */
+#define WLAN_ADDTS_REQ                  5
+/** Private command ID to request DELTS */
+#define WLAN_DELTS_REQ                  6
+/** Private command ID to queue configuration */
+#define WLAN_QUEUE_CONFIG               7
+/** Private command ID to queue stats */
+#define WLAN_QUEUE_STATS                8
+/** Private command ID to get CFP table */
+#define WLAN_GET_CFP_TABLE              9
+/** Private command ID to set/get MEF configuration */
+#define WLAN_MEF_CFG                   10
+/** Private command ID to get memory */
+#define WLAN_GET_MEM                   11
+/** Private command ID to get Tx packet stats */
+#define WLAN_TX_PKT_STATS              12
+
+/** Private command ID to set none/get one int */
+#define WLAN_SETNONE_GETONEINT		(WLANIOCTL + 15)
+/** Private command ID to get region */
+#define WLANGETREGION				1
+/** Private command ID to get listen interval */
+#define WLAN_GET_LISTEN_INTERVAL		2
+/** Private command ID to get multiple DTIM */
+#define WLAN_GET_MULTIPLE_DTIM			3
+/** Private command ID to get Tx rate */
+#define WLAN_GET_TX_RATE			4
+/** Private command ID to get beacon average */
+#define	WLANGETBCNAVG				5
+/** Private command ID to get data average */
+#define WLANGETDATAAVG				6
+
+/** Private command ID to set ten characters and get none */
+#define WLAN_SETTENCHAR_GETNONE		(WLANIOCTL + 16)
+/** Private command ID to set band */
+#define WLAN_SET_BAND               		1
+/** Private command ID to set AdHoc channel */
+#define WLAN_SET_ADHOC_CH           		2
+/** Private command ID to set/get SW ann for 11h */
+#define WLAN_11H_CHANSWANN          		3
+
+/** Private command ID to set none and get ten characters */
+#define WLAN_SETNONE_GETTENCHAR		(WLANIOCTL + 17)
+/** Private command ID to get band */
+#define WLAN_GET_BAND				1
+/** Private command ID to get AdHoc channel */
+#define WLAN_GET_ADHOC_CH			2
+
+/** Private command ID to set none/get tewlve chars*/
+#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
+/** Private command ID to get Rx antenna */
+#define WLAN_SUBCMD_GETRXANTENNA    1
+/** Private command ID to get Tx antenna */
+#define WLAN_SUBCMD_GETTXANTENNA    2
+/** Private command ID to get TSF value */
+#define WLAN_GET_TSF                3
+/** Private command ID for WPS session */
+#define WLAN_WPS_SESSION            4
+
+/** Private command ID to set word character and get none */
+#define WLAN_SETWORDCHAR_GETNONE	(WLANIOCTL + 20)
+/** Private command ID to set AdHoc AES */
+#define WLANSETADHOCAES				1
+
+/** Private command ID to set one int/get word char */
+#define WLAN_SETONEINT_GETWORDCHAR	(WLANIOCTL + 21)
+/** Private command ID to get AdHoc AES key */
+#define WLANGETADHOCAES				1
+/** Private command ID to get version */
+#define WLANVERSION				2
+/** Private command ID to get extended version */
+#define WLANVEREXT				3
+
+/** Private command ID to set one int/get one int */
+#define WLAN_SETONEINT_GETONEINT	(WLANIOCTL + 23)
+/** Private command ID to set local power for 11h */
+#define WLAN_11H_SETLOCALPOWER      		1
+/** Private command ID to get WMM QoS information */
+#define WLAN_WMM_QOSINFO			2
+/** Private command ID to set/get listen interval */
+#define	WLAN_LISTENINTRVL			3
+/** Private command ID to set/get firmware wakeup method */
+#define WLAN_FW_WAKEUP_METHOD			4
+/** Firmware wakeup method : Unchanged */
+#define WAKEUP_FW_UNCHANGED			0
+/** Firmware wakeup method : Through interface */
+#define WAKEUP_FW_THRU_INTERFACE		1
+/** Firmware wakeup method : Through GPIO*/
+#define WAKEUP_FW_THRU_GPIO			2
+
+/** Private command ID to set/get NULL packet interval */
+#define WLAN_NULLPKTINTERVAL			5
+/** Private command ID to set/get beacon miss timeout */
+#define WLAN_BCN_MISS_TIMEOUT			6
+/** Private command ID to set/get AdHoc awake period */
+#define WLAN_ADHOC_AWAKE_PERIOD			7
+/** Private command ID to set/get module type */
+#define WLAN_MODULE_TYPE			11
+/** Private command ID to enable/disable auto Deep Sleep */
+#define WLAN_AUTODEEPSLEEP			12
+/** Private command ID to set/get enhance DPS */
+#define WLAN_ENHANCEDPS				13
+/** Private command ID to wake up MT */
+#define WLAN_WAKEUP_MT				14
+
+/** Private command ID to set one int/get none */
+#define WLAN_SETONEINT_GETNONE		(WLANIOCTL + 24)
+/** Private command ID to set Rx antenna */
+#define WLAN_SUBCMD_SETRXANTENNA		1
+/** Private command ID to set Tx antenna */
+#define WLAN_SUBCMD_SETTXANTENNA		2
+/** Private command ID to set authentication algorithm */
+#define WLANSETAUTHALG				4
+/** Private command ID to set encryption mode */
+#define WLANSETENCRYPTIONMODE			5
+/** Private command ID to set region */
+#define WLANSETREGION				6
+/** Private command ID to set listen interval */
+#define WLAN_SET_LISTEN_INTERVAL		7
+
+/** Private command ID to set multiple DTIM */
+#define WLAN_SET_MULTIPLE_DTIM			8
+
+/** Private command ID to set beacon average */
+#define WLANSETBCNAVG				9
+/** Private command ID to set data average */
+#define WLANSETDATAAVG				10
+/** Private command ID to associate */
+#define WLANASSOCIATE				11
+
+/** Private command ID to set 64-bit char/get 64-bit char */
+#define WLAN_SET64CHAR_GET64CHAR	(WLANIOCTL + 25)
+/** Private command ID to set/get sleep parameters */
+#define WLANSLEEPPARAMS 			2
+/** Private command ID to set/get BCA timeshare */
+#define	WLAN_BCA_TIMESHARE			3
+/** Private command ID to request TPC for 11h */
+#define WLAN_11H_REQUESTTPC         		4
+/** Private command ID to set power capabilities */
+#define WLAN_11H_SETPOWERCAP        		5
+/** Private command ID to set/get scan mode */
+#define WLANSCAN_MODE				6
+
+/** Private command ID to get AdHoc status */
+#define WLAN_GET_ADHOC_STATUS			9
+
+/** Private command ID to set generic IE */
+#define WLAN_SET_GEN_IE                 	10
+/** Private command ID to get generic IE */
+#define WLAN_GET_GEN_IE                 	11
+
+/** Private command ID to request MEAS */
+#define WLAN_MEASREQ                    	12
+/** Private command ID to get WMM queue status */
+#define WLAN_WMM_QUEUE_STATUS               13
+/** Private command ID to get Traffic stream status */
+#define WLAN_WMM_TS_STATUS                  14
+
+/** Private command to scan for a specific ESSID */
+#define WLANEXTSCAN			(WLANIOCTL + 26)
+/** Private command ID to set/get Deep Sleep mode */
+#define WLANDEEPSLEEP			(WLANIOCTL + 27)
+/** Deep Sleep enable flag */
+#define DEEP_SLEEP_ENABLE			1
+/** Deep Sleep disable flag */
+#define DEEP_SLEEP_DISABLE  			0
+
+/** Private command ID to set/get sixteen int */
+#define WLAN_SET_GET_SIXTEEN_INT       (WLANIOCTL + 29)
+/** Private command ID to set/get TPC configurations */
+#define WLAN_TPCCFG                             1
+/** Private command ID to set/get LED GPIO control */
+#define WLAN_LED_GPIO_CTRL			5
+/** Private command ID to set the number of probe requests per channel */
+#define WLAN_SCANPROBES 			6
+/** Private command ID to set/get the sleep period */
+#define WLAN_SLEEP_PERIOD			7
+/** Private command ID to set/get the rate set */
+#define	WLAN_ADAPT_RATESET			8
+/** Private command ID to set/get the inactivity timeout */
+#define	WLAN_INACTIVITY_TIMEOUT			9
+/** Private command ID to get the SNR */
+#define WLANSNR					10
+/** Private command ID to get the rate */
+#define WLAN_GET_RATE				11
+/** Private command ID to get Rx information */
+#define	WLAN_GET_RXINFO				12
+/** Private command ID to set the ATIM window */
+#define	WLAN_SET_ATIM_WINDOW			13
+/** Private command ID to set/get the beacon interval */
+#define WLAN_BEACON_INTERVAL			14
+/** Private command ID to set/get SDIO pull */
+#define WLAN_SDIO_PULL_CTRL			15
+/** Private command ID to set/get the scan time */
+#define WLAN_SCAN_TIME				16
+/** Private command ID to set/get ECL system clock */
+#define WLAN_ECL_SYS_CLOCK			17
+/** Private command ID to set/get the Tx control */
+#define WLAN_TXCONTROL				19
+/** Private command ID to set/get Host Sleep configuration */
+#define WLANHSCFG				21
+/** Private command ID to set Host Sleep parameters */
+#define WLANHSSETPARA				22
+/** Private command ID for debug configuration */
+#define WLANDBGSCFG				24
+#ifdef DEBUG_LEVEL1
+/** Private command ID to set/get driver debug */
+#define WLAN_DRV_DBG				25
+#endif
+/** Private command ID to set/get the max packet delay passed from drv to fw */
+#define WLAN_DRV_DELAY_MAX       27
+
+/** Private command ID to read/write Command 52 */
+#define WLANCMD52RDWR			(WLANIOCTL + 30)
+/** Private command ID to read/write Command 53 */
+#define WLANCMD53RDWR			(WLANIOCTL + 31)
+/** Command 53 buffer length */
+#define CMD53BUFLEN				512
+
+/** MAC register */
+#define	REG_MAC					0x19
+/** BBP register */
+#define	REG_BBP					0x1a
+/** RF register */
+#define	REG_RF					0x1b
+/** EEPROM register */
+#define	REG_EEPROM				0x59
+
+/** Command disabled */
+#define	CMD_DISABLED				0
+/** Command enabled */
+#define	CMD_ENABLED				1
+/** Command get */
+#define	CMD_GET					2
+/** Skip command number */
+#define SKIP_CMDNUM				4
+/** Skip type */
+#define SKIP_TYPE				1
+/** Skip size */
+#define SKIP_SIZE				2
+/** Skip action */
+#define SKIP_ACTION				2
+/** Skip type and size */
+#define SKIP_TYPE_SIZE			(SKIP_TYPE + SKIP_SIZE)
+/** Skip type and action */
+#define SKIP_TYPE_ACTION		(SKIP_TYPE + SKIP_ACTION)
+
+/** Maximum size of set/get configurations */
+#define MAX_SETGET_CONF_SIZE		2000    /* less than MRVDRV_SIZE_OF_CMD_BUFFER */
+/** Maximum length of set/get configuration commands */
+#define MAX_SETGET_CONF_CMD_LEN		(MAX_SETGET_CONF_SIZE - SKIP_CMDNUM)
+
+/* define custom events */
+/** Custom event : Host Sleep activated */
+#define CUS_EVT_HS_ACTIVATED		"HS_ACTIVATED "
+/** Custom event : Host Sleep deactivated */
+#define CUS_EVT_HS_DEACTIVATED		"HS_DEACTIVATED "
+/** Custom event : Host Sleep wakeup */
+#define CUS_EVT_HS_WAKEUP		"HS_WAKEUP"
+/** Custom event : Beacon RSSI low */
+#define CUS_EVT_BEACON_RSSI_LOW		"EVENT=BEACON_RSSI_LOW"
+/** Custom event : Beacon SNR low */
+#define CUS_EVT_BEACON_SNR_LOW		"EVENT=BEACON_SNR_LOW"
+/** Custom event : Beacon RSSI high */
+#define CUS_EVT_BEACON_RSSI_HIGH	"EVENT=BEACON_RSSI_HIGH"
+/** Custom event : Beacon SNR high */
+#define CUS_EVT_BEACON_SNR_HIGH		"EVENT=BEACON_SNR_HIGH"
+/** Custom event : Max fail */
+#define CUS_EVT_MAX_FAIL		"EVENT=MAX_FAIL"
+/** Custom event : MIC failure, unicast */
+#define CUS_EVT_MLME_MIC_ERR_UNI	"MLME-MICHAELMICFAILURE.indication unicast "
+/** Custom event : MIC failure, multicast */
+#define CUS_EVT_MLME_MIC_ERR_MUL	"MLME-MICHAELMICFAILURE.indication multicast "
+
+/** Custom event : Data RSSI low */
+#define CUS_EVT_DATA_RSSI_LOW		"EVENT=DATA_RSSI_LOW"
+/** Custom event : Data SNR low */
+#define CUS_EVT_DATA_SNR_LOW		"EVENT=DATA_SNR_LOW"
+/** Custom event : Data RSSI high */
+#define CUS_EVT_DATA_RSSI_HIGH		"EVENT=DATA_RSSI_HIGH"
+/** Custom event : Data SNR high */
+#define CUS_EVT_DATA_SNR_HIGH		"EVENT=DATA_SNR_HIGH"
+
+/** Custom event : Deep Sleep awake */
+#define CUS_EVT_DEEP_SLEEP_AWAKE	"EVENT=DS_AWAKE"
+
+/** Custom event : AdHoc link sensed */
+#define CUS_EVT_ADHOC_LINK_SENSED	"EVENT=ADHOC_LINK_SENSED"
+/** Custom event : AdHoc beacon lost */
+#define CUS_EVT_ADHOC_BCN_LOST		"EVENT=ADHOC_BCN_LOST"
+
+/** wlan_ioctl */
+typedef struct _wlan_ioctl
+{
+        /** Command ID */
+    u16 command;
+        /** data length */
+    u16 len;
+        /** data pointer */
+    u8 *data;
+} wlan_ioctl;
+
+/** wlan_ioctl_rfantenna */
+typedef struct _wlan_ioctl_rfantenna
+{
+    /** Action */
+    u16 Action;
+    /** RF Antenna mode */
+    u16 AntennaMode;
+} wlan_ioctl_rfantenna;
+
+/** wlan_ioctl_regrdwr */
+typedef struct _wlan_ioctl_regrdwr
+{
+        /** Which register to access */
+    u16 WhichReg;
+        /** Read or Write */
+    u16 Action;
+    /** Register offset */
+    u32 Offset;
+    /** NOB */
+    u16 NOB;
+    /** Value */
+    u32 Value;
+} wlan_ioctl_regrdwr;
+
+/** wlan_ioctl_cfregrdwr */
+typedef struct _wlan_ioctl_cfregrdwr
+{
+        /** Read or Write */
+    u8 Action;
+        /** register address */
+    u16 Offset;
+        /** register value */
+    u16 Value;
+} wlan_ioctl_cfregrdwr;
+
+/** wlan_ioctl_adhoc_key_info */
+typedef struct _wlan_ioctl_adhoc_key_info
+{
+    /** Action */
+    u16 action;
+    /** AdHoc key */
+    u8 key[16];
+    /** TKIP Tx MIC */
+    u8 tkiptxmickey[16];
+    /** TKIP Rx MIC */
+    u8 tkiprxmickey[16];
+} wlan_ioctl_adhoc_key_info;
+
+/** sleep_params */
+typedef struct _wlan_ioctl_sleep_params_config
+{
+    /** Action */
+    u16 Action;
+    /** Error */
+    u16 Error;
+    /** Offset */
+    u16 Offset;
+    /** Stable time */
+    u16 StableTime;
+    /** Calibration control */
+    u8 CalControl;
+    /** External sleep clock */
+    u8 ExtSleepClk;
+    /** Reserved */
+    u16 Reserved;
+} __ATTRIB_PACK__ wlan_ioctl_sleep_params_config,
+    *pwlan_ioctl_sleep_params_config;
+
+/** BCA TIME SHARE */
+typedef struct _wlan_ioctl_bca_timeshare_config
+{
+        /** ACT_GET/ACT_SET */
+    u16 Action;
+        /** Type: WLAN, BT */
+    u16 TrafficType;
+        /** Interval: 20msec - 60000msec */
+    u32 TimeShareInterval;
+        /** PTA arbiter time in msec */
+    u32 BTTime;
+} __ATTRIB_PACK__ wlan_ioctl_bca_timeshare_config,
+    *pwlan_ioctl_bca_timeshare_config;
+
+/** Maximum number of CFPs in the list */
+#define MAX_CFP_LIST_NUM	64
+
+/** wlan_ioctl_cfp_table */
+typedef struct _wlan_ioctl_cfp_table
+{
+    /** Region */
+    u32 region;
+    /** CFP number */
+    u32 cfp_no;
+    struct
+    {
+        /** CFP channel */
+        u16 Channel;
+        /** CFP frequency */
+        u32 Freq;
+        /** Maximum Tx power */
+        u16 MaxTxPower;
+        /** Unsupported flag */
+        u8 Unsupported;
+    } cfp[MAX_CFP_LIST_NUM];
+} __ATTRIB_PACK__ wlan_ioctl_cfp_table, *pwlan_ioctl_cfp_table;
+
+#endif /* _WLAN_WEXT_H_ */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.c linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.c
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.c	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,1801 @@
+/** @file wlan_wmm.c
+ * @brief This file contains functions for WMM.
+ *
+ * (c) Copyright © 2003-2006, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available along with the File in the gpl.txt file or by writing to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+/********************************************************
+Change log:
+    10/04/05: Add Doxygen format comments
+    11/11/05: Add support for WMM Status change event
+    01/05/06: Add kernel 2.6.x support
+    01/11/06: Conditionalize new scan/join code modifications.
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+    08/14/07: Support Linux 2.6.22 kernel
+********************************************************/
+#include    "wlan_headers.h"
+
+/********************************************************
+    Local Variables
+********************************************************/
+
+/** Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX   512
+
+/** Upper and Lower threshold for packet queuing in the driver
+ *
+ *    - When the number of packets queued reaches the upper limit,
+ *      the driver will stop the net queue in the app/kernel space.
+ *
+ *    - When the number of packets drops beneath the lower limit after
+ *      having reached the upper limit, the driver will restart the net
+ *      queue.
+ */
+
+/** Lower threshold for packet queuing in the driver.
+ * When the number of packets drops beneath the lower limit after having
+ * reached the upper limit, the driver will restart the net queue.
+ */
+#define WMM_QUEUED_PACKET_LOWER_LIMIT   180
+
+/** Upper threshold for packet queuing in the driver.
+ * When the number of packets queued reaches the upper limit, the driver
+ * will stop the net queue in the app/kernel space.
+ */
+#define WMM_QUEUED_PACKET_UPPER_LIMIT   200
+
+/** Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+static const u8 wmm_info_ie[] = { WMM_IE, 0x07,
+    0x00, 0x50, 0xf2, 0x02,
+    0x00, 0x01, 0x00
+};
+
+/**
+ * AC Priorities go from AC_BK to AC_VO.  The ACI enumeration for AC_BK (1)
+ *   is higher than the enumeration for AC_BE (0); hence the needed
+ *   mapping conversion for wmm AC to priority Queue Index
+ */
+static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
+    WMM_AC_BK,
+    WMM_AC_VI,
+    WMM_AC_VO
+};
+
+/********************************************************
+    Local Functions
+********************************************************/
+#ifdef DEBUG_LEVEL2
+/**
+ *  @brief Debug print function to display the priority parameters for a WMM AC
+ *
+ *  @param pACParam Pointer to the AC paramters to display
+ *
+ *  @return         void
+ */
+static void
+wlan_wmm_ac_debug_print(const IEEEtypes_WmmAcParameters_t * pACParam)
+{
+    const char *acStr[] = { "BK", "BE", "VI", "VO" };
+
+    PRINTM(INFO, "WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+           "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+           acStr[wmm_aci_to_qidx_map[pACParam->AciAifsn.Aci]],
+           pACParam->AciAifsn.Aci, pACParam->AciAifsn.Acm,
+           pACParam->AciAifsn.Aifsn, pACParam->Ecw.EcwMin,
+           pACParam->Ecw.EcwMax, wlan_le16_to_cpu(pACParam->TxopLimit));
+}
+
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pACParam) wlan_wmm_ac_debug_print(pACParam)
+#else
+/** Print the WMM AC for debug purpose */
+#define PRINTM_AC(pACParam)
+#endif
+
+/**
+ *  @brief Compute the difference between two timestamps.
+ *
+ *  @param pTv1 Pointer to timestamp1
+ *  @param pTv2 Pointer to timestamp2
+ *
+ *  @return Time difference in ms between pTv1 and pTv2 (pTv1 - pTv2)
+ */
+static int
+timeval_diff_in_ms(const struct timeval *pTv1, const struct timeval *pTv2)
+{
+    int diff_ms;
+
+    diff_ms = (pTv1->tv_sec - pTv2->tv_sec) * 1000;
+    diff_ms += (pTv1->tv_usec - pTv2->tv_usec) / 1000;
+
+    return diff_ms;
+}
+
+/**
+ *  @brief Set the WMM queue priorities to their default values
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_default_queue_priorities(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    /* default queue priorities: VO->VI->BE->BK */
+    Adapter->wmm.queuePriority[0] = WMM_AC_VO;
+    Adapter->wmm.queuePriority[1] = WMM_AC_VI;
+    Adapter->wmm.queuePriority[2] = WMM_AC_BE;
+    Adapter->wmm.queuePriority[3] = WMM_AC_BK;
+}
+
+/**
+ *  @brief Initialize WMM priority queues
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_setup_queue_priorities(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    IEEEtypes_WmmParameter_t *pWmmIe;
+
+    u16 cwmax, cwmin, avg_back_off, tmp[4];
+    int i, j, numAc, acIdx;
+
+    if (Adapter->wmm.enabled == FALSE) {
+        /* WMM is not enabled, just set the defaults and return */
+        wmm_default_queue_priorities(priv);
+        return;
+    }
+
+    pWmmIe = &Adapter->CurBssParams.BSSDescriptor.wmmIE;
+
+    HEXDUMP("WMM: setup_queue_priorities: param IE",
+            (u8 *) pWmmIe, sizeof(IEEEtypes_WmmParameter_t));
+
+    PRINTM(INFO, "WMM Parameter IE: version=%d, "
+           "QoSInfo Parameter Set Count=%d, Reserved=%#x\n",
+           pWmmIe->VendHdr.Version, pWmmIe->QoSInfo.ParaSetCount,
+           pWmmIe->Reserved);
+
+    for (numAc = 0; numAc < NELEMENTS(pWmmIe->AcParams); numAc++) {
+        cwmax = (1 << pWmmIe->AcParams[numAc].Ecw.EcwMax) - 1;
+        cwmin = (1 << pWmmIe->AcParams[numAc].Ecw.EcwMin) - 1;
+        avg_back_off = (cwmin >> 1) + pWmmIe->AcParams[numAc].AciAifsn.Aifsn;
+
+        acIdx = wmm_aci_to_qidx_map[pWmmIe->AcParams[numAc].AciAifsn.Aci];
+        Adapter->wmm.queuePriority[acIdx] = acIdx;
+        tmp[acIdx] = avg_back_off;
+
+        PRINTM(INFO, "WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+               cwmax, cwmin, avg_back_off);
+        PRINTM_AC(&pWmmIe->AcParams[numAc]);
+    }
+
+    HEXDUMP("WMM: avg_back_off", (u8 *) tmp, sizeof(tmp));
+    HEXDUMP("WMM: queuePriority", Adapter->wmm.queuePriority,
+            sizeof(Adapter->wmm.queuePriority));
+
+    /* bubble sort */
+    for (i = 0; i < numAc; i++) {
+        for (j = 1; j < numAc - i; j++) {
+            if (tmp[j - 1] > tmp[j]) {
+                SWAP_U16(tmp[j - 1], tmp[j]);
+                SWAP_U8(Adapter->wmm.queuePriority[j - 1],
+                        Adapter->wmm.queuePriority[j]);
+            } else if (tmp[j - 1] == tmp[j]) {
+                if (Adapter->wmm.queuePriority[j - 1]
+                    < Adapter->wmm.queuePriority[j]) {
+                    SWAP_U8(Adapter->wmm.queuePriority[j - 1],
+                            Adapter->wmm.queuePriority[j]);
+                }
+            }
+        }
+    }
+
+    HEXDUMP("WMM: avg_back_off, sort", (u8 *) tmp, sizeof(tmp));
+    HEXDUMP("WMM: queuePriority, sort", Adapter->wmm.queuePriority,
+            sizeof(Adapter->wmm.queuePriority));
+}
+
+/**
+ *  @brief pop up the highest skb from wmm queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_pop_highest_prio_skb(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+    u8 ac;
+
+    ENTER();
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        ac = Adapter->wmm.queuePriority[i];
+        if (!list_empty((struct list_head *) &Adapter->wmm.txSkbQ[ac])) {
+            PRINTM(DATA, "WMM: Highest prio pkt in AC Queue %d\n", i);
+            Adapter->CurrentTxSkb = Adapter->wmm.txSkbQ[ac].next;
+            Adapter->wmm.packetsOut[ac]++;
+            list_del((struct list_head *) Adapter->wmm.txSkbQ[ac].next);
+            break;
+        }
+    }
+
+    LEAVE();
+}
+
+/**
+ *  @brief Evaluate whether or not an AC is to be downgraded
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param evalAC   AC to evaluate for downgrading
+ *
+ *  @return WMM AC the evalAC traffic is to be sent on.
+ */
+static wlan_wmm_ac_e
+wmm_eval_downgrade_ac(wlan_private * priv, wlan_wmm_ac_e evalAC)
+{
+    wlan_wmm_ac_e downAC;
+    wlan_wmm_ac_e retAC;
+    WmmAcStatus_t *pACStatus;
+
+    pACStatus = &priv->adapter->wmm.acStatus[evalAC];
+
+    if (pACStatus->Disabled == FALSE) {
+        /* Okay to use this AC, its enabled */
+        return evalAC;
+    }
+
+    /* Setup a default return value of the lowest priority */
+    retAC = WMM_AC_BK;
+
+    /*
+     *  Find the highest AC that is enabled and does not require admission
+     *    control.  The spec disallows downgarding to an AC which is enabled
+     *    due to a completed admission control.  Unadmitted traffic is not
+     *    to be sent on an AC with admitted traffic.
+     */
+    for (downAC = WMM_AC_BK; downAC < evalAC; downAC++) {
+        pACStatus = &priv->adapter->wmm.acStatus[downAC];
+
+        if ((pACStatus->Disabled == FALSE)
+            && (pACStatus->FlowRequired == FALSE)) {
+            /* AC is enabled and does not require admission control */
+            retAC = downAC;
+        }
+    }
+
+    return retAC;
+}
+
+/**
+ *  @brief Downgrade WMM priority queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+static void
+wmm_setup_ac_downgrade(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_wmm_ac_e acVal;
+
+    PRINTM(INFO, "WMM: AC Priorities: BK(0), BE(1), VI(2), VO(3)\n");
+
+    if (Adapter->wmm.enabled == FALSE) {
+        /* WMM is not enabled, default priorities */
+        for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+            for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+                Adapter->wmm.acDowngradedVals[acVal] = acVal;
+            }
+        }
+    } else {
+        for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+            Adapter->wmm.acDowngradedVals[acVal]
+                = wmm_eval_downgrade_ac(priv, acVal);
+            PRINTM(INFO, "WMM: AC PRIO %d maps to %d\n",
+                   acVal, Adapter->wmm.acDowngradedVals[acVal]);
+        }
+    }
+}
+
+/**
+ *  @brief Convert the IP TOS field to an WMM AC Queue assignment
+ *
+ *  @param tos  IP TOS field
+ *
+ *  @return     WMM AC Queue mapping of the IP TOS field
+ */
+wlan_wmm_ac_e
+wmm_convert_tos_to_ac(int tos)
+{
+    u8 tosIdx;
+
+    /* Map of TOS UP values to WMM AC */
+    const wlan_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
+        WMM_AC_BK,
+        WMM_AC_BK,
+        WMM_AC_BE,
+        WMM_AC_VI,
+        WMM_AC_VI,
+        WMM_AC_VO,
+        WMM_AC_VO
+    };
+
+    tosIdx = tos >> IPTOS_OFFSET;
+
+    if (tosIdx >= NELEMENTS(tos_to_ac)) {
+        return WMM_AC_BE;
+    }
+
+    return tos_to_ac[tosIdx];
+}
+
+/**
+ *  @brief  Evaluate a given AC and downgrade it to a lower AC if the
+ *          WMM Parameter IE received from the AP indicates that the AP
+ *          is disabled (due to call admission control (ACM bit)
+ *
+ *  @param priv   Pointer to the wlan_private driver data struct
+ *  @param acVal  AC to evaulate for downgrading
+ *
+ *  @return       Same AC as input if downgrading not required or
+ *                the AC the traffic for the given AC should be downgraded to
+ */
+wlan_wmm_ac_e
+wmm_downgrade_ac(wlan_private * priv, wlan_wmm_ac_e acVal)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    return (Adapter->wmm.acDowngradedVals[acVal]);
+}
+
+/**
+ *  @brief  Map the IP TOS field to a user priority value
+ *
+ *  @param tos  IP TOS field
+ *
+ *  @return     User priority tos input parameter maps to
+ */
+static u8
+wmm_tos_to_priority(u8 tos)
+{
+    u8 tosIdx;
+    const u8 tos_to_priority[] = {
+        /* Priority   DSCP_P2   DSCP_P1  DSCP_P0   WMM_AC   */
+        0x00,                   /*    0         0        0       AC_BE   */
+        0x01,                   /*    0         0        1       AC_BK   */
+        0x02,                   /*    0         1        0       AC_BK   */
+        0x03,                   /*    0         1        1       AC_BE   */
+        0x04,                   /*    1         0        0       AC_VI   */
+        0x05,                   /*    1         0        1       AC_VI   */
+        0x06,                   /*    1         1        0       AC_VO   */
+        0x07                    /*    1         1        1       AC_VO   */
+    };
+
+    tosIdx = tos >> IPTOS_OFFSET;
+
+    if (tosIdx >= NELEMENTS(tos_to_priority)) {
+        return WMM_AC_BE;
+    }
+
+    return tos_to_priority[tosIdx];
+}
+
+/**
+ *  @brief  Process a transfer of a data packet to the firmware from the
+ *          driver queue in order to manipulate flow control in the driver.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_process_fw_iface_tx_xfer_start(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    if (--Adapter->wmm.packetsQueued < WMM_QUEUED_PACKET_LOWER_LIMIT) {
+        PRINTM(DATA, "WMM: FW OS+: %d\n", Adapter->wmm.packetsQueued);
+        os_start_queue(priv);
+    }
+}
+
+/**
+ *  @brief  Process the completion of a data packet transfer to the firmware
+ *          from the driver queue in order to manipulate flow control in the
+ *          driver.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ *
+ */
+void
+wmm_process_fw_iface_tx_xfer_end(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    if (Adapter->wmm.packetsQueued) {
+        PRINTM(DATA, "WMM: FW OS-: %d\n", Adapter->wmm.packetsQueued);
+        os_stop_queue(priv);
+    }
+}
+
+/**
+ *  @brief  Process a transfer of a data packet from the OS to the driver
+ *          queue in order to manipulate flow control in the driver.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_process_app_iface_tx(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    Adapter->wmm.packetsQueued++;
+
+    if ((!priv->wlan_dev.dnld_sent && (Adapter->PSState != PS_STATE_SLEEP))
+        || (Adapter->wmm.packetsQueued >= WMM_QUEUED_PACKET_UPPER_LIMIT)) {
+        PRINTM(DATA, "WMM: APP OS-: %d\n", Adapter->wmm.packetsQueued);
+        os_stop_queue(priv);
+    }
+}
+
+/**
+ *  @brief  Stop the WMM data queues.  Traffic is still accepted from the
+ *          OS until the buffer limits are reached.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_stop_queue(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    PRINTM(DATA, "WMM: Q-: %d\n", Adapter->wmm.packetsQueued);
+    Adapter->wmm.queueStopped = TRUE;
+}
+
+/**
+ *  @brief  Start/re-start the WMM data queues and indicate to the OS layer
+ *          that data is being accepted again.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      void
+ */
+void
+wmm_start_queue(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    PRINTM(DATA, "WMM: Q+: %d\n", Adapter->wmm.packetsQueued);
+    Adapter->wmm.queueStopped = FALSE;
+    if (Adapter->wmm.packetsQueued) {
+        wake_up_interruptible(&priv->MainThread.waitQ);
+    }
+}
+
+/**
+ *  @brief  Query the status of the WMM queues.  Determine if the driver data
+ *          path is active or not.
+ *
+ *  @param priv  Pointer to the wlan_private driver data struct
+ *
+ *  @return      TRUE if WMM queues have been stopped, FALSE if still active
+ */
+int
+wmm_is_queue_stopped(wlan_private * priv)
+{
+    return (priv->adapter->wmm.queueStopped == TRUE);
+}
+
+/**
+ *  @brief Initialize the WMM state information and the WMM data path queues.
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+void
+wmm_init(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int i;
+
+    memset(&Adapter->wmm, 0x00, sizeof(Adapter->wmm));
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        INIT_LIST_HEAD((struct list_head *) &Adapter->wmm.txSkbQ[i]);
+    }
+
+    Adapter->wmm.required = FALSE;
+
+    Adapter->gen_null_pkg = TRUE;       /* Enable NULL Pkg generation */
+}
+
+/**
+ *  @brief Setup the queue priorities and downgrade any queues as required
+ *         by the WMM info.  Setups default values if WMM is not active
+ *         for this association.
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+void
+wmm_setup_queues(wlan_private * priv)
+{
+    wmm_setup_queue_priorities(priv);
+    wmm_setup_ac_downgrade(priv);
+}
+
+/**
+ *  @brief implement WMM enable command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param wrq      Pointer to user data
+ *
+ *  @return         WLAN_STATUS_SUCCESS if success; otherwise <0
+ */
+int
+wlan_wmm_enable_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+
+    ENTER();
+
+    switch (*((int *) (wrq->u.name + SUBCMD_OFFSET))) {
+
+    case CMD_DISABLED:         /* disable */
+        Adapter->wmm.required = FALSE;
+        break;
+
+    case CMD_ENABLED:          /* enable */
+        Adapter->wmm.required = TRUE;
+        break;
+
+    case CMD_GET:
+        break;
+
+    default:
+        PRINTM(INFO, "Invalid option\n");
+        return -EINVAL;
+    }
+
+    *(int *) wrq->u.name = Adapter->wmm.required;
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Application API to set/get the maximum driver queue delay 
+ *         used in the firmware for computing packet lifetime expiry.
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param wrq      Pointer to user data
+ *
+ *  @return         WLAN_STATUS_SUCCESS if success; otherwise <0
+ */
+int
+wlan_wmm_drv_delay_max_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    int ret;
+    int data;
+
+    ENTER();
+
+    ret = WLAN_STATUS_SUCCESS;
+
+    if (wrq->u.data.length > 1) {
+        ret = -ENOTSUPP;
+    }
+
+    if (wrq->u.data.length == 1) {
+        /* Set */
+        if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+            PRINTM(INFO, "Copy from user failed\n");
+            ret = -EFAULT;
+        } else if (data > DRV_PKT_DELAY_TO_FW_MAX) {
+            ret = -EINVAL;
+        } else {
+            Adapter->wmm.drvPktDelayMax = data;
+        }
+    }
+
+    if (copy_to_user(wrq->u.data.pointer,
+                     &Adapter->wmm.drvPktDelayMax, sizeof(int))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        ret = -EFAULT;
+    }
+
+    wrq->u.data.length = 1;
+
+    LEAVE();
+    return ret;
+}
+
+/**
+ *  @brief Implement cmd HostCmd_CMD_WMM_GET_STATUS
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      Pointer to CMD buffer
+ *  @param InfoBuf  Pointer to cmd data
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_get_status(wlan_private * priv,
+                        HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    PRINTM(INFO, "WMM: WMM_GET_STATUS cmd sent\n");
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+    cmd->Size =
+        wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_GET_STATUS) + S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief  Send a command to firmware to retrieve the current WMM status
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE
+ */
+int
+wlan_cmd_wmm_status_change(wlan_private * priv)
+{
+    return wlan_prepare_cmd(priv, HostCmd_CMD_WMM_GET_STATUS, 0, 0, 0, NULL);
+}
+
+/**
+ *  @brief Check if wmm TX queue is empty
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         FALSE if not empty; TRUE if empty
+ */
+int
+wmm_lists_empty(wlan_private * priv)
+{
+    int i;
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        if (!list_empty((struct list_head *) &priv->adapter->wmm.txSkbQ[i])) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/**
+ *  @brief Cleanup wmm TX queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *
+ *  @return         void
+ */
+void
+wmm_cleanup_queues(wlan_private * priv)
+{
+    int i;
+    struct sk_buff *delNode, *Q;
+
+    ENTER();
+
+    for (i = 0; i < MAX_AC_QUEUES; i++) {
+        Q = &priv->adapter->wmm.txSkbQ[i];
+
+        while (!list_empty((struct list_head *) Q)) {
+            delNode = Q->next;
+            list_del((struct list_head *) delNode);
+            kfree_skb(delNode);
+        }
+    }
+
+    priv->adapter->wmm.packetsQueued = 0;
+
+    LEAVE();
+}
+
+/**
+ *  @brief Add skb to WMM queue
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param skb      Pointer to sk_buff
+ *
+ *  @return         void
+ */
+void
+wmm_map_and_add_skb(wlan_private * priv, struct sk_buff *skb)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    struct ethhdr *eth;
+    struct timeval tstamp;
+    u8 tos;
+    wlan_wmm_ac_e ac;
+    wlan_wmm_ac_e ac_down;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+    struct iphdr *iph;
+#endif
+    eth = (struct ethhdr *) skb->data;
+
+    switch (eth->h_proto) {
+    case __constant_htons(ETH_P_IP):
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+        iph = ip_hdr(skb);
+        tos = IPTOS_PREC(iph->tos);
+#else
+        tos = IPTOS_PREC(skb->nh.iph->tos);
+#endif
+        PRINTM(DATA, "packet type ETH_P_IP: %04x, tos=%#x prio=%#x\n",
+               eth->h_proto, tos, skb->priority);
+        break;
+    case __constant_htons(ETH_P_ARP):
+        PRINTM(DATA, "ARP packet %04x\n", eth->h_proto);
+    default:
+        tos = 0;
+        break;
+    }
+
+    ac = wmm_convert_tos_to_ac(tos);
+    ac_down = wmm_downgrade_ac(priv, ac);
+
+    skb->priority = wmm_tos_to_priority(tos);
+    PRINTM(DATA, "wmm_map: tos=%#x, ac=%#x ac_down=%#x, priority=%#x\n",
+           tos, ac, ac_down, skb->priority);
+
+    list_add_tail((struct list_head *) skb,
+                  (struct list_head *) &Adapter->wmm.txSkbQ[ac_down]);
+
+    wmm_process_app_iface_tx(priv);
+
+    /* Record the current time the packet was queued; used to determine
+     *   the amount of time the packet was queued in the driver before it
+     *   was sent to the firmware.  The delay is then sent along with the
+     *   packet to the firmware for aggregate delay calculation for stats
+     *   and MSDU lifetime expiry.
+     */
+    do_gettimeofday(&tstamp);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+    skb->tstamp = timeval_to_ktime(tstamp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+    skb_set_timestamp(skb, &tstamp);
+#else
+    memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp));
+#endif
+}
+
+/**
+ *  @brief Process the GET_WMM_STATUS command response from firmware
+ *
+ *  The GET_WMM_STATUS command returns multiple TLVs for:
+ *      - Each AC Queue status
+ *      - Current WMM Parameter IE
+ *
+ *  This function parses the TLVs and then calls further functions
+ *   to process any changes in the queue prioritization or state.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer including TLVs
+ *                 TLVs for each queue and the WMM Parameter IE.
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmdresp_wmm_get_status(wlan_private * priv,
+                            const HostCmd_DS_COMMAND * resp)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    u8 *pCurrent = (u8 *) & resp->params.getWmmStatus;
+    u32 respLen = resp->Size;
+    int valid = TRUE;
+    int enableData = TRUE;
+
+    MrvlIEtypes_Data_t *pTlvHdr;
+    MrvlIEtypes_WmmQueueStatus_t *pTlvWmmQStatus;
+    IEEEtypes_WmmParameter_t *pWmmParamIe;
+    WmmAcStatus_t *pACStatus;
+
+    PRINTM(INFO, "WMM: WMM_GET_STATUS cmdresp received: %d\n", respLen);
+    HEXDUMP("CMD_RESP: WMM_GET_STATUS", pCurrent, respLen);
+
+    while ((respLen >= sizeof(pTlvHdr->Header)) && valid) {
+        pTlvHdr = (MrvlIEtypes_Data_t *) pCurrent;
+        pTlvHdr->Header.Len = wlan_le16_to_cpu(pTlvHdr->Header.Len);
+
+        switch (wlan_le16_to_cpu(pTlvHdr->Header.Type)) {
+        case TLV_TYPE_WMMQSTATUS:
+            pTlvWmmQStatus = (MrvlIEtypes_WmmQueueStatus_t *) pTlvHdr;
+            PRINTM(INFO,
+                   "CMD_RESP: WMM_GET_STATUS: QSTATUS TLV: %d, %d, %d\n",
+                   pTlvWmmQStatus->QueueIndex, pTlvWmmQStatus->FlowRequired,
+                   pTlvWmmQStatus->Disabled);
+
+            pACStatus = &Adapter->wmm.acStatus[pTlvWmmQStatus->QueueIndex];
+            pACStatus->Disabled = pTlvWmmQStatus->Disabled;
+            pACStatus->FlowRequired = pTlvWmmQStatus->FlowRequired;
+            pACStatus->FlowCreated = pTlvWmmQStatus->FlowCreated;
+            break;
+
+        case WMM_IE:
+            /*
+             * Point the regular IEEE IE 2 bytes into the Marvell IE
+             *   and setup the IEEE IE type and length byte fields
+             */
+
+            HEXDUMP("WMM: WMM TLV:", (u8 *) pTlvHdr, pTlvHdr->Header.Len + 4);
+
+            pWmmParamIe = (IEEEtypes_WmmParameter_t *) (pCurrent + 2);
+            pWmmParamIe->VendHdr.Len = pTlvHdr->Header.Len;
+            pWmmParamIe->VendHdr.ElementId = WMM_IE;
+
+            PRINTM(INFO, "CMD_RESP: WMM_GET_STATUS: WMM Parameter Set: %d\n",
+                   pWmmParamIe->QoSInfo.ParaSetCount);
+
+            memcpy((u8 *) & Adapter->CurBssParams.BSSDescriptor.wmmIE,
+                   pWmmParamIe, pWmmParamIe->VendHdr.Len + 2);
+
+            break;
+
+        default:
+            valid = FALSE;
+            break;
+        }
+
+        pCurrent += (pTlvHdr->Header.Len + sizeof(pTlvHdr->Header));
+        respLen -= (pTlvHdr->Header.Len + sizeof(pTlvHdr->Header));
+    }
+
+    wmm_setup_queue_priorities(priv);
+    wmm_setup_ac_downgrade(priv);
+
+    if (enableData) {
+        wmm_start_queue(priv);
+        os_carrier_on(priv);
+        os_start_queue(priv);
+    }
+
+    send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Call back from the command module to allow insertion of a WMM TLV
+ *
+ *  If the BSS we are associating to supports WMM, add the required WMM
+ *    Information IE to the association request command buffer in the form
+ *    of a Marvell extended IEEE IE.
+ *
+ *  @param priv        Pointer to the wlan_private driver data struct
+ *  @param ppAssocBuf  Output parameter: Pointer to the TLV output buffer,
+ *                     modified on return to point after the appended WMM TLV
+ *  @param pWmmIE      Pointer to the WMM IE for the BSS we are joining
+ *
+ *  @return Length of data appended to the association tlv buffer
+ */
+u32
+wlan_wmm_process_association_req(wlan_private * priv,
+                                 u8 ** ppAssocBuf,
+                                 IEEEtypes_WmmParameter_t * pWmmIE)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    MrvlIEtypes_WmmParamSet_t *pWmmTlv;
+    u32 retLen = 0;
+
+    /* Null checks */
+    if (ppAssocBuf == 0)
+        return 0;
+    if (*ppAssocBuf == 0)
+        return 0;
+    if (pWmmIE == 0)
+        return 0;
+
+    PRINTM(INFO, "WMM: process assoc req: bss->wmmIe=%x\n",
+           pWmmIE->VendHdr.ElementId);
+
+    if (Adapter->wmm.required && pWmmIE->VendHdr.ElementId == WMM_IE) {
+        pWmmTlv = (MrvlIEtypes_WmmParamSet_t *) * ppAssocBuf;
+        pWmmTlv->Header.Type = (u16) wmm_info_ie[0];
+        pWmmTlv->Header.Type = wlan_cpu_to_le16(pWmmTlv->Header.Type);
+        pWmmTlv->Header.Len = (u16) wmm_info_ie[1];
+        pWmmTlv->Header.Len = wlan_cpu_to_le16(pWmmTlv->Header.Len);
+
+        memcpy(pWmmTlv->WmmIE, &wmm_info_ie[2], pWmmTlv->Header.Len);
+#define QOS_INFO_PARA_MASK 0x0f
+        if (pWmmIE->QoSInfo.QosUAPSD
+            && ((Adapter->wmm.qosinfo & QOS_INFO_PARA_MASK) != 0)) {
+            memcpy((u8 *) (pWmmTlv->WmmIE + pWmmTlv->Header.Len
+                           - sizeof(Adapter->wmm.qosinfo)),
+                   &Adapter->wmm.qosinfo, sizeof(Adapter->wmm.qosinfo));
+        }
+        retLen = sizeof(pWmmTlv->Header) + pWmmTlv->Header.Len;
+
+        HEXDUMP("ASSOC_CMD: WMM IE", (u8 *) pWmmTlv, retLen);
+        *ppAssocBuf += retLen;
+    }
+
+    return retLen;
+}
+
+/**
+ *   @brief Compute the time delay in the driver queues for a given skb.
+ *
+ *   When the skb is received at the OS/Driver interface, the current
+ *     time is set in the skb structure.  The difference between the present
+ *     time and that received time is computed in this function and limited
+ *     based on pre-compiled limits in the driver.
+ *
+ *   @param skb  Pointer to a sk_buff which has been previously timestamped
+ *
+ *   @return Time delay of the packet in 2ms units after having limit applied
+ */
+u8
+wmm_compute_driver_packet_delay(wlan_private * priv,
+                                const struct sk_buff * skb)
+{
+    u8 retVal;
+    struct timeval in_tv;
+    struct timeval out_tv;
+    int queue_delay;
+
+    retVal = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+    skb_get_timestamp(skb, &in_tv);
+#else
+    memcpy(&in_tv, &skb->stamp, sizeof(in_tv));
+#endif
+    do_gettimeofday(&out_tv);
+
+    queue_delay = timeval_diff_in_ms(&out_tv, &in_tv);
+
+    /* Queue delay is passed as a uint8 in units of 2ms (ms shifted
+     *  by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+     *
+     * Pass max value if queue_delay is beyond the uint8 range
+     */
+    retVal = MIN(queue_delay, priv->adapter->wmm.drvPktDelayMax) >> 1;
+
+    PRINTM(DATA, "WMM: Pkt Delay: %d ms, %d ms sent to FW\n",
+           queue_delay, retVal);
+
+    return retVal;
+}
+
+/**
+ *  @brief Transmit the highest priority packet awaiting in the WMM Queues
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *
+ *  @return        void
+ */
+void
+wmm_process_tx(wlan_private * priv)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    ulong flags;
+
+    OS_INTERRUPT_SAVE_AREA;
+
+    ENTER();
+
+    if ((Adapter->PSState == PS_STATE_SLEEP)
+        || (Adapter->PSState == PS_STATE_PRE_SLEEP)) {
+        PRINTM(INFO, "In PS State %d"
+               " - Not sending the packet\n", Adapter->PSState);
+        LEAVE();
+
+        return;
+    }
+
+    spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
+
+    if (priv->wlan_dev.dnld_sent) {
+        spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+
+        LEAVE();
+
+        return;
+    }
+
+    UpdateTransStart(priv->wlan_dev.netdev);
+    wmm_pop_highest_prio_skb(priv);
+
+    spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
+
+    if (Adapter->CurrentTxSkb) {
+        wlan_process_tx(priv);
+    }
+
+    LEAVE();
+}
+
+/**
+ *  @brief Private IOCTL entry to get the status of the WMM queues
+ *
+ *  Return the following information for each WMM AC:
+ *        - WMM IE Acm Required
+ *        - Firmware Flow Required
+ *        - Firmware Flow Established
+ *        - Firmware Queue Enabled
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_queue_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_adapter *Adapter = priv->adapter;
+    wlan_ioctl_wmm_queue_status_t qstatus;
+    wlan_wmm_ac_e acVal;
+    WmmAcStatus_t *pACStatus;
+    IEEEtypes_WmmAcParameters_t *pWmmIeAC;
+
+    for (acVal = WMM_AC_BK; acVal <= WMM_AC_VO; acVal++) {
+        pACStatus = &Adapter->wmm.acStatus[acVal];
+        pWmmIeAC = &Adapter->CurBssParams.BSSDescriptor.wmmIE.AcParams[acVal];
+
+        /* Acm bit */
+        qstatus.acStatus[acVal].wmmAcm = pWmmIeAC->AciAifsn.Acm;
+
+        /* Firmware status */
+        qstatus.acStatus[acVal].flowRequired = pACStatus->FlowRequired;
+        qstatus.acStatus[acVal].flowCreated = pACStatus->FlowCreated;
+        qstatus.acStatus[acVal].disabled = pACStatus->Disabled;
+    }
+
+    if (copy_to_user(wrq->u.data.pointer, &qstatus, sizeof(qstatus))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to get the status of the WMM Traffic Streams
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_status_t struct for request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_ts_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_ts_status_t ts_status_ioctl;
+    wlan_cmd_wmm_ts_status_t ts_status_cmd;
+    int retcode;
+
+    if (copy_from_user(&ts_status_ioctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length,
+                           sizeof(ts_status_ioctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "WMM: TS Status: copy from user failed\n");
+        retcode = -EFAULT;
+    }
+
+    memset(&ts_status_cmd, 0x00, sizeof(ts_status_cmd));
+    ts_status_cmd.tid = ts_status_ioctl.tid;
+
+    retcode = wlan_prepare_cmd(priv,
+                               HostCmd_CMD_WMM_TS_STATUS, 0,
+                               HostCmd_OPTION_WAITFORRSP, 0, &ts_status_cmd);
+
+    if (retcode) {
+        return -EFAULT;
+    }
+
+    memcpy(&ts_status_ioctl, &ts_status_cmd, sizeof(ts_status_ioctl));
+
+    if (copy_to_user(wrq->u.data.pointer,
+                     &ts_status_ioctl, sizeof(ts_status_ioctl))) {
+        PRINTM(INFO, "Copy to user failed\n");
+        return -EFAULT;
+    }
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to send an ADDTS TSPEC
+ *
+ *  Receive a ADDTS command from the application.  The command structure
+ *    contains a TSPEC and timeout in milliseconds.  The timeout is performed
+ *    in the firmware after the ADDTS command frame is sent.
+ *
+ *  The TSPEC is received in the API as an opaque block whose length is
+ *    calculated from the IOCTL data length.  The firmware will send the
+ *    entire data block, including the bytes after the TSPEC.  This is done
+ *    to allow extra IEs to be packaged with the TSPEC in the ADDTS action
+ *    frame.
+ *
+ *  The IOCTL structure contains two return fields:
+ *    - The firmware command result which indicates failure and timeouts
+ *    - The IEEE Status code which contains the corresponding value from
+ *      any ADDTS response frame received.
+ *
+ *  In addition, the opaque TSPEC data block passed in is replaced with the
+ *    TSPEC recieved in the ADDTS response frame.  In case of failure, the
+ *    AP may modify the TSPEC on return and in the case of success, the
+ *    medium time is returned as calculated by the AP.  Along with the TSPEC,
+ *    any IEs that are sent in the ADDTS response are also returned and can be
+ *    parsed using the IOCTL length as an indicator of extra elements.
+ *
+ *  The return value to the application layer indicates a driver execution
+ *    success or failure.  A successful return could still indicate a firmware
+ *    failure or AP negotiation failure via the commandResult field copied
+ *    back to the application.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_addts_req_t struct for this ADDTS request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_addts_req_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    static int dialogTok = 0;
+    wlan_ioctl_wmm_addts_req_t addtsIoctl;
+    wlan_cmd_wmm_addts_req_t addtsCmd;
+    int retcode;
+
+    if (copy_from_user(&addtsIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(addtsIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "TSPEC: ADDTS copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memset(&addtsCmd, 0x00, sizeof(addtsCmd));
+        addtsCmd.dialogToken = ++dialogTok;
+        addtsCmd.timeout_ms = addtsIoctl.timeout_ms;
+        addtsCmd.tspecDataLen = (wrq->u.data.length
+                                 - sizeof(addtsCmd.timeout_ms)
+                                 - sizeof(addtsCmd.commandResult)
+                                 - sizeof(addtsCmd.ieeeStatusCode));
+        memcpy(addtsCmd.tspecData,
+               addtsIoctl.tspecData, addtsCmd.tspecDataLen);
+
+        retcode = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_WMM_ADDTS_REQ, 0,
+                                   HostCmd_OPTION_WAITFORRSP, 0, &addtsCmd);
+
+        wrq->u.data.length = (sizeof(addtsIoctl.timeout_ms)
+                              + sizeof(addtsIoctl.commandResult)
+                              + sizeof(addtsIoctl.ieeeStatusCode)
+                              + addtsCmd.tspecDataLen);
+
+        addtsIoctl.commandResult = addtsCmd.commandResult;
+        addtsIoctl.ieeeStatusCode = addtsCmd.ieeeStatusCode;
+        memcpy(addtsIoctl.tspecData,
+               addtsCmd.tspecData, addtsCmd.tspecDataLen);
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         &addtsIoctl, sizeof(addtsIoctl))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+
+        if (retcode) {
+            return -EFAULT;
+        }
+    }
+
+    return retcode;
+}
+
+/**
+ *  @brief Private IOCTL entry to send a DELTS TSPEC
+ *
+ *  Receive a DELTS command from the application.  The command structure
+ *    contains a TSPEC and reason code along with space for a command result
+ *    to be returned.  The information is packaged is sent to the wlan_cmd.c
+ *    firmware command prep and send routines for execution in the firmware.
+ *
+ *  The reason code is not used for WMM implementations but is indicated in
+ *    the 802.11e specification.
+ *
+ *  The return value to the application layer indicates a driver execution
+ *    success or failure.  A successful return could still indicate a firmware
+ *    failure via the commandResult field copied back to the application.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_delts_req_t struct for this DELTS request
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_delts_req_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_delts_req_t deltsIoctl;
+    wlan_cmd_wmm_delts_req_t deltsCmd;
+    int retcode;
+
+    if (copy_from_user(&deltsIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length, sizeof(deltsIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "TSPEC: DELTS copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memset(&deltsCmd, 0x00, sizeof(deltsCmd));
+
+        /* Dialog token unused for WMM implementations */
+        deltsCmd.dialogToken = 0;
+
+        deltsCmd.ieeeReasonCode = deltsIoctl.ieeeReasonCode;
+
+        /* Calculate the length of the TSPEC and any other IEs */
+        deltsCmd.tspecDataLen = (wrq->u.data.length
+                                 - sizeof(deltsCmd.commandResult)
+                                 - sizeof(deltsCmd.ieeeReasonCode));
+        memcpy(deltsCmd.tspecData,
+               deltsIoctl.tspecData, deltsCmd.tspecDataLen);
+
+        /* Send the DELTS request to firmware, wait for a response */
+        retcode = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_WMM_DELTS_REQ, 0,
+                                   HostCmd_OPTION_WAITFORRSP, 0, &deltsCmd);
+
+        /* Return the firmware command result back to the application layer */
+        deltsIoctl.commandResult = deltsCmd.commandResult;
+
+        if (copy_to_user(wrq->u.data.pointer,
+                         &deltsCmd,
+                         MIN(wrq->u.data.length, sizeof(deltsIoctl)))) {
+            PRINTM(INFO, "Copy to user failed\n");
+            return -EFAULT;
+        }
+
+        if (retcode) {
+            retcode = -EFAULT;
+        }
+    }
+
+    return retcode;
+}
+
+/**
+ *  @brief Process the ADDTS_REQ command response from firmware
+ *
+ *  Return the ADDTS firmware response to the calling thread that sent
+ *    the command.  The result is then relayed back the app layer.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer including the
+ *                 command result and any returned ADDTS response TSPEC
+ *                 elements
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ */
+int
+wlan_cmdresp_wmm_addts_req(wlan_private * priv,
+                           const HostCmd_DS_COMMAND * resp)
+{
+    wlan_cmd_wmm_addts_req_t *pAddTsCmd;
+    const HostCmd_DS_WMM_ADDTS_REQ *pCmdResp;
+
+    /* Cast the NULL pointer of the buffer the IOCTL sent in the command req */
+    pAddTsCmd = (wlan_cmd_wmm_addts_req_t *) priv->adapter->CurCmd->pdata_buf;
+
+    /* Convenience variable for the ADDTS response from the firmware */
+    pCmdResp = &resp->params.addTsReq;
+
+    /* Assign return data */
+    pAddTsCmd->commandResult = pCmdResp->commandResult;
+    pAddTsCmd->dialogToken = pCmdResp->dialogToken;
+    pAddTsCmd->ieeeStatusCode = pCmdResp->ieeeStatusCode;
+
+    if (pCmdResp->commandResult == TSPEC_RESULT_SUCCESS) {
+        /* The tspecData field is potentially variable in size due to extra IEs
+         *   that may have been in the ADDTS response action frame.  Calculate
+         *   the data length from the firmware command response.
+         */
+        pAddTsCmd->tspecDataLen = (resp->Size
+                                   - sizeof(pCmdResp->commandResult)
+                                   - sizeof(pCmdResp->timeout_ms)
+                                   - sizeof(pCmdResp->dialogToken)
+                                   - sizeof(pCmdResp->ieeeStatusCode)
+                                   - S_DS_GEN);
+
+        /* Copy the TSPEC data include any extra IEs after the TSPEC */
+        memcpy(pAddTsCmd->tspecData,
+               pCmdResp->tspecData,
+               MIN(pAddTsCmd->tspecDataLen, sizeof(pAddTsCmd->tspecData)
+                   + sizeof(pAddTsCmd->addtsExtraIEBuf)));
+    } else {
+        pAddTsCmd->tspecDataLen = 0;
+    }
+
+    PRINTM(INFO, "TSPEC: ADDTS ret = %d,%d sz=%d\n",
+           pAddTsCmd->commandResult, pAddTsCmd->ieeeStatusCode,
+           pAddTsCmd->tspecDataLen);
+
+    HEXDUMP("TSPEC: ADDTS data",
+            pAddTsCmd->tspecData, pAddTsCmd->tspecDataLen);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the DELTS_REQ command response from firmware
+ *
+ *  Return the DELTS firmware response to the calling thread that sent
+ *    the command.  The result is then relayed back the app layer.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer with the command
+ *                 result.  No other response information is passed back
+ *                 to the driver.
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ */
+int
+wlan_cmdresp_wmm_delts_req(wlan_private * priv,
+                           const HostCmd_DS_COMMAND * resp)
+{
+    wlan_cmd_wmm_delts_req_t *pDelTsCmd;
+
+    /* Cast the NULL pointer of the buffer the IOCTL sent in the command req */
+    pDelTsCmd = (wlan_cmd_wmm_delts_req_t *) priv->adapter->CurCmd->pdata_buf;
+
+    pDelTsCmd->commandResult
+        = wlan_le16_to_cpu(resp->params.delTsReq.commandResult);
+
+    PRINTM(INFO, "TSPEC: DELTS result = %d\n", pDelTsCmd->commandResult);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Implement cmd HostCmd_DS_WMM_ADDTS_REQ
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param cmd     Pointer to CMD buffer
+ *  @param InfoBuf Pointer to cmd data
+ *
+ *  @return        WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_addts_req_ioctl
+ */
+int
+wlan_cmd_wmm_addts_req(wlan_private * priv,
+                       HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    wlan_cmd_wmm_addts_req_t *pAddTsCmd;
+    int tspecCopySize;
+
+    pAddTsCmd = (wlan_cmd_wmm_addts_req_t *) InfoBuf;
+
+    cmd->params.addTsReq.timeout_ms = pAddTsCmd->timeout_ms;
+    cmd->params.addTsReq.dialogToken = pAddTsCmd->dialogToken;
+
+    tspecCopySize = MIN(pAddTsCmd->tspecDataLen,
+                        sizeof(cmd->params.addTsReq.tspecData));
+    memcpy(&cmd->params.addTsReq.tspecData,
+           pAddTsCmd->tspecData, tspecCopySize);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_ADDTS_REQ);
+    cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.addTsReq.dialogToken)
+                                 + sizeof(cmd->params.addTsReq.timeout_ms)
+                                 + sizeof(cmd->params.addTsReq.commandResult)
+                                 + sizeof(cmd->params.addTsReq.ieeeStatusCode)
+                                 + tspecCopySize + S_DS_GEN);
+
+    cmd->params.addTsReq.timeout_ms
+        = wlan_cpu_to_le32(cmd->params.addTsReq.timeout_ms);
+
+    PRINTM(INFO, "WMM: ADDTS Cmd: Data Len = %d\n", pAddTsCmd->tspecDataLen);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Implement cmd HostCmd_DS_WMM_DELTS_REQ
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      Pointer to CMD buffer
+ *  @param InfoBuf  Void pointer cast of a wlan_cmd_wmm_delts_req_t struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_delts_req_ioctl
+ */
+int
+wlan_cmd_wmm_delts_req(wlan_private * priv,
+                       HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    wlan_cmd_wmm_delts_req_t *pDelTsCmd;
+    int tspecCopySize;
+
+    pDelTsCmd = (wlan_cmd_wmm_delts_req_t *) InfoBuf;
+
+    cmd->params.delTsReq.dialogToken = pDelTsCmd->dialogToken;
+    cmd->params.delTsReq.ieeeReasonCode = pDelTsCmd->ieeeReasonCode;
+
+    tspecCopySize = MIN(pDelTsCmd->tspecDataLen,
+                        sizeof(cmd->params.delTsReq.tspecData));
+    memcpy(&cmd->params.delTsReq.tspecData,
+           pDelTsCmd->tspecData, tspecCopySize);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_DELTS_REQ);
+    cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.delTsReq.dialogToken)
+                                 + sizeof(cmd->params.delTsReq.commandResult)
+                                 + sizeof(cmd->params.delTsReq.ieeeReasonCode)
+                                 + tspecCopySize + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: DELTS Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Prepare the firmware command buffer for the WMM_QUEUE_CONFIG command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      Pointer to CMD buffer
+ *  @param InfoBuf  Void pointer cast of a wlan_cmd_wmm_queue_config_t struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_queue_config(wlan_private * priv,
+                          HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    wlan_cmd_wmm_queue_config_t *pQConfigCmd;
+    int tlvCopySize;
+
+    pQConfigCmd = (wlan_cmd_wmm_queue_config_t *) InfoBuf;
+
+    cmd->params.queueConfig.action = pQConfigCmd->action;
+    cmd->params.queueConfig.accessCategory = pQConfigCmd->accessCategory;
+    cmd->params.queueConfig.msduLifetimeExpiry
+        = wlan_cpu_to_le16(pQConfigCmd->msduLifetimeExpiry);
+
+    tlvCopySize = MIN(pQConfigCmd->tlvBufLen,
+                      sizeof(cmd->params.queueConfig.tlvBuffer));
+    memcpy(&cmd->params.queueConfig.tlvBuffer,
+           pQConfigCmd->tlvBuffer, tlvCopySize);
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_CONFIG);
+    cmd->Size = wlan_cpu_to_le16(sizeof(cmd->params.queueConfig.action)
+                                 +
+                                 sizeof(cmd->params.queueConfig.
+                                        accessCategory)
+                                 +
+                                 sizeof(cmd->params.queueConfig.
+                                        msduLifetimeExpiry)
+                                 + tlvCopySize + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: QUEUE CONFIG Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the WMM_QUEUE_CONFIG command response from firmware
+ *
+ *  Return the firmware command response to the blocked IOCTL caller function.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer with:
+ *                      - action code
+ *                      - access category
+ *                      - collected statistics if requested
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_queue_config_ioctl
+ */
+int
+wlan_cmdresp_wmm_queue_config(wlan_private * priv,
+                              const HostCmd_DS_COMMAND * resp)
+{
+    wlan_cmd_wmm_queue_config_t *pQConfigCmd;
+    const HostCmd_DS_WMM_QUEUE_CONFIG *pCmdResp;
+
+    pQConfigCmd =
+        (wlan_cmd_wmm_queue_config_t *) (priv->adapter->CurCmd->pdata_buf);
+    pCmdResp = &resp->params.queueConfig;
+
+    pQConfigCmd->action = pCmdResp->action;
+    pQConfigCmd->accessCategory = pCmdResp->accessCategory;
+    pQConfigCmd->msduLifetimeExpiry
+        = wlan_le16_to_cpu(pCmdResp->msduLifetimeExpiry);
+
+    pQConfigCmd->tlvBufLen = (resp->Size - sizeof(pCmdResp->action)
+                              - sizeof(pCmdResp->accessCategory)
+                              - sizeof(pCmdResp->msduLifetimeExpiry)
+                              - S_DS_GEN);
+
+    memcpy(pQConfigCmd->tlvBuffer,
+           pCmdResp->tlvBuffer, pQConfigCmd->tlvBufLen);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to get/set a specified AC Queue's parameters
+ *
+ *  Receive a AC Queue configuration command which is used to get, set, or
+ *    default the parameters associated with a specific WMM AC Queue.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_config_t struct
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_queue_config_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_queue_config_t queueConfigIoctl;
+    wlan_cmd_wmm_queue_config_t queueConfigCmd;
+    int retcode;
+
+    PRINTM(INFO, "WMM: Queue Config IOCTL Enter\n");
+
+    if (copy_from_user(&queueConfigIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length,
+                           sizeof(queueConfigIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "WMM: Queue Config: copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memset(&queueConfigCmd, 0x00, sizeof(queueConfigCmd));
+
+        queueConfigCmd.action = queueConfigIoctl.action;
+        queueConfigCmd.accessCategory = queueConfigIoctl.accessCategory;
+        queueConfigCmd.msduLifetimeExpiry
+            = queueConfigIoctl.msduLifetimeExpiry;
+
+        /* Create a rates TLV from the supportedRates[] ioctl field */
+        queueConfigCmd.tlvBufLen = 0;
+
+        retcode = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_WMM_QUEUE_CONFIG, 0,
+                                   HostCmd_OPTION_WAITFORRSP, 0,
+                                   &queueConfigCmd);
+        if (retcode) {
+            retcode = -EFAULT;
+        } else {
+            memset(&queueConfigIoctl, 0x00, sizeof(queueConfigIoctl));
+
+            queueConfigIoctl.action = queueConfigCmd.action;
+            queueConfigIoctl.accessCategory = queueConfigCmd.accessCategory;
+            queueConfigIoctl.msduLifetimeExpiry
+                = queueConfigCmd.msduLifetimeExpiry;
+
+            wrq->u.data.length = sizeof(queueConfigIoctl);
+
+            if (copy_to_user(wrq->u.data.pointer,
+                             &queueConfigIoctl, sizeof(queueConfigIoctl))) {
+                PRINTM(INFO, "Copy to user failed\n");
+                retcode = -EFAULT;
+            }
+        }
+    }
+
+    return retcode;
+}
+
+/**
+ *  @brief Prepare the firmware command buffer for the WMM_QUEUE_STATS command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      pointer to CMD buffer
+ *  @param InfoBuf  void pointer cast of a HostCmd_CMD_WMM_QUEUE_STATS struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_queue_stats(wlan_private * priv,
+                         HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    memcpy(&cmd->params.queueStats, InfoBuf, sizeof(cmd->params.queueStats));
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_QUEUE_STATS);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_QUEUE_STATS)
+                                 + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: QUEUE STATS Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the WMM_QUEUE_STATS command response from firmware
+ *
+ *  Return the firmware command response to the blocked IOCTL caller function.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer with:
+ *                      - action code
+ *                      - access category
+ *                      - collected statistics if requested
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_queue_stats_ioctl
+ */
+int
+wlan_cmdresp_wmm_queue_stats(wlan_private * priv,
+                             const HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_WMM_QUEUE_STATS *pQueueStats =
+        (HostCmd_DS_WMM_QUEUE_STATS *) priv->adapter->CurCmd->pdata_buf;
+
+    memcpy(pQueueStats, &resp->params.queueStats, (resp->Size - S_DS_GEN));
+
+    pQueueStats->pktCount = wlan_le16_to_cpu(pQueueStats->pktCount);
+    pQueueStats->pktLoss = wlan_le16_to_cpu(pQueueStats->pktLoss);
+    pQueueStats->avgQueueDelay = wlan_le32_to_cpu(pQueueStats->avgQueueDelay);
+    pQueueStats->avgTxDelay = wlan_le32_to_cpu(pQueueStats->avgTxDelay);
+    pQueueStats->usedTime = wlan_le16_to_cpu(pQueueStats->usedTime);
+    pQueueStats->policedTime = wlan_le16_to_cpu(pQueueStats->policedTime);
+
+    PRINTM(INFO, "WMM: Queue Stats response: %d\n", resp->Size - S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC
+ *
+ *  Receive a AC Queue statistics command from the application for a specific
+ *    WMM AC.  The command can:
+ *         - Turn stats on
+ *         - Turn stats off
+ *         - Collect and clear the stats
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param wrq     A pointer to iwreq structure containing the
+ *                 wlan_ioctl_wmm_queue_stats_t struct
+ *
+ *  @return        0 if successful; IOCTL error code otherwise
+ */
+int
+wlan_wmm_queue_stats_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+    wlan_ioctl_wmm_queue_stats_t queueStatsIoctl;
+    HostCmd_DS_WMM_QUEUE_STATS queueStatsCmd;
+    int retcode;
+
+    if (copy_from_user(&queueStatsIoctl,
+                       wrq->u.data.pointer,
+                       MIN(wrq->u.data.length,
+                           sizeof(queueStatsIoctl))) != 0) {
+        /* copy_from_user failed  */
+        PRINTM(INFO, "WMM: Queue Stats: copy from user failed\n");
+        retcode = -EFAULT;
+
+    } else {
+        memcpy(&queueStatsCmd, &queueStatsIoctl, sizeof(queueStatsCmd));
+
+        PRINTM(INFO, "WMM: QUEUE STATS Ioctl: %d, %d\n",
+               queueStatsCmd.action, queueStatsCmd.accessCategory);
+
+        retcode = wlan_prepare_cmd(priv,
+                                   HostCmd_CMD_WMM_QUEUE_STATS, 0,
+                                   HostCmd_OPTION_WAITFORRSP, 0,
+                                   &queueStatsCmd);
+        if (retcode) {
+            retcode = -EFAULT;
+        } else {
+            if (copy_to_user(wrq->u.data.pointer,
+                             &queueStatsCmd,
+                             MIN(wrq->u.data.length,
+                                 sizeof(queueStatsCmd)))) {
+                PRINTM(INFO, "Copy to user failed\n");
+                retcode = -EFAULT;
+            }
+        }
+    }
+
+    if (retcode != WLAN_STATUS_SUCCESS) {
+        PRINTM(INFO, "WMM: QUEUE STATS Ioctl FAILED: %d, %d\n",
+               queueStatsIoctl.action, queueStatsIoctl.accessCategory);
+    }
+
+    return retcode;
+}
+
+/**
+ *  @brief Prepare the firmware command buffer for the WMM_TS_STATUS command
+ *
+ *  @param priv     Pointer to the wlan_private driver data struct
+ *  @param cmd      pointer to CMD buffer
+ *  @param InfoBuf  void pointer cast of a HostCmd_CMD_TS_STATUS struct
+ *
+ *  @return         WLAN_STATUS_SUCCESS
+ */
+int
+wlan_cmd_wmm_ts_status(wlan_private * priv,
+                       HostCmd_DS_COMMAND * cmd, void *InfoBuf)
+{
+    memcpy(&cmd->params.tsStatus, InfoBuf, sizeof(cmd->params.tsStatus));
+
+    cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_WMM_TS_STATUS);
+    cmd->Size = wlan_cpu_to_le16(sizeof(HostCmd_DS_WMM_TS_STATUS) + S_DS_GEN);
+
+    PRINTM(INFO, "WMM: TS STATUS Cmd prepared\n");
+
+    return WLAN_STATUS_SUCCESS;
+}
+
+/**
+ *  @brief Process the WMM_TS_STATUS command response from firmware
+ *
+ *  Return the firmware command response to the blocked IOCTL caller function.
+ *
+ *  @param priv    Pointer to the wlan_private driver data struct
+ *  @param resp    Pointer to the command response buffer
+ *
+ *  @return WLAN_STATUS_SUCCESS
+ *
+ *  @sa wlan_wmm_queue_stats_ioctl
+ */
+int
+wlan_cmdresp_wmm_ts_status(wlan_private * priv,
+                           const HostCmd_DS_COMMAND * resp)
+{
+    HostCmd_DS_WMM_TS_STATUS *pTsStatus =
+        (HostCmd_DS_WMM_TS_STATUS *) priv->adapter->CurCmd->pdata_buf;
+
+    memcpy(pTsStatus, &resp->params.tsStatus, (resp->Size - S_DS_GEN));
+
+    pTsStatus->mediumTime = wlan_le16_to_cpu(pTsStatus->mediumTime);
+
+    PRINTM(INFO, "WMM: TS Status response: %d\n", resp->Size - S_DS_GEN);
+
+    return WLAN_STATUS_SUCCESS;
+}
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.h linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.h
--- linux-2.6.24.7-rt20/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/8688_wlan/wlan/wlan_wmm.h	2008-09-28 11:33:16.000000000 +0200
@@ -0,0 +1,136 @@
+/** @file wlan_wmm.h
+ * @brief This file contains related macros, enum, and struct
+ * of wmm functionalities
+ *
+ * (c) Copyright © 2003-2006, Marvell International Ltd. 
+ *
+ * This software file (the "File") is distributed by Marvell International 
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991 
+ * (the "License").  You may use, redistribute and/or modify this File in 
+ * accordance with the terms and conditions of the License, a copy of which 
+ * is available along with the File in the gpl.txt file or by writing to 
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
+ * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about 
+ * this warranty disclaimer.
+ *
+ */
+/****************************************************
+Change log:
+    09/26/05: add Doxygen format comments 
+    04/06/06: Add TSPEC, queue metrics, and MSDU expiry support
+****************************************************/
+
+#ifndef __WLAN_WMM_H
+#define __WLAN_WMM_H
+
+/** Custom indiciation message sent to the application layer for WMM changes */
+#define WMM_CONFIG_CHANGE_INDICATION  "WMM_CONFIG_CHANGE.indication"
+
+/** Highest priority setting for a packet (uses voice AC) */
+#define WMM_HIGHEST_PRIORITY  7
+
+#ifdef __KERNEL__
+
+/** struct of WMM DESC */
+typedef struct
+{
+    u8 required;
+    u8 enabled;
+    u8 packetsQueued;
+    u8 queueStopped;
+    u32 packetsOut[MAX_AC_QUEUES];
+    u32 userPriPktTxCtrl[WMM_HIGHEST_PRIORITY + 1];     /* UP: 0 to 7 */
+
+    struct sk_buff txSkbQ[MAX_AC_QUEUES];
+    WmmAcStatus_t acStatus[MAX_AC_QUEUES];
+    wlan_wmm_ac_e acDowngradedVals[MAX_AC_QUEUES];
+
+    /** max driver packet delay sent to the firmware for expiry eval */
+    int drvPktDelayMax;
+
+    /** wmm queue priority table*/
+    u8 queuePriority[MAX_AC_QUEUES];
+
+    u8 qosinfo;
+} __ATTRIB_PACK__ WMM_DESC;
+
+extern void wmm_map_and_add_skb(wlan_private * priv, struct sk_buff *);
+extern u8 wmm_compute_driver_packet_delay(wlan_private * priv,
+                                          const struct sk_buff *skb);
+#endif
+
+extern int wlan_cmd_wmm_status_change(wlan_private * priv);
+extern int wmm_lists_empty(wlan_private * priv);
+extern void wmm_cleanup_queues(wlan_private * priv);
+extern void wmm_process_tx(wlan_private * priv);
+
+extern void wmm_init(wlan_private * priv);
+extern void wmm_setup_queues(wlan_private * priv);
+extern void wmm_start_queue(wlan_private * priv);
+extern void wmm_stop_queue(wlan_private * priv);
+extern int wmm_is_queue_stopped(wlan_private * priv);
+
+extern void wmm_process_fw_iface_tx_xfer_start(wlan_private * priv);
+extern void wmm_process_fw_iface_tx_xfer_end(wlan_private * priv);
+extern void wmm_process_app_iface_tx(wlan_private * priv);
+extern wlan_wmm_ac_e wmm_convert_tos_to_ac(int tos);
+extern wlan_wmm_ac_e wmm_downgrade_ac(wlan_private * priv,
+                                      wlan_wmm_ac_e acVal);
+
+extern u32 wlan_wmm_process_association_req(wlan_private * priv,
+                                            u8 ** ppAssocBuf,
+                                            IEEEtypes_WmmParameter_t *
+                                            pWmmIE);
+
+/* 
+ *  Functions used in the cmd handling routine
+ */
+extern int wlan_cmd_wmm_get_status(wlan_private * priv,
+                                   HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_addts_req(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_delts_req(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_queue_config(wlan_private * priv,
+                                     HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_queue_stats(wlan_private * priv,
+                                    HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+extern int wlan_cmd_wmm_ts_status(wlan_private * priv,
+                                  HostCmd_DS_COMMAND * cmd, void *InfoBuf);
+
+/* 
+ *  Functions used in the cmdresp handling routine
+ */
+extern int wlan_cmdresp_wmm_get_status(wlan_private * priv,
+                                       const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_addts_req(wlan_private * priv,
+                                      const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_delts_req(wlan_private * priv,
+                                      const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_queue_config(wlan_private * priv,
+                                         const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_queue_stats(wlan_private * priv,
+                                        const HostCmd_DS_COMMAND * resp);
+extern int wlan_cmdresp_wmm_ts_status(wlan_private * priv,
+                                      const HostCmd_DS_COMMAND * resp);
+
+/* 
+ * IOCTLs 
+ */
+extern int wlan_wmm_enable_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_drv_delay_max_ioctl(wlan_private * priv,
+                                        struct iwreq *wrq);
+extern int wlan_wmm_queue_status_ioctl(wlan_private * priv,
+                                       struct iwreq *wrq);
+extern int wlan_wmm_ts_status_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_addts_req_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_delts_req_ioctl(wlan_private * priv, struct iwreq *wrq);
+extern int wlan_wmm_queue_config_ioctl(wlan_private * priv,
+                                       struct iwreq *wrq);
+extern int wlan_wmm_queue_stats_ioctl(wlan_private * priv, struct iwreq *wrq);
+
+#endif /* __WLAN_WMM_H */
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/Kconfig linux-2.6.24.7-rt20-atom/drivers/net/wireless/Kconfig
--- linux-2.6.24.7-rt20/drivers/net/wireless/Kconfig	2008-10-06 08:30:22.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/Kconfig	2008-09-28 11:33:16.000000000 +0200
@@ -656,4 +656,20 @@
 source "drivers/net/wireless/zd1211rw/Kconfig"
 source "drivers/net/wireless/rt2x00/Kconfig"
 
+comment "Marvell 8686/8688 SDIO device support"
+	depends on WLAN_80211 && PCI
+
+config MMC_SD8686
+        tristate "Marvell 8686 SDIO-WLAN support"
+        depends on PCI && WLAN_80211 && MMC && MMC_SDHCI
+	default y
+        help
+          WLAN is for Marvell SD8686 WLAN based on Pierr Ossman's
+	  mainline SDIO stack.
+
+config MMC_SD8688
+        tristate "Marvell 8688 SDIO-WLAN/BT support"
+        depends on PCI && WLAN_80211 && MMC && MMC_SDHCI && BT 
+	default y
+
 endmenu
diff -urN linux-2.6.24.7-rt20/drivers/net/wireless/Makefile linux-2.6.24.7-rt20-atom/drivers/net/wireless/Makefile
--- linux-2.6.24.7-rt20/drivers/net/wireless/Makefile	2008-10-06 08:30:22.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/net/wireless/Makefile	2008-09-28 11:33:16.000000000 +0200
@@ -33,6 +33,9 @@
 obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 
 obj-$(CONFIG_PRISM54)		+= prism54/
+obj-$(CONFIG_MMC_SD8686)	+= 8686_v9/
+obj-$(CONFIG_MMC_SD8688)	+= 8688_wlan/
+obj-$(CONFIG_MMC_SD8688)	+= 8688_bt/
 
 obj-$(CONFIG_HOSTAP)		+= hostap/
 obj-$(CONFIG_BCM43XX)		+= bcm43xx/
diff -urN linux-2.6.24.7-rt20/drivers/pci/quirks.c linux-2.6.24.7-rt20-atom/drivers/pci/quirks.c
--- linux-2.6.24.7-rt20/drivers/pci/quirks.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/pci/quirks.c	2008-09-28 11:31:30.000000000 +0200
@@ -1481,6 +1481,17 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
 
+
+static void __devinit fixup_poulsbo_hda(struct pci_dev* dev)
+{
+	/* poulsbo A2 HD audio controller has the wrong class type of 604h */
+	if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
+		printk(KERN_INFO "Poulsbo A2 HDA detected, setting PCI class.\n");
+		dev->class = PCI_CLASS_MULTIMEDIA_AUDIO;
+	}
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_POULSBO_HDA, fixup_poulsbo_hda);
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
 {
 	while (f < end) {
diff -urN linux-2.6.24.7-rt20/drivers/thermal/Kconfig linux-2.6.24.7-rt20-atom/drivers/thermal/Kconfig
--- linux-2.6.24.7-rt20/drivers/thermal/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/thermal/Kconfig	2008-09-28 11:30:55.000000000 +0200
@@ -0,0 +1,16 @@
+#
+# Generic thermal sysfs drivers configuration
+#
+
+menuconfig THERMAL
+	bool "Generic Thermal sysfs driver"
+	default y
+	help
+	  Generic Thermal Sysfs driver offers a generic mechanism for
+	  thermal management. Usually it's made up of one or more thermal
+	  zone and cooling device.
+	  each thermal zone contains its own temperature, trip points,
+	  cooling devices.
+	  All platforms with ACPI thermal support can use this driver.
+	  If you want this support, you should say Y here
+
diff -urN linux-2.6.24.7-rt20/drivers/thermal/Makefile linux-2.6.24.7-rt20-atom/drivers/thermal/Makefile
--- linux-2.6.24.7-rt20/drivers/thermal/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/thermal/Makefile	2008-09-28 11:30:55.000000000 +0200
@@ -0,0 +1,6 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_THERMAL)		+= thermal.o
+
diff -urN linux-2.6.24.7-rt20/drivers/thermal/thermal.c linux-2.6.24.7-rt20-atom/drivers/thermal/thermal.c
--- linux-2.6.24.7-rt20/drivers/thermal/thermal.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/thermal/thermal.c	2008-09-28 11:30:55.000000000 +0200
@@ -0,0 +1,714 @@
+/*
+ *  thermal.c - Generic Thermal Management Sysfs support.
+ *
+ *  Copyright (C) 2008 Intel Corp
+ *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/thermal.h>
+#include <linux/spinlock.h>
+
+MODULE_AUTHOR("Zhang Rui")
+MODULE_DESCRIPTION("Generic thermal management sysfs support");
+MODULE_LICENSE("GPL");
+
+#define PREFIX "Thermal: "
+
+struct thermal_cooling_device_instance {
+	int id;
+	char name[THERMAL_NAME_LENGTH];
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *cdev;
+	int trip;
+	char attr_name[THERMAL_NAME_LENGTH];
+	struct device_attribute attr;
+	struct list_head node;
+};
+
+static DEFINE_IDR(thermal_tz_idr);
+static DEFINE_IDR(thermal_cdev_idr);
+static DEFINE_MUTEX(thermal_idr_lock);
+
+static LIST_HEAD(thermal_tz_list);
+static LIST_HEAD(thermal_cdev_list);
+static DEFINE_MUTEX(thermal_list_lock);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+	int err;
+
+      again:
+	if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
+		return -ENOMEM;
+
+	if (lock)
+		mutex_lock(lock);
+	err = idr_get_new(idr, NULL, id);
+	if (lock)
+		mutex_unlock(lock);
+	if (unlikely(err == -EAGAIN))
+		goto again;
+	else if (unlikely(err))
+		return err;
+
+	*id = *id & MAX_ID_MASK;
+	return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+	if (lock)
+		mutex_lock(lock);
+	idr_remove(idr, id);
+	if (lock)
+		mutex_unlock(lock);
+}
+
+/* sys I/F for thermal zone */
+
+#define to_thermal_zone(_dev) \
+	container_of(_dev, struct thermal_zone_device, device)
+
+static ssize_t
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	return sprintf(buf, "%s\n", tz->type);
+}
+
+static ssize_t
+temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	if (!tz->ops->get_temp)
+		return -EPERM;
+
+	return tz->ops->get_temp(tz, buf);
+}
+
+static ssize_t
+mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	if (!tz->ops->get_mode)
+		return -EPERM;
+
+	return tz->ops->get_mode(tz, buf);
+}
+
+static ssize_t
+mode_store(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int result;
+
+	if (!tz->ops->set_mode)
+		return -EPERM;
+
+	result = tz->ops->set_mode(tz, buf);
+	if (result)
+		return result;
+
+	return count;
+}
+
+static ssize_t
+trip_point_type_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip;
+
+	if (!tz->ops->get_trip_type)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
+		return -EINVAL;
+
+	return tz->ops->get_trip_type(tz, trip, buf);
+}
+
+static ssize_t
+trip_point_temp_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip;
+
+	if (!tz->ops->get_trip_temp)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
+		return -EINVAL;
+
+	return tz->ops->get_trip_temp(tz, trip, buf);
+}
+
+static DEVICE_ATTR(type, 0444, type_show, NULL);
+static DEVICE_ATTR(temp, 0444, temp_show, NULL);
+static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
+
+static struct device_attribute trip_point_attrs[] = {
+	__ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
+	__ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
+	__ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
+};
+
+#define TRIP_POINT_ATTR_ADD(_dev, _index, result)     \
+do {    \
+	result = device_create_file(_dev,	\
+				&trip_point_attrs[_index * 2]);	\
+	if (result)	\
+		break;	\
+	result = device_create_file(_dev,	\
+			&trip_point_attrs[_index * 2 + 1]);	\
+} while (0)
+
+#define TRIP_POINT_ATTR_REMOVE(_dev, _index)	\
+do {	\
+	device_remove_file(_dev, &trip_point_attrs[_index * 2]);	\
+	device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]);	\
+} while (0)
+
+/* sys I/F for cooling device */
+#define to_cooling_device(_dev)	\
+	container_of(_dev, struct thermal_cooling_device, device)
+
+static ssize_t
+thermal_cooling_device_type_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+	return sprintf(buf, "%s\n", cdev->type);
+}
+
+static ssize_t
+thermal_cooling_device_max_state_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+	return cdev->ops->get_max_state(cdev, buf);
+}
+
+static ssize_t
+thermal_cooling_device_cur_state_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+	return cdev->ops->get_cur_state(cdev, buf);
+}
+
+static ssize_t
+thermal_cooling_device_cur_state_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	int state;
+	int result;
+
+	if (!sscanf(buf, "%d\n", &state))
+		return -EINVAL;
+
+	if (state < 0)
+		return -EINVAL;
+
+	result = cdev->ops->set_cur_state(cdev, state);
+	if (result)
+		return result;
+	return count;
+}
+
+static struct device_attribute dev_attr_cdev_type =
+		__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
+static DEVICE_ATTR(max_state, 0444,
+		   thermal_cooling_device_max_state_show, NULL);
+static DEVICE_ATTR(cur_state, 0644,
+		   thermal_cooling_device_cur_state_show,
+		   thermal_cooling_device_cur_state_store);
+
+static ssize_t
+thermal_cooling_device_trip_point_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device_instance *instance;
+
+	instance =
+	    container_of(attr, struct thermal_cooling_device_instance, attr);
+
+	if (instance->trip == THERMAL_TRIPS_NONE)
+		return sprintf(buf, "-1\n");
+	else
+		return sprintf(buf, "%d\n", instance->trip);
+}
+
+/* Device management */
+
+/**
+ * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
+ * this function is usually called in the thermal zone device .bind callback.
+ * @tz:		thermal zone device
+ * @trip:	indicates which trip point the cooling devices is
+ *		associated with in this thermal zone.
+ * @cdev:	thermal cooling device
+ */
+int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+				     int trip,
+				     struct thermal_cooling_device *cdev)
+{
+	struct thermal_cooling_device_instance *dev;
+	struct thermal_cooling_device_instance *pos;
+	int result;
+
+	if (trip >= tz->trips ||
+	    (trip < 0 && trip != THERMAL_TRIPS_NONE))
+		return -EINVAL;
+
+	if (!tz || !cdev)
+		return -EINVAL;
+
+	dev =
+	    kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	dev->tz = tz;
+	dev->cdev = cdev;
+	dev->trip = trip;
+	result = get_idr(&tz->idr, &tz->lock, &dev->id);
+	if (result)
+		goto free_mem;
+
+	sprintf(dev->name, "cdev%d", dev->id);
+	result =
+	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
+	if (result)
+		goto release_idr;
+
+	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
+	dev->attr.attr.name = dev->attr_name;
+	dev->attr.attr.mode = 0444;
+	dev->attr.show = thermal_cooling_device_trip_point_show;
+	result = device_create_file(&tz->device, &dev->attr);
+	if (result)
+		goto remove_symbol_link;
+
+	mutex_lock(&tz->lock);
+	list_for_each_entry(pos, &tz->cooling_devices, node)
+	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+		result = -EEXIST;
+		break;
+	}
+	if (!result)
+		list_add_tail(&dev->node, &tz->cooling_devices);
+	mutex_unlock(&tz->lock);
+
+	if (!result)
+		return 0;
+
+	device_remove_file(&tz->device, &dev->attr);
+      remove_symbol_link:
+	sysfs_remove_link(&tz->device.kobj, dev->name);
+      release_idr:
+	release_idr(&tz->idr, &tz->lock, dev->id);
+      free_mem:
+	kfree(dev);
+	return result;
+}
+EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
+
+/**
+ * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
+ * this function is usually called in the thermal zone device .unbind callback.
+ * @tz:		thermal zone device
+ * @trip:	indicates which trip point the cooling devices is
+ *		associated with in this thermal zone.
+ * @cdev:	thermal cooling device
+ */
+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+				       int trip,
+				       struct thermal_cooling_device *cdev)
+{
+	struct thermal_cooling_device_instance *pos, *next;
+
+	mutex_lock(&tz->lock);
+	list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
+		if (pos->tz == tz && pos->trip == trip
+		    && pos->cdev == cdev) {
+			list_del(&pos->node);
+			mutex_unlock(&tz->lock);
+			goto unbind;
+		}
+	}
+	mutex_unlock(&tz->lock);
+
+	return -ENODEV;
+
+      unbind:
+	device_remove_file(&tz->device, &pos->attr);
+	sysfs_remove_link(&tz->device.kobj, pos->name);
+	release_idr(&tz->idr, &tz->lock, pos->id);
+	kfree(pos);
+	return 0;
+}
+EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
+
+static void thermal_release(struct device *dev)
+{
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *cdev;
+
+	if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) {
+		tz = to_thermal_zone(dev);
+		kfree(tz);
+	} else {
+		cdev = to_cooling_device(dev);
+		kfree(cdev);
+	}
+}
+
+static struct class thermal_class = {
+	.name = "thermal",
+	.dev_release = thermal_release,
+};
+
+/**
+ * thermal_cooling_device_register - register a new thermal cooling device
+ * @type:	the thermal cooling device type.
+ * @devdata:	device private data.
+ * @ops:		standard thermal cooling devices callbacks.
+ */
+struct thermal_cooling_device *thermal_cooling_device_register(char *type,
+		       void *devdata, struct thermal_cooling_device_ops *ops)
+{
+	struct thermal_cooling_device *cdev;
+	struct thermal_zone_device *pos;
+	int result;
+
+	if (strlen(type) >= THERMAL_NAME_LENGTH)
+		return NULL;
+
+	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
+		!ops->set_cur_state)
+		return NULL;
+
+	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
+	if (!cdev)
+		return NULL;
+
+	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
+	if (result) {
+		kfree(cdev);
+		return NULL;
+	}
+
+	strcpy(cdev->type, type);
+	cdev->ops = ops;
+	cdev->device.class = &thermal_class;
+	cdev->devdata = devdata;
+	sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id);
+	result = device_register(&cdev->device);
+	if (result) {
+		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+		kfree(cdev);
+		return NULL;
+	}
+
+	/* sys I/F */
+	if (type) {
+		result = device_create_file(&cdev->device,
+					    &dev_attr_cdev_type);
+		if (result)
+			goto unregister;
+	}
+
+	result = device_create_file(&cdev->device, &dev_attr_max_state);
+	if (result)
+		goto unregister;
+
+	result = device_create_file(&cdev->device, &dev_attr_cur_state);
+	if (result)
+		goto unregister;
+
+	mutex_lock(&thermal_list_lock);
+	list_add(&cdev->node, &thermal_cdev_list);
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (!pos->ops->bind)
+			continue;
+		result = pos->ops->bind(pos, cdev);
+		if (result)
+			break;
+
+	}
+	mutex_unlock(&thermal_list_lock);
+
+	if (!result)
+		return cdev;
+
+      unregister:
+	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+	device_unregister(&cdev->device);
+	return NULL;
+}
+EXPORT_SYMBOL(thermal_cooling_device_register);
+
+/**
+ * thermal_cooling_device_unregister - removes the registered thermal cooling device
+ *
+ * @cdev:	the thermal cooling device to remove.
+ *
+ * thermal_cooling_device_unregister() must be called when the device is no
+ * longer needed.
+ */
+void thermal_cooling_device_unregister(struct
+				       thermal_cooling_device
+				       *cdev)
+{
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *pos = NULL;
+
+	if (!cdev)
+		return;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(pos, &thermal_cdev_list, node)
+	    if (pos == cdev)
+		break;
+	if (pos != cdev) {
+		/* thermal cooling device not found */
+		mutex_unlock(&thermal_list_lock);
+		return;
+	}
+	list_del(&cdev->node);
+	list_for_each_entry(tz, &thermal_tz_list, node) {
+		if (!tz->ops->unbind)
+			continue;
+		tz->ops->unbind(tz, cdev);
+	}
+	mutex_unlock(&thermal_list_lock);
+	if (cdev->type[0])
+		device_remove_file(&cdev->device,
+				   &dev_attr_cdev_type);
+	device_remove_file(&cdev->device, &dev_attr_max_state);
+	device_remove_file(&cdev->device, &dev_attr_cur_state);
+
+	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+	device_unregister(&cdev->device);
+	return;
+}
+EXPORT_SYMBOL(thermal_cooling_device_unregister);
+
+/**
+ * thermal_zone_device_register - register a new thermal zone device
+ * @type:	the thermal zone device type
+ * @trips:	the number of trip points the thermal zone support
+ * @devdata:	private device data
+ * @ops:	standard thermal zone device callbacks
+ *
+ * thermal_zone_device_unregister() must be called when the device is no
+ * longer needed.
+ */
+struct thermal_zone_device *thermal_zone_device_register(char *type,
+					int trips, void *devdata,
+					struct thermal_zone_device_ops *ops)
+{
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *pos;
+	int result;
+	int count;
+
+	if (strlen(type) >= THERMAL_NAME_LENGTH)
+		return NULL;
+
+	if (trips > THERMAL_MAX_TRIPS || trips < 0)
+		return NULL;
+
+	if (!ops || !ops->get_temp)
+		return NULL;
+
+	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
+	if (!tz)
+		return NULL;
+
+	INIT_LIST_HEAD(&tz->cooling_devices);
+	idr_init(&tz->idr);
+	mutex_init(&tz->lock);
+	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
+	if (result) {
+		kfree(tz);
+		return NULL;
+	}
+
+	strcpy(tz->type, type);
+	tz->ops = ops;
+	tz->device.class = &thermal_class;
+	tz->devdata = devdata;
+	tz->trips = trips;
+	sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
+	result = device_register(&tz->device);
+	if (result) {
+		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+		kfree(tz);
+		return NULL;
+	}
+
+	/* sys I/F */
+	if (type) {
+		result = device_create_file(&tz->device, &dev_attr_type);
+		if (result)
+			goto unregister;
+	}
+
+	result = device_create_file(&tz->device, &dev_attr_temp);
+	if (result)
+		goto unregister;
+
+	if (ops->get_mode) {
+		result = device_create_file(&tz->device, &dev_attr_mode);
+		if (result)
+			goto unregister;
+	}
+
+	for (count = 0; count < trips; count++) {
+		TRIP_POINT_ATTR_ADD(&tz->device, count, result);
+		if (result)
+			goto unregister;
+	}
+
+	mutex_lock(&thermal_list_lock);
+	list_add_tail(&tz->node, &thermal_tz_list);
+	if (ops->bind)
+		list_for_each_entry(pos, &thermal_cdev_list, node) {
+			result = ops->bind(tz, pos);
+			if (result)
+				break;
+		}
+	mutex_unlock(&thermal_list_lock);
+
+	if (!result)
+		return tz;
+
+      unregister:
+	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+	device_unregister(&tz->device);
+	return NULL;
+}
+EXPORT_SYMBOL(thermal_zone_device_register);
+
+/**
+ * thermal_device_unregister - removes the registered thermal zone device
+ *
+ * @tz: the thermal zone device to remove
+ */
+void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+{
+	struct thermal_cooling_device *cdev;
+	struct thermal_zone_device *pos = NULL;
+	int count;
+
+	if (!tz)
+		return;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(pos, &thermal_tz_list, node)
+	    if (pos == tz)
+		break;
+	if (pos != tz) {
+		/* thermal zone device not found */
+		mutex_unlock(&thermal_list_lock);
+		return;
+	}
+	list_del(&tz->node);
+	if (tz->ops->unbind)
+		list_for_each_entry(cdev, &thermal_cdev_list, node)
+		    tz->ops->unbind(tz, cdev);
+	mutex_unlock(&thermal_list_lock);
+
+	if (tz->type[0])
+		device_remove_file(&tz->device, &dev_attr_type);
+	device_remove_file(&tz->device, &dev_attr_temp);
+	if (tz->ops->get_mode)
+		device_remove_file(&tz->device, &dev_attr_mode);
+
+	for (count = 0; count < tz->trips; count++)
+		TRIP_POINT_ATTR_REMOVE(&tz->device, count);
+
+	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+	idr_destroy(&tz->idr);
+	mutex_destroy(&tz->lock);
+	device_unregister(&tz->device);
+	return;
+}
+EXPORT_SYMBOL(thermal_zone_device_unregister);
+
+static int __init thermal_init(void)
+{
+	int result = 0;
+
+	result = class_register(&thermal_class);
+	if (result) {
+		idr_destroy(&thermal_tz_idr);
+		idr_destroy(&thermal_cdev_idr);
+		mutex_destroy(&thermal_idr_lock);
+		mutex_destroy(&thermal_list_lock);
+	}
+	return result;
+}
+
+static void __exit thermal_exit(void)
+{
+	class_unregister(&thermal_class);
+	idr_destroy(&thermal_tz_idr);
+	idr_destroy(&thermal_cdev_idr);
+	mutex_destroy(&thermal_idr_lock);
+	mutex_destroy(&thermal_list_lock);
+}
+
+subsys_initcall(thermal_init);
+module_exit(thermal_exit);
diff -urN linux-2.6.24.7-rt20/drivers/usb/core/driver.c linux-2.6.24.7-rt20-atom/drivers/usb/core/driver.c
--- linux-2.6.24.7-rt20/drivers/usb/core/driver.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/core/driver.c	2008-09-28 11:34:04.000000000 +0200
@@ -866,6 +866,9 @@
 	return status;
 }
 
+struct usb_hub;
+void hub_port_logical_disconnect(struct usb_hub *hub, int port1);
+
 /* Caller has locked intf's usb_device's pm_mutex */
 static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 {
@@ -894,9 +897,15 @@
 				dev_err(&intf->dev, "%s error %d\n",
 						"reset_resume", status);
 		} else {
-			// status = -EOPNOTSUPP;
+			struct usb_device		*udev = interface_to_usbdev(intf);
+			struct usb_device               *parent_hdev = udev->parent;
+			/* status = -EOPNOTSUPP; */
 			dev_warn(&intf->dev, "no %s for driver %s?\n",
 					"reset_resume", driver->name);
+			if (parent_hdev) {
+				struct usb_hub *parent_hub = usb_get_intfdata(parent_hdev->actconfig->interface[0]);
+				hub_port_logical_disconnect(parent_hub, udev->portnum);
+			}
 		}
 	} else {
 		if (driver->resume) {
@@ -905,7 +914,7 @@
 				dev_err(&intf->dev, "%s error %d\n",
 						"resume", status);
 		} else {
-			// status = -EOPNOTSUPP;
+			/* status = -EOPNOTSUPP; */
 			dev_warn(&intf->dev, "no %s for driver %s?\n",
 					"resume", driver->name);
 		}
diff -urN linux-2.6.24.7-rt20/drivers/usb/core/hub.c linux-2.6.24.7-rt20-atom/drivers/usb/core/hub.c
--- linux-2.6.24.7-rt20/drivers/usb/core/hub.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/core/hub.c	2008-09-28 11:34:04.000000000 +0200
@@ -584,7 +584,7 @@
  * time later khubd will disconnect() any existing usb_device on the port
  * and will re-enumerate if there actually is a device attached.
  */
-static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
+void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
 {
 	dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
 	hub_port_disable(hub, port1, 1);
@@ -601,6 +601,7 @@
 	set_bit(port1, hub->change_bits);
  	kick_khubd(hub);
 }
+EXPORT_SYMBOL(hub_port_logical_disconnect);
 
 /* caller has locked the hub device */
 static int hub_pre_reset(struct usb_interface *intf)
diff -urN linux-2.6.24.7-rt20/drivers/usb/core/quirks.c linux-2.6.24.7-rt20-atom/drivers/usb/core/quirks.c
--- linux-2.6.24.7-rt20/drivers/usb/core/quirks.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/core/quirks.c	2008-09-28 11:34:04.000000000 +0200
@@ -48,6 +48,8 @@
 	/* SKYMEDI USB_DRIVE */
 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* ASIX Ethernet device */
+	{ USB_DEVICE(0x0b95, 0x1720), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ }  /* terminating entry must be last */
 };
 
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/ether.c linux-2.6.24.7-rt20-atom/drivers/usb/gadget/ether.c
--- linux-2.6.24.7-rt20/drivers/usb/gadget/ether.c	2008-10-06 08:30:46.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/ether.c	2008-09-28 11:32:46.000000000 +0200
@@ -19,7 +19,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/* #define VERBOSE_DEBUG */
+#define VERBOSE_DEBUG
 
 #include <linux/kernel.h>
 #include <linux/utsname.h>
@@ -34,6 +34,10 @@
 
 #include "gadget_chips.h"
 
+#ifdef CONFIG_USB_GADGET_IUSBC
+#include "iusbc.h"
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -68,7 +72,7 @@
  */
 
 #define DRIVER_DESC		"Ethernet Gadget"
-#define DRIVER_VERSION		"May Day 2005"
+#define	DRIVER_VERSION		"2.0.0.32L.0009"
 
 static const char shortname [] = "ether";
 static const char driver_desc [] = DRIVER_DESC;
@@ -239,6 +243,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_IUSBC
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define DEV_CONFIG_CDC
 #endif
@@ -1353,11 +1361,31 @@
 	u16			wIndex = le16_to_cpu(ctrl->wIndex);
 	u16			wValue = le16_to_cpu(ctrl->wValue);
 	u16			wLength = le16_to_cpu(ctrl->wLength);
+	__le16			status = 0;
 
 	/* descriptors just go into the pre-allocated ep0 buffer,
 	 * while config change events may enable network traffic.
 	 */
 	req->complete = eth_setup_complete;
+
+#ifdef CONFIG_USB_GADGET_IUSBC
+	/* software handles get_status in iusbc controller */
+	if (gadget_is_iusbc(dev->gadget)) {
+		if ((ctrl->bRequest == USB_REQ_GET_STATUS)
+			&& (ctrl->bRequestType & USB_DIR_IN)
+			&& (ctrl->bRequestType != 0x21)) {
+			struct iusbc *controller =
+				container_of(dev->gadget,
+						struct iusbc,
+						gadget);
+			status = controller->status_d;
+			DEBUG (dev, "status_d: %d\n", status);
+			value = sizeof status;
+			*(u16 *) req->buf = le16_to_cpu(status);
+		}
+	}
+#endif
+
 	switch (ctrl->bRequest) {
 
 	case USB_REQ_GET_DESCRIPTOR:
@@ -1421,7 +1449,7 @@
 				|| !dev->config
 				|| wIndex > 1)
 			break;
-		if (!cdc_active(dev) && wIndex != 0)
+		if (!rndis_active(dev) && !cdc_active(dev) && wIndex != 0)
 			break;
 		spin_lock (&dev->lock);
 
@@ -1556,9 +1584,9 @@
 			u32 n;
 
 			/* return the result */
-			buf = rndis_get_next_response(dev->rndis_config, &n);
+			buf = rndis_get_next_response (dev->rndis_config, &value);
 			if (buf) {
-				memcpy(req->buf, buf, n);
+				memcpy (req->buf, buf, value);
 				req->complete = rndis_response_complete;
 				rndis_free_response(dev->rndis_config, buf);
 				value = n;
@@ -2640,6 +2668,7 @@
 
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell, Benedikt Spanger");
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE ("GPL");
 
 
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/file_storage.c linux-2.6.24.7-rt20-atom/drivers/usb/gadget/file_storage.c
--- linux-2.6.24.7-rt20/drivers/usb/gadget/file_storage.c	2008-10-06 08:30:26.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/file_storage.c	2008-09-28 11:32:46.000000000 +0200
@@ -244,18 +244,23 @@
 
 #include "gadget_chips.h"
 
+#ifdef CONFIG_USB_GADGET_IUSBC
+#include "iusbc.h"
+#include <linux/pci.h> /* for uevent usage */
+#endif
 
 /*-------------------------------------------------------------------------*/
 
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_NAME		"g_file_storage"
-#define DRIVER_VERSION		"7 August 2007"
+#define DRIVER_VERSION		"2.0.0.32L.0009"
 
 static const char longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Alan Stern");
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* Thanks to NetChip Technologies for donating this product ID.
@@ -545,6 +550,7 @@
 	unsigned int	prevent_medium_removal : 1;
 	unsigned int	registered : 1;
 	unsigned int	info_valid : 1;
+	unsigned int	switch_flag : 1;
 
 	u32		sense_data;
 	u32		sense_data_info;
@@ -684,6 +690,7 @@
 	unsigned int		nluns;
 	struct lun		*luns;
 	struct lun		*curlun;
+	int			uevent_flag;
 };
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
@@ -1335,11 +1342,27 @@
 	int			value = -EOPNOTSUPP;
 	u16			w_index = le16_to_cpu(ctrl->wIndex);
 	u16			w_value = le16_to_cpu(ctrl->wValue);
+	__le16			status = 0;
 
 	/* Usually this just stores reply data in the pre-allocated ep0 buffer,
 	 * but config change events will also reconfigure hardware. */
 	switch (ctrl->bRequest) {
 
+#ifdef CONFIG_USB_GADGET_IUSBC
+	case USB_REQ_GET_STATUS:
+		/* software handles get_status in iusbc controller */
+		if (gadget_is_iusbc(fsg->gadget)) {
+			struct iusbc *controller =
+				container_of(fsg->gadget,
+						struct iusbc,
+						gadget);
+			status = controller->status_d;
+			DBG(fsg, "status_d: %d\n", status);
+			value = sizeof status;
+			*(u16 *) req->buf = le16_to_cpu(status);
+		}
+		break;
+#endif
 	case USB_REQ_GET_DESCRIPTOR:
 		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
 				USB_RECIP_DEVICE))
@@ -1392,6 +1415,13 @@
 		if (w_value == CONFIG_VALUE || w_value == 0) {
 			fsg->new_config = w_value;
 
+#ifdef CONFIG_USB_GADGET_IUSBC
+		/* for resume from S3 in iusbc controller */ 
+		if (gadget_is_iusbc(fsg->gadget)) {
+			fsg->state = FSG_STATE_IDLE;
+			fsg->config = 0;
+		}
+#endif
 			/* Raise an exception to wipe out previous transaction
 			 * state (queued bufs, etc) and set the new config. */
 			raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
@@ -2853,6 +2883,9 @@
 		break;
 
 	case SC_TEST_UNIT_READY:
+		i = fsg->cmnd[2];
+		if (i == 0x55)
+			fsg->curlun->switch_flag = 1;
 		fsg->data_size_from_cmnd = 0;
 		reply = check_command(fsg, 6, DATA_DIR_NONE,
 				0, 1,
@@ -3357,6 +3390,13 @@
 
 	case FSG_STATE_CONFIG_CHANGE:
 		rc = do_set_config(fsg, new_config);
+#ifdef CONFIG_USB_GADGET_IUSBC
+		if (!fsg->uevent_flag){
+			struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget);
+			kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_ONLINE);
+			fsg->uevent_flag=1;
+		}
+#endif
 		if (fsg->ep0_req_tag != exception_req_tag)
 			break;
 		if (rc != 0)			// STALL on errors
@@ -3368,6 +3408,13 @@
 	case FSG_STATE_DISCONNECT:
 		fsync_all(fsg);
 		do_set_config(fsg, 0);		// Unconfigured state
+#ifdef CONFIG_USB_GADGET_IUSBC
+		if (fsg->uevent_flag) {
+			struct iusbc *_iusbc=container_of(fsg->gadget,struct iusbc,gadget);
+			kobject_uevent(&(_iusbc->pdev->dev.kobj), KOBJ_OFFLINE);
+			fsg->uevent_flag=0;
+		}
+#endif
 		break;
 
 	case FSG_STATE_EXIT:
@@ -3585,6 +3632,12 @@
 	return rc;
 }
 
+static ssize_t show_switch(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct lun      *curlun = dev_to_lun(dev);
+	
+	return sprintf(buf, "%d\n", curlun->switch_flag);
+}
 
 static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
@@ -3649,6 +3702,7 @@
 /* The write permissions and store_xxx pointers are set in fsg_bind() */
 static DEVICE_ATTR(ro, 0444, show_ro, NULL);
 static DEVICE_ATTR(file, 0444, show_file, NULL);
+static DEVICE_ATTR(switch, 0444, show_switch, NULL);
 
 
 /*-------------------------------------------------------------------------*/
@@ -3684,6 +3738,7 @@
 		if (curlun->registered) {
 			device_remove_file(&curlun->dev, &dev_attr_ro);
 			device_remove_file(&curlun->dev, &dev_attr_file);
+			device_remove_file(&curlun->dev, &dev_attr_switch);
 			device_unregister(&curlun->dev);
 			curlun->registered = 0;
 		}
@@ -3842,6 +3897,7 @@
 
 	for (i = 0; i < fsg->nluns; ++i) {
 		curlun = &fsg->luns[i];
+		curlun->switch_flag = 0;
 		curlun->ro = mod_data.ro[i];
 		curlun->dev.release = lun_release;
 		curlun->dev.parent = &gadget->dev;
@@ -3857,7 +3913,9 @@
 		if ((rc = device_create_file(&curlun->dev,
 					&dev_attr_ro)) != 0 ||
 				(rc = device_create_file(&curlun->dev,
-					&dev_attr_file)) != 0) {
+					&dev_attr_file)) != 0 ||
+				(rc = device_create_file(&curlun->dev,
+					&dev_attr_switch)) != 0) {
 			device_unregister(&curlun->dev);
 			goto out;
 		}
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/gadget_chips.h linux-2.6.24.7-rt20-atom/drivers/usb/gadget/gadget_chips.h
--- linux-2.6.24.7-rt20/drivers/usb/gadget/gadget_chips.h	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/gadget_chips.h	2008-09-28 11:32:46.000000000 +0200
@@ -147,6 +147,11 @@
 #define	gadget_is_m66592(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_IUSBC
+#define gadget_is_iusbc(g)	!strcmp("iusbc", (g)->name)
+#else
+#define gadget_is_iusbc(g)	0
+#endif
 
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
@@ -212,5 +217,7 @@
 		return 0x20;
 	else if (gadget_is_m66592(gadget))
 		return 0x21;
+	else if (gadget_is_iusbc(gadget))
+		return 0x99;
 	return -ENOENT;
 }
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/iusbc.c linux-2.6.24.7-rt20-atom/drivers/usb/gadget/iusbc.c
--- linux-2.6.24.7-rt20/drivers/usb/gadget/iusbc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/iusbc.c	2008-09-28 11:32:46.000000000 +0200
@@ -0,0 +1,3110 @@
+/*
+ * Intel Poulsbo USB Client Controller Driver
+ * Copyright (C) 2006-07, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#define		DEBUG	/* messages on error and most fault paths */
+//#define	VERBOSE	/* extra debug messages (success too) */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Power management */
+#include <linux/pm.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include "iusbc.h"
+
+#define	DRIVER_DESC	"Intel Poulsbo USB Client Controller Driver"
+#define	DRIVER_VERSION	"2.0.0.32L.0009"
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+static const char driver_name [] = "iusbc";
+static const char driver_desc [] = DRIVER_DESC;
+
+static const char *const ep_name [] = {
+	"ep0-in", "ep0-out",
+	"ep1in-bulk", "ep1out-bulk",
+	"ep2in-int", "ep2out-int",
+	"ep3in-iso", "ep3out-iso",
+};
+
+
+/* module parameter */
+
+/* force_fullspeed -- device will be forced to full speed operation
+ * default value: 0 for high speed
+ */
+static int force_fullspeed = 0;
+
+/* modprobe iusbc force_fullspeed=n" etc */
+module_param (force_fullspeed, bool, S_IRUGO);
+
+#define RNDIS_INIT_HW_BUG
+//#define DMA_DISABLED
+
+/*-------------------------------------------------------------------------*/
+/* DEBUGGING */
+#define xprintk(dev,level,fmt,args...) \
+	printk(level "%s %s: " fmt , driver_name , \
+			pci_name(dev->pdev) , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+	xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif	/* VERBOSE */
+
+
+#define ERROR(dev,fmt,args...) \
+	xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+	xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+	xprintk(dev , KERN_INFO , fmt , ## args)
+
+
+#ifdef VERBOSE
+static inline void print_all_registers(struct iusbc_regs *regs)
+{
+	unsigned	i, j;
+	/* device */
+	printk(KERN_DEBUG "----Intel USB-C Memory Space Registers----\n");
+	printk(KERN_DEBUG "Register Length: 0x%x\n",
+			sizeof(struct iusbc_regs));
+	printk(KERN_DEBUG "gcap=0x%08x\n", readl(&regs->gcap));
+	printk(KERN_DEBUG "dev_sts=0x%08x\n", readl(&regs->dev_sts));
+	printk(KERN_DEBUG "frame=0x%04x\n", readw(&regs->frame));
+	printk(KERN_DEBUG "int_sts=0x%08x\n", readl(&regs->int_sts));
+	printk(KERN_DEBUG "int_ctrl=0x%08x\n", readl(&regs->int_ctrl));
+	printk(KERN_DEBUG "dev_ctrl=0x%08x\n", readl(&regs->dev_ctrl));
+
+	/* endpoints */
+	for (i = 0; i < 5; i++) {
+		printk(KERN_DEBUG "ep[%d]_base_low_32=0x%08x\n",
+				i, readl(&regs->ep[i].ep_base_low_32));
+		printk(KERN_DEBUG "ep[%d]_base_hi_32=0x%08x\n",
+				i, readl(&regs->ep[i].ep_base_hi_32));
+		printk(KERN_DEBUG "ep[%d]_len=0x%04x\n",
+				i, readw(&regs->ep[i].ep_len));
+		printk(KERN_DEBUG "ep[%d]_pib=0x%04x\n",
+				i, readw(&regs->ep[i].ep_pib));
+		printk(KERN_DEBUG "ep[%d]_dil=0x%04x\n",
+				i, readw(&regs->ep[i].ep_dil));
+		printk(KERN_DEBUG "ep[%d]_tiq=0x%04x\n",
+				i, readw(&regs->ep[i].ep_tiq));
+		printk(KERN_DEBUG "ep[%d]_max=0x%04x\n",
+				i, readw(&regs->ep[i].ep_max));
+		printk(KERN_DEBUG "ep[%d]_sts=0x%04x\n",
+				i, readw(&regs->ep[i].ep_sts));
+		printk(KERN_DEBUG "ep[%d]_cfg=0x%04x\n",
+				i, readw(&regs->ep[i].ep_cfg));
+
+		if (1 == i) {	/* ep0-out */
+			printk(KERN_DEBUG "ep-out setup_pkt_sts=0x%02x\n",
+					readb(&regs->ep[i].setup_pkt_sts));
+			for (j = 0; j< 8; j++) {
+				printk(KERN_DEBUG "ep0-out "
+					"setup_pkt[%d]=0x%02x\n",
+					j, readb(&regs->ep[i].setup_pkt[j]));
+			}
+		}
+	}
+}
+
+#endif /* VERBOSE */
+
+/*-------------------------------------------------------------------------*/
+
+#define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+
+#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG)
+static char *type_string(u8 bmAttributes)
+{
+	switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
+		return "bulk";
+	case USB_ENDPOINT_XFER_ISOC:
+		return "iso";
+	case USB_ENDPOINT_XFER_INT:
+		return "int";
+	};
+
+	return "control";
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* configure endpoint, making it usable */	
+static int
+iusbc_ep_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct iusbc		*dev;
+	struct iusbc_ep		*ep;
+	u16			val_16, max;
+	u8			val_8;
+	unsigned long		flags;
+	unsigned		i;
+	int			retval;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	DEBUG(ep->dev, "---> iusbc_ep_enable() \n");
+
+	if (!_ep || !desc || _ep->name == "ep0-in"
+			|| _ep->name == "ep0-out"
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* wMaxPacketSize up to 1024 bytes */
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	ep->ep.maxpacket = max;
+	if (!ep->desc)
+		ep->desc = desc;
+
+	/* ep_reset() has already been called */
+	ep->stopped = 0;
+	ep->out_overflow = 0;
+	ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0;
+
+	/* sanity check type, direction, address */
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
+		if ((dev->gadget.speed == USB_SPEED_HIGH
+					&& max != 512)
+				|| (dev->gadget.speed == USB_SPEED_FULL
+					&& max > 64)) {
+			goto done;
+		}
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
+			goto done;
+
+		switch (dev->gadget.speed) {
+		case USB_SPEED_HIGH:
+			if (max <= 1024)
+				break;
+		case USB_SPEED_FULL:
+			if (max <= 64)
+				break;
+		default:
+			if (max <= 8)
+				break;
+			goto done;
+		}
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (strstr (ep->ep.name, "-bulk")
+				|| strstr (ep->ep.name, "-int"))
+			goto done;
+
+		switch (dev->gadget.speed) {
+		case USB_SPEED_HIGH:
+			if (max <= 1024)
+				break;
+		case USB_SPEED_FULL:
+			if (max <= 1023)
+				break;
+		default:
+			goto done;
+		}
+		break;
+	default:
+		goto done;
+	}
+
+	/* ep_type */
+	ep->ep_type = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+
+	/* DMA modes, only support Linear Mode now */
+	if (ep->dev->sg_mode_dma) {
+		ep->dma_mode = SCATTER_GATHER_MODE;
+	} else {
+		ep->dma_mode = LINEAR_MODE;
+	}
+
+	/* reset ep registers to default value */
+	i = ep->num;
+	writew(0, &dev->regs->ep[i].ep_cfg);
+
+	/* set endpoints valid */
+	val_16 = readw(&dev->regs->ep[i].ep_cfg);
+	val_16 |= INTR_BAD_PID_TYPE
+		| INTR_CRC_ERROR
+		| INTR_FIFO_ERROR
+		| INTR_DMA_ERROR
+		| INTR_TRANS_COMPLETE
+		/* | INTR_PING_NAK_SENT */
+		| INTR_DMA_IOC
+		| ep->dma_mode << 6
+		| ep->ep_type << 4 
+		/* | EP_ENABLE */
+		| EP_VALID;
+
+	/* will set EP_ENABLE later to start dma */
+	writew(val_16, &dev->regs->ep[i].ep_cfg);
+
+	val_16 = readw(&dev->regs->ep[i].ep_cfg);
+	VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16);
+
+	val_8 = desc->bEndpointAddress;
+	DEBUG(dev, "enabled %s (ep%d%s-%s), max %04x, dma_mode: %02x\n",
+			_ep->name,
+			val_8 & USB_ENDPOINT_NUMBER_MASK,
+			DIR_STRING(val_8),
+			type_string(desc->bmAttributes),
+			max,
+			ep->dma_mode);
+
+	retval = 0;
+done:
+	spin_unlock_irqrestore(&dev->lock, flags);
+	DEBUG(ep->dev, "<--- iusbc_ep_enable() \n");
+	return retval;
+}
+
+
+static const struct usb_ep_ops iusbc_ep_ops;
+
+static void ep_reset(struct iusbc_regs __iomem *regs, struct iusbc_ep *ep)
+{
+	unsigned	i = ep->num;
+
+	/* reset ep values */
+	ep->stopped = 1;
+	ep->ep.maxpacket = ~0;
+	ep->ep.ops = &iusbc_ep_ops;
+
+	/* reset ep registers to default value
+	 * clear all interrupt and status
+	 * clear and reset all DMA FIFOs and state machine
+	 * hardware shall minimize power usage
+	 */
+	writew(0, &regs->ep[i].ep_cfg);
+}
+
+
+static void nuke(struct iusbc_ep *);
+
+/* endpoint is no longer usable */
+static int
+iusbc_ep_disable(struct usb_ep *_ep)
+{
+	struct iusbc_ep		*ep;
+	unsigned long		flags;
+	struct iusbc		*dev;
+	unsigned		i;
+	u16			val_16;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	VDEBUG(ep->dev, "---> iusbc_ep_disable() \n");
+
+	if (!_ep || !ep->desc
+		|| _ep->name == "ep0-in"
+		|| _ep->name == "ep0-out")
+		return -EINVAL;
+
+	dev = ep->dev;
+	if (dev->ep0state == EP0_SUSPEND)
+		return -EBUSY;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	nuke(ep);
+	ep_reset(ep->dev->regs, ep);
+
+	i = ep->num;
+
+	/* display endpoint configuration register */
+	val_16 = readw(&dev->regs->ep[i].ep_cfg);
+	VDEBUG(dev, "%s.ep_cfg = 0x%04x\n", _ep->name, val_16);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DEBUG(ep->dev, "disabled %s\n", _ep->name);
+
+	VDEBUG(ep->dev, "<--- iusbc_ep_disable() \n");
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate a request object to use with this endpoint */
+static struct usb_request *
+iusbc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct iusbc_ep		*ep;
+	struct iusbc_request	*req;
+	struct iusbc_dma	*td;
+
+	if (!_ep)
+		return NULL;
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	VDEBUG(ep->dev, "---> iusbc_alloc_request() \n");
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&req->queue);
+
+	/* this dma descriptor may be swapped with the previous dummy */
+	td = pci_pool_alloc(ep->dev->requests,
+			gfp_flags,
+			&req->td_dma);
+
+	if (!td) {
+		kfree(req);
+		return NULL;
+	}
+
+	td->dmacount = 0;	/* not VALID */
+	td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
+
+	req->td = td;
+
+	VDEBUG(ep->dev, "alloc request for %s\n", _ep->name);
+
+	VDEBUG(ep->dev, "<--- iusbc_alloc_request() \n");
+
+	return &req->req;
+}
+
+
+/* frees a request object */
+static void
+iusbc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct iusbc_ep		*ep;
+	struct iusbc_request	*req;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	VDEBUG(ep->dev, "---> iusbc_free_request() \n");
+
+	if (!_ep || !_req)
+		return;
+
+	req = container_of(_req, struct iusbc_request, req);
+
+	WARN_ON(!list_empty(&req->queue));
+
+	if (req->td)
+		pci_pool_free(ep->dev->requests, req->td, req->td_dma);
+
+	kfree(req);
+
+	VDEBUG(ep->dev, "free request for %s\n", _ep->name);
+
+	VDEBUG(ep->dev, "<--- iusbc_free_request() \n");
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate an I/O buffer
+ *
+ * dma-coherent memory allocation
+ *
+ * NOTE: the dma_*_coherent() API calls suck.  Most implementations are
+ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
+ * respect to calls with irqs disabled:  alloc is safe, free is not.
+ * We currently work around (b), but not (a).
+ */
+static void *
+iusbc_alloc_buffer(
+	struct usb_ep		*_ep,
+	unsigned		bytes,
+	dma_addr_t		*dma,
+	gfp_t			gfp_flags
+)
+{
+	void			*retval;
+	struct iusbc_ep		*ep;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	VDEBUG(ep->dev, "---> iusbc_alloc_buffer() \n");
+
+	if (!_ep)
+		return NULL;
+
+	*dma = DMA_ADDR_INVALID;
+
+	retval = dma_alloc_coherent(&ep->dev->pdev->dev,
+				bytes, dma, gfp_flags);
+
+	DEBUG(ep->dev, "alloc buffer for %s\n", _ep->name);
+
+	VDEBUG(ep->dev, "<--- iusbc_alloc_buffer() \n");
+
+	return retval;
+}
+
+
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+	struct list_head	list;
+	struct device		*dev;
+	unsigned		bytes;
+	dma_addr_t		dma;
+};
+
+
+static void do_free(unsigned long ignored)
+{
+#ifdef VERBOSE
+	printk(KERN_DEBUG "---> do_free() \n");
+#endif
+
+	spin_lock_irq(&buflock);
+	while (!list_empty(&buffers)) {
+		struct free_record	*buf;
+
+		buf = list_entry(buffers.next, struct free_record, list);
+		list_del(&buf->list);
+		spin_unlock_irq(&buflock);
+
+		dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+		spin_lock_irq(&buflock);
+	}
+	spin_unlock_irq(&buflock);
+
+#ifdef VERBOSE
+	printk(KERN_DEBUG "<--- do_free() \n");
+#endif
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
+/* free an I/O buffer */
+static void
+iusbc_free_buffer(
+	struct usb_ep	*_ep,
+	void		*address,
+	dma_addr_t	dma,
+	unsigned	bytes
+) {
+
+	/* free memory into the right allocator */
+	if (dma != DMA_ADDR_INVALID) {
+		struct iusbc_ep	*ep;
+		struct free_record	*buf = address;
+		unsigned long		flags;
+
+		ep = container_of(_ep, struct iusbc_ep, ep);
+
+		VDEBUG(ep->dev, "---> iusbc_free_buffer() \n");
+
+		if (!_ep)
+			return;
+
+		buf->dev = &ep->dev->pdev->dev;
+		buf->bytes = bytes;
+		buf->dma = dma;
+
+		spin_lock_irqsave(&buflock, flags);
+		list_add_tail(&buf->list, &buffers);
+		tasklet_schedule(&deferred_free);
+		spin_unlock_irqrestore(&buflock, flags);
+
+		DEBUG(ep->dev, "free buffer for %s\n", _ep->name);
+		VDEBUG(ep->dev, "<--- iusbc_free_buffer() \n");
+
+	} else
+		kfree(address);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fill out dma descriptor to match a given request */
+static void
+fill_dma(struct iusbc_ep *ep, struct iusbc_request *req)
+{
+	struct iusbc_dma	*td = req->td;
+	u16			dmacount;
+
+	VDEBUG(ep->dev, "---> fill_dma() \n");
+
+	dmacount = req->req.length;
+
+	td->dmaaddr = cpu_to_le32(req->req.dma);
+	td->dmacount = cpu_to_le16(dmacount);
+
+	VDEBUG(ep->dev, "<--- fill_dma() \n");
+}
+
+
+static void start_dma(struct iusbc_ep *ep, struct iusbc_request *req)
+{
+	u16		val_16;		
+	u32		val_32;
+	unsigned	i;
+
+	VDEBUG(ep->dev, "---> start_dma() \n");
+
+	i = ep->num;
+
+	/* init req->td, pointing to the current dummy */
+	fill_dma(ep, req);
+
+	/* ep_base_low_32 */
+	writel(cpu_to_le32(req->req.dma),
+			&ep->dev->regs->ep[i].ep_base_low_32);
+	val_32 = readl(&ep->dev->regs->ep[i].ep_base_low_32);
+	VDEBUG(ep->dev, "%s.ep_base_low_32=0x%08x\n",
+			ep->ep.name, val_32);
+
+	/* ep_base_hi_32 */
+	writel(0, &ep->dev->regs->ep[i].ep_base_hi_32);
+	val_32 = readl(&ep->dev->regs->ep[i].ep_base_hi_32);
+	VDEBUG(ep->dev, "%s.ep_base_hi_32=0x%08x\n",
+			ep->ep.name, val_32);
+
+	writew(le16_to_cpu(req->td->dmacount), &ep->dev->regs->ep[i].ep_len);
+	val_16 = readw(&ep->dev->regs->ep[i].ep_len);
+	VDEBUG(ep->dev, "%s.ep_len=0x%04x\n",
+			ep->ep.name, val_16);
+
+	/* endpoint maximum transaction size, up to 1024 Bytes */
+	writew((ep->ep.maxpacket & 0x3ff),
+			&ep->dev->regs->ep[i].ep_max);
+	val_16 = readw(&ep->dev->regs->ep[i].ep_max);
+	VDEBUG(ep->dev, "%s.ep_max=0x%04x\n",
+			ep->ep.name, val_16);
+
+	/* validate endpoint, enable DMA */
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	val_16 |= EP_VALID | EP_ENABLE;
+	writew(val_16, &ep->dev->regs->ep[i].ep_cfg);
+
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	VDEBUG(ep->dev, "enable %s DMA transfer...\n",
+			ep->ep.name);
+	VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n",
+			ep->ep.name, val_16);
+
+	VDEBUG(ep->dev, "<--- start_dma() \n");
+}
+
+
+/* queues I/O requests in endpoint queue  */
+static inline void
+queue_dma(struct iusbc_ep *ep, struct iusbc_request *req)
+{
+	struct iusbc_dma	*end;
+	dma_addr_t		tmp_dma_addr;
+
+	VDEBUG(ep->dev, "---> queue_dma() \n");
+
+	/* swap new dummy for old, link; fill and maybe activate */
+	end = ep->dummy;
+	ep->dummy = req->td;
+	req->td = end;
+
+	tmp_dma_addr = ep->td_dma;
+	ep->td_dma = req->td_dma;
+	req->td_dma = tmp_dma_addr;
+
+	fill_dma(ep, req);
+
+	VDEBUG(ep->dev, "<--- queue_dma() \n");
+}
+
+
+static void
+done(struct iusbc_ep *ep, struct iusbc_request *req, int status)
+{
+	struct iusbc		*dev;
+	unsigned		stopped = ep->stopped;
+
+	VDEBUG(ep->dev, "---> done() \n");
+
+	list_del_init(&req->queue);
+
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	dev = ep->dev;
+
+	if (req->mapped) {
+		pci_unmap_single(dev->pdev, req->req.dma, req->req.length,
+			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+	if (status != -ESHUTDOWN)
+		DEBUG(dev, "complete %s, req %p, stat %d, len %u/%u\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+
+	/* XXX WORKAROUND: first ep0-out OUT packet HW BUG */
+#ifdef RNDIS_INIT_HW_BUG
+	if (ep->num == 1) {
+		char *buf;
+		const u8 remote_ndis_initialize_msg[24] = {
+			0x02, 0x00, 0x00, 0x00,
+			0x18, 0x00, 0x00, 0x00,
+			0x02, 0x00, 0x00, 0x00,
+			0x01, 0x00, 0x00, 0x00,
+			0x00, 0x00, 0x00, 0x00,
+			0x00, 0x04, 0x00, 0x00
+		};
+
+		buf = req->req.buf;
+
+		/* req->buf haven't been DMAed for hardware bug? */
+		if ((buf[0] == 0x9) && (buf[1] == 0x02)) {
+			memcpy(buf, remote_ndis_initialize_msg, 24);
+			DEBUG(ep->dev, "WORKAROUND HW BUG: ep0-out OUT\n");
+		}
+	}
+#endif
+	/* XXX */
+
+	spin_unlock(&dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&dev->lock);
+	ep->stopped = stopped;
+
+	VDEBUG(ep->dev, "<--- done() \n");
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* queues (submits) an I/O requests to an endpoint */
+static int
+iusbc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct iusbc_request	*req;
+	struct iusbc_ep		*ep;
+	struct iusbc		*dev;
+	unsigned long		flags;
+	u16			val_16;
+	unsigned		zlflag = 0;
+
+	/* always require a cpu-view buffer */
+	req = container_of(_req, struct iusbc_request, req);
+	ep = container_of(_ep, struct iusbc_ep, ep);
+	dev = ep->dev;
+	VDEBUG(ep->dev, "---> iusbc_queue() \n");
+
+	VDEBUG(ep->dev, "_req=%p, complete=%p, buf=%p, list_empty=%d\n",
+			_req, _req->complete,
+			_req->buf,
+			list_empty(&req->queue));
+
+	if (dev->ep0state == EP0_DISCONNECT || ep->stopped)
+		return -EINVAL;
+
+	if (!_req || !_req->complete || !_req->buf
+			|| !list_empty(&req->queue))
+		return -EINVAL;
+
+	if (!_ep || (!ep->desc && ep->num > 1))
+		return -EINVAL;
+
+	dev = ep->dev;
+
+	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
+		return -ESHUTDOWN;
+
+	/* can't touch registers when suspended */
+	if (dev->ep0state == EP0_SUSPEND)
+		return -EBUSY;
+
+	/* set up dma mapping in case the caller didn't */
+	if (_req->dma == DMA_ADDR_INVALID) {
+		/* WORKAROUND: WARN_ON(size == 0) */
+		if (_req->length == 0) {
+			VDEBUG(dev, "req->length: 0->1\n");
+			zlflag = 1;
+			_req->length++;
+		}
+
+		_req->dma = pci_map_single(dev->pdev, _req->buf, _req->length,
+			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+		if (zlflag && (_req->length == 1)) {
+			VDEBUG(dev, "req->length: 1->0\n");
+			zlflag = 0;
+			_req->length = 0;
+		}
+
+		req->mapped = 1;
+	}
+
+	DEBUG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n",
+			_ep->name, _req, _req->length,
+			_req->buf, _req->dma);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* set ZLP flag for ep0-in, when writting data,
+	 * makes the last packet be "short" by adding a zero
+	 * length packet as needed
+	 */
+	if (unlikely(ep->num == 0 && ep->is_in))
+		_req->zero = 1;
+
+	/* kickstart this I/O queue */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		start_dma(ep, req);
+
+		val_16 = readw(&ep->dev->regs->ep[ep->num].ep_pib);
+		VDEBUG(ep->dev, "after dma, %s.ep_pib = 0x%04x\n",
+				_ep->name, val_16);
+
+		val_16 = readw(&ep->dev->regs->ep[ep->num].ep_sts);
+		VDEBUG(ep->dev, "after dma, %s.ep_sts = 0x%04x\n",
+				_ep->name, val_16);
+	} else {
+		queue_dma(ep, req);
+		VDEBUG(ep->dev, "%s queue_dma()\n", _ep->name);
+	}
+
+	ep->responded = 1;
+	if (likely(req != 0)) {
+		list_add_tail(&req->queue, &ep->queue);
+		VDEBUG(ep->dev, "list_add_tail() \n");
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	VDEBUG(ep->dev, "<--- iusbc_queue() \n");
+
+	return 0;
+}
+
+
+static inline void
+dma_done(struct iusbc_ep *ep, struct iusbc_request *req, int status)
+{
+	unsigned	i;
+	VDEBUG(ep->dev, "---> dma_done() \n");
+
+	i = ep->num;
+	req->req.actual = readw(&ep->dev->regs->ep[i].ep_pib);
+	VDEBUG(ep->dev, "req->req.actual = %d\n", req->req.actual);
+
+	done(ep, req, status);
+
+	VDEBUG(ep->dev, "<--- dma_done() \n");
+}
+
+
+/* restart dma in endpoint */
+static void restart_dma(struct iusbc_ep *ep)
+{
+	struct iusbc_request	*req;
+
+	VDEBUG(ep->dev, "---> restart_dma() \n");
+
+	if (ep->stopped)
+		return;
+
+	req = list_entry(ep->queue.next, struct iusbc_request, queue);
+	start_dma(ep, req);
+
+	VDEBUG(ep->dev, "<--- restart_dma() \n");
+
+	return;
+}
+
+
+/* dequeue ALL requests */
+static void nuke(struct iusbc_ep *ep)
+{
+	struct iusbc_request	*req;
+
+	VDEBUG(ep->dev, "---> nuke() \n");
+
+	/* called with spinlock held */
+	ep->stopped = 1;
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+				struct iusbc_request,
+				queue);
+		done(ep, req, -ESHUTDOWN);
+	}
+
+	VDEBUG(ep->dev, "<--- nuke() \n");
+}
+
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int
+iusbc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct iusbc_ep		*ep;
+	struct iusbc		*dev;
+	struct iusbc_request	*req;
+	unsigned long		flags;
+	int			stopped;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	VDEBUG(ep->dev, "---> iusbc_dequeue() \n");
+
+	if (!_ep || (!ep->desc && ep->num > 1) || !_req)
+		return -EINVAL;
+
+	dev = ep->dev;
+
+	if (!dev->driver)
+		return -ESHUTDOWN;
+
+	/* can't touch registers when suspended */
+	if (dev->ep0state == EP0_SUSPEND)
+		return -EBUSY;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	stopped = ep->stopped;
+
+	/* quiesce dma while we patch the queue */
+	ep->stopped = 1;
+
+	/* make sure it's still queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+
+	/* queue head may be partially complete. */
+	if (ep->queue.next == &req->queue) {
+		DEBUG(ep->dev, "unlink (%s) dma\n", _ep->name);
+		_req->status = -ECONNRESET;
+		if (likely(ep->queue.next == &req->queue)) {
+			req->td->dmacount = 0;	/* invalidate */
+			dma_done(ep, req, -ECONNRESET);
+		}
+		req = NULL;
+	}
+
+	if (req)
+		done(ep, req, -ECONNRESET);
+
+	ep->stopped = stopped;
+
+	if (!list_empty(&ep->queue) && (!ep->stopped)) {
+		/* resume current request, or start new one */
+		if (!req)
+			start_dma(ep, list_entry(ep->queue.next,
+				struct iusbc_request, queue));
+	}
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	VDEBUG(ep->dev, "<--- iusbc_dequeue() \n");
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ep0_start(struct iusbc *dev);
+static void ep_ack(struct iusbc_ep *ep);
+static int iusbc_ep_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc);
+
+static void clear_halt(struct iusbc_ep *ep)
+{
+	u16		 	val_16;
+	unsigned		i = ep->num;
+	int			rc = 0;
+	struct iusbc_request	*req;
+	const struct usb_endpoint_descriptor	*desc;
+
+	DEBUG(ep->dev, "---> clear_halt() \n");
+
+	/* validate and enable endpoint */
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	val_16 |= EP_VALID | EP_ENABLE;
+	writew(val_16, &ep->dev->regs->ep[i].ep_cfg);
+
+	/* re-enable endpoint */
+	if (i < 2) {	/* ep0-in and ep0-out */
+		ep0_start(ep->dev);
+	} else {
+		spin_unlock_irq(&ep->dev->lock);
+		/* remember ep->desc */
+		desc = ep->desc;
+		rc = iusbc_ep_enable(&ep->ep, desc);
+		if (rc) {
+			DEBUG(ep->dev, "re-enable error: %d\n", rc);
+		}
+		spin_lock_irq(&ep->dev->lock);
+	}
+
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16);
+
+	ep->stopped = 0;
+	if (list_empty(&ep->queue))
+		return;
+
+	req = list_entry(ep->queue.next, struct iusbc_request,queue);
+	start_dma(ep, req);
+
+	DEBUG(ep->dev, "<--- clear_halt() \n");
+}
+
+
+static void set_halt(struct iusbc_ep *ep)
+{
+	u16		val_16;
+	unsigned	i = ep->num;
+
+	DEBUG(ep->dev, "---> set_halt() \n");
+
+	/* reset data buffer zero length */
+	writew(0, &ep->dev->regs->ep[i].ep_len);
+
+	/* invalidate and disable endpoint */
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	val_16 &= (~EP_VALID & ~EP_ENABLE);
+	writew(val_16, &ep->dev->regs->ep[i].ep_cfg);
+
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	DEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16);
+
+	ep->stopped = 1;
+
+	DEBUG(ep->dev, "<--- set_halt() \n");
+}
+
+
+static int iusbc_fifo_status(struct usb_ep *_ep);
+
+/* sets the endpoint halt feature */
+static int
+iusbc_set_halt(struct usb_ep *_ep, int value)
+{
+	struct iusbc_ep		*ep;
+	unsigned long		flags;
+	int			retval = 0;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	DEBUG(ep->dev, "---> iusbc_set_halt() \n");
+
+	if (!_ep || (!ep->desc && ep->num > 1))
+		return -EINVAL;
+
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	if (ep->desc && (ep->desc->bmAttributes & 0x03)
+			== USB_ENDPOINT_XFER_ISOC)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+
+	/* transfer requests are still queued */
+	if (!list_empty(&ep->queue))
+		retval = -EAGAIN;
+
+	else if (ep->is_in && value && iusbc_fifo_status(_ep) != 0) {
+		/* FIFO holds bytes, the host hasn't collected */
+		DEBUG(ep->dev, "%s FIFO holds bytes\n", _ep->name);
+
+		/* reset position in buffer register */
+		writew(0, &ep->dev->regs->ep[ep->num].ep_pib);
+
+		retval = -EAGAIN;
+	} else {
+		DEBUG(ep->dev, "%s %s halt\n", _ep->name,
+				value ? "set" : "clear");
+		/* set/clear, then synch memory views with the device */
+		if (value) {
+			if (ep->num < 2) { /* ep0-in/out */
+				ep->dev->ep0state = EP0_STALL;
+				VDEBUG(ep->dev, "ep0state: EP0_STALL\n");
+			} else {
+				set_halt(ep);
+				ep_ack(&ep->dev->ep[0]);
+			}
+		} else {
+			clear_halt(ep);
+			ep_ack(&ep->dev->ep[0]);
+		}
+
+	}
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	DEBUG(ep->dev, "<--- iusbc_set_halt() \n");
+
+	return retval;
+}
+
+
+/* return number of bytes in fifo, or error */
+static int
+iusbc_fifo_status(struct usb_ep *_ep)
+{
+	struct iusbc_ep		*ep;
+	unsigned		i;
+	u16			nbytes, fifo_size;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	DEBUG(ep->dev, "---> iusbc_fifo_status() \n");
+
+	if (!_ep || (!ep->desc && ep->num > 1))
+		return -ENODEV;
+
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	i = ep->num;
+	fifo_size = readw(&ep->dev->regs->ep[i].ep_len);
+	nbytes = readw(&ep->dev->regs->ep[i].ep_pib);
+
+	if (nbytes > fifo_size)
+		return -EOVERFLOW;
+
+	DEBUG(ep->dev, "%s, 0x%04x bytes (%s) in FIFO\n",
+			_ep->name, nbytes, ep->is_in? "IN" : "OUT");
+
+	DEBUG(ep->dev, "<--- iusbc_fifo_status() \n");
+
+	return nbytes;
+}
+
+
+static void ep_nak(struct iusbc_ep *ep);
+
+/* flushes contents of a fifo */
+static void
+iusbc_fifo_flush(struct usb_ep *_ep)
+{
+	struct iusbc_ep		*ep;
+	unsigned		i;
+	u16			val_16;
+
+	ep = container_of(_ep, struct iusbc_ep, ep);
+
+	DEBUG(ep->dev, "---> iusbc_fifo_flush() \n");
+
+	if (!_ep || (!ep->desc && ep->num > 1)){
+		VDEBUG(ep->dev, "XXX: return from iusbc_fifo_flush()\n");
+		return;
+	}
+
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return;
+
+	i = ep->num;
+
+	/* FIXME: remove it ? */
+	ep_nak(ep);
+
+	/* reset position in buffer register */
+	val_16 = readw(&ep->dev->regs->ep[i].ep_pib);
+	DEBUG(ep->dev, "%s.ep_pib = 0x%04x\n", _ep->name, val_16);
+	writew(0, &ep->dev->regs->ep[i].ep_pib);
+
+	DEBUG(ep->dev, "<--- iusbc_fifo_flush() \n");
+}
+
+static const struct usb_ep_ops iusbc_ep_ops = {
+
+	/* configure endpoint, making it usable */	
+	.enable		= iusbc_ep_enable,
+
+	/* endpoint is no longer usable */
+	.disable	= iusbc_ep_disable,
+
+	/* allocate a request object to use with this endpoint */
+	.alloc_request	= iusbc_alloc_request,
+
+	/* frees a request object */
+	.free_request	= iusbc_free_request,
+
+	/* allocate an I/O buffer */
+	/*.alloc_buffer	= iusbc_alloc_buffer,*/
+
+	/* free an I/O buffer */
+	/*.free_buffer	= iusbc_free_buffer,*/
+
+	/* queues (submits) an I/O requests to an endpoint */
+	.queue		= iusbc_queue,
+
+	/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+	.dequeue	= iusbc_dequeue,
+
+	/* sets the endpoint halt feature */
+	.set_halt	= iusbc_set_halt,
+
+	/* return number of bytes in fifo, or error */
+	.fifo_status	= iusbc_fifo_status,
+
+	/* flushes contents of a fifo */
+	.fifo_flush	= iusbc_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* returns the current frame number */
+static int iusbc_get_frame(struct usb_gadget *_gadget)
+{
+	struct iusbc		*dev;
+	unsigned long		flags;
+	u16			retval;
+
+	if (!_gadget)
+		return -ENODEV;
+
+	dev = container_of(_gadget, struct iusbc, gadget);
+
+	VDEBUG(dev, "---> iusbc_get_frame() \n");
+
+	spin_lock_irqsave(&dev->lock, flags);
+	retval = readw(&dev->regs->frame);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	VDEBUG(dev, "<--- iusbc_get_frame() \n");
+
+	return retval;
+}
+
+
+/* TODO: wakeup host function */
+/* tries to wake up the host connected to this gadget */
+static int iusbc_wakeup(struct usb_gadget *_gadget)
+{
+	struct iusbc		*dev;
+
+	if (!_gadget)
+		return 0;
+
+	dev = container_of(_gadget, struct iusbc, gadget);
+
+	VDEBUG(dev, "---> iusbc_wakeup() \n");
+
+	/* TODO: spec 4.3 */
+
+	VDEBUG(dev, "<--- iusbc_wakeup() \n");
+
+	return 0;
+}
+
+
+/* software-controlled connect/disconnect to USB host */
+static int iusbc_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct iusbc	*dev;
+	u32             val_32;
+	unsigned long   flags;
+
+	if (!_gadget)
+		return -ENODEV;
+	dev = container_of(_gadget, struct iusbc, gadget);
+
+	VDEBUG(dev, "---> iusbc_pullup() \n");
+
+	spin_lock_irqsave(&dev->lock, flags);
+	val_32 = readl(&dev->regs->dev_ctrl);
+	dev->connected = (is_on != 0);
+	if (is_on)
+		val_32 |= CONNECTION_ENABLE;
+	else
+		val_32 &= ~CONNECTION_ENABLE;
+
+	writel(val_32, &dev->regs->dev_ctrl);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	VDEBUG(dev, "<--- iusbc_pullup() \n");
+
+	return 0;
+}
+
+
+static const struct usb_gadget_ops iusbc_ops = {
+
+	/* returns the current frame number */
+	.get_frame	= iusbc_get_frame,
+
+	/* TODO */
+	/* tries to wake up the host connected to this gadget */
+	.wakeup		= iusbc_wakeup,
+
+	/* software-controlled connect/disconnect to USB host */
+	.pullup		= iusbc_pullup,
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
+
+/* "function" sysfs attribute */
+static ssize_t
+show_function(struct device *_dev, struct device_attribute *attr, char *buf)
+{
+	struct iusbc	*dev = dev_get_drvdata(_dev);
+
+	if (!dev->driver
+			|| !dev->driver->function
+			|| strlen(dev->driver->function) > PAGE_SIZE)
+		return 0;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function);
+}
+static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
+
+
+static ssize_t
+show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
+{
+	struct iusbc		*dev;
+	char			*next;
+	unsigned		size;
+	unsigned		t;
+	unsigned		i;
+	unsigned long		flags;
+	const char		*name;
+	const char		*speed;
+
+	dev = dev_get_drvdata(_dev);
+	next = buf;
+	size = PAGE_SIZE;
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (dev->driver)
+		name = dev->driver->driver.name;
+	else
+		name = "(none)";
+
+	if (dev->gadget.speed == USB_SPEED_HIGH)
+		speed = "high speed";
+	else if (dev->gadget.speed == USB_SPEED_FULL)
+		speed = "full speed";
+	else 
+		speed = "unknown speed";
+
+	/* device information */
+	t = scnprintf(next, size,
+			"%s %s - %s\n"
+			"Version: %s\n"
+			"Gadget driver: %s\n"
+			"Speed mode: %s\n",
+			driver_name, pci_name(dev->pdev), driver_desc,
+			DRIVER_VERSION, 
+			name,
+			speed);
+	size -= t;
+	next += t;
+
+	/* device memory space registers */
+	t = scnprintf(next, size,
+			"\nDevice registers:\n"
+			"\tgcap=0x%08x\n"
+			"\tdev_sts=0x%08x\n"
+			"\tframe=0x%04x\n"
+			"\tint_sts=0x%08x\n"
+			"\tint_ctrl=0x%08x\n"
+			"\tdev_ctrl=0x%08x\n",
+			readl(&dev->regs->gcap),
+			readl(&dev->regs->dev_sts),
+			readw(&dev->regs->frame),
+			readl(&dev->regs->int_sts),
+			readl(&dev->regs->int_ctrl),
+			readl(&dev->regs->dev_ctrl)
+			);
+	size -= t;
+	next += t;
+
+	/* endpoints memory space registers */
+	t = scnprintf(next, size, "\nEndpoints registers:\n");
+	size -= t;
+	next += t;
+
+	for (i = 0; i < 5; i++) {
+		struct iusbc_ep		*ep;
+		ep = &dev->ep[i];
+
+		if (i > 1 && !ep->desc)
+			continue;
+
+		name = ep->ep.name;
+		t = scnprintf(next, size,
+				"\t%s.ep_base_low_32=0x%08x\n"
+				"\t%s.ep_base_hi_32=0x%08x\n"
+				"\t%s.ep_len=0x%04x\n"
+				"\t%s.ep_pib=0x%04x\n"
+				"\t%s.ep_dil=0x%04x\n"
+				"\t%s.ep_tiq=0x%04x\n"
+				"\t%s.ep_max=0x%04x\n"
+				"\t%s.ep_sts=0x%04x\n"
+				"\t%s.ep_cfg=0x%04x\n",
+				name, readl(&dev->regs->ep[i].ep_base_low_32),
+				name, readl(&dev->regs->ep[i].ep_base_hi_32),
+				name, readw(&dev->regs->ep[i].ep_len),
+				name, readw(&dev->regs->ep[i].ep_pib),
+				name, readw(&dev->regs->ep[i].ep_dil),
+				name, readw(&dev->regs->ep[i].ep_tiq),
+				name, readw(&dev->regs->ep[i].ep_max),
+				name, readw(&dev->regs->ep[i].ep_sts),
+				name, readw(&dev->regs->ep[i].ep_cfg)
+			     );
+		size -= t;
+		next += t;
+	}
+
+	/* ep0-out setup packet registers */
+	t = scnprintf(next, size,
+			"\tsetup_pkt_sts=0x%02x\n",
+			readb(&dev->regs->ep[1].setup_pkt_sts)
+		     );
+	size -= t;
+	next += t;
+
+	for (i = 0; i < 8; i++) {
+		t = scnprintf(next, size,
+				"\tsetup_pkt[%d]=0x%02x\n",
+				i,
+				readb(&dev->regs->ep[1].setup_pkt[i])
+				);
+		size -= t;
+		next += t;
+	}
+
+	/* Irq statistics */
+	t = scnprintf(next, size, "\nIrq statistics:\n");
+	size -= t;
+	next += t;
+
+	for (i = 0; i < 5; i++) {
+		struct iusbc_ep	*ep;
+		ep = &dev->ep[i];
+
+		if (i && !ep->irqs)
+			continue;
+
+		t = scnprintf(next, size,
+				"\t%s/%lu\n",
+				ep->ep.name, ep->irqs);
+		size -= t;
+		next += t;
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
+
+
+static ssize_t
+show_queues(struct device *_dev, struct device_attribute *attr, char *buf)
+{
+	struct iusbc		*dev;
+	char			*next;
+	unsigned		size, i;
+	unsigned long		flags;
+
+	dev = dev_get_drvdata(_dev);
+	next = buf;
+	size = PAGE_SIZE;
+	spin_lock_irqsave(&dev->lock, flags);
+
+	for (i = 0; i < 5; i++) {
+		struct iusbc_ep		*ep = &dev->ep[i];
+		struct iusbc_request	*req;
+		struct iusbc_dma	*td;
+		int			t;
+		int			addr;
+
+		if (i > 1 && !ep->desc)
+			continue;
+
+		/* ep0-in, ep0-out */
+		if (i == 0 || i == 1) {
+			t = scnprintf(next, size,
+				"%s (ep%d%s-%s), "
+				"max %04x, dma_mode: %02x\n",
+				ep->ep.name,
+				0,
+				ep->is_in ? "in" : "out",
+				"control",
+				ep->ep.maxpacket,
+				ep->dma_mode);
+		} else {
+			addr = ep->desc->bEndpointAddress;
+			t = scnprintf(next, size,
+				"\n%s (ep%d%s-%s), "
+				"max %04x, dma_mode: %02x\n",
+				ep->ep.name,
+				addr & USB_ENDPOINT_NUMBER_MASK,
+				DIR_STRING(addr),
+				type_string(ep->desc->bmAttributes),
+				ep->ep.maxpacket,
+				ep->dma_mode);
+		}
+
+		if (t <= 0 || t > size)
+			goto done;
+
+		size -= t;
+		next += t;
+
+		if (list_empty(&ep->queue)) {
+			t = scnprintf(next, size, "\t(nothing queued)\n");
+			if (t <= 0 || t > size)
+				goto done;
+
+			size -= t;
+			next += t;
+			continue;
+		}
+
+		list_for_each_entry(req, &ep->queue, queue) {
+			t = scnprintf(next, size,
+				"\treq %p, len %u/%u, "
+				"buf %p, dma 0x%08x)\n",
+				&req->req, req->req.actual,
+				req->req.length, req->req.buf,
+				req->req.dma);
+
+			if (t <= 0 || t > size)
+				goto done;
+
+			size -= t;
+			next += t;
+
+			td = req->td;
+			t = scnprintf(next, size, "\ttd 0x%08x, "
+				" count 0x%08x, buf 0x%08x\n",
+				(u32) req->td_dma,
+				le32_to_cpu(td->dmacount),
+				le32_to_cpu(td->dmaaddr));
+
+			if (t <= 0 || t > size)
+				goto done;
+
+			size -= t;
+			next += t;
+		}
+	}
+
+done:
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR(queues, S_IRUGO, show_queues, NULL);
+
+#else
+
+#define device_create_file(a,b)	(0)
+#define device_remove_file(a,b)	do { } while (0)
+
+#endif	/*CONFIG_USB_GADGET_DEBUG_FILES */
+
+/*-------------------------------------------------------------------------*/
+
+/* global variable */
+static struct iusbc	*the_controller;
+
+static void iusbc_reset(struct iusbc *dev)
+{
+	DEBUG(dev, "---> iusbc_reset() \n");
+
+	/* disable irqs */
+	writel(0, &dev->regs->int_ctrl);
+
+	/* set device power stauts */
+	dev->powered = 1;
+
+	/* set device remote wakeup flag */
+	dev->enable_wakeup = 0;
+
+	/* 16 bits status data for GET_STATUS */
+	dev->status_d = 0;
+
+	DEBUG(dev, "<--- iusbc_reset() \n");
+}
+
+
+static void iusbc_reinit(struct iusbc *dev)
+{
+	unsigned	i;
+
+	DEBUG(dev, "---> iusbc_reinit() \n");
+
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+
+	/* ep0-in */
+	dev->gadget.ep0 = &dev->ep[0].ep;
+
+	/* init ep0-in and ep0-out driver_data */
+	dev->ep[0].ep.driver_data = get_gadget_data(&dev->gadget);
+	dev->ep[1].ep.driver_data = get_gadget_data(&dev->gadget);
+
+	dev->ep0state = EP0_DISCONNECT;
+	VDEBUG(dev, "ep0state: EP0_DISCONNECT\n");
+
+	/* basic endpoint init */
+	/* 2 ep0, 3 data ep */
+	for (i = 0; i < 5; i++) {
+		struct iusbc_ep	*ep = &dev->ep[i];
+		ep->dev = dev;
+
+		INIT_LIST_HEAD(&ep->queue);
+
+		ep->desc = NULL;
+		ep->num = i;
+		ep->stopped = 1;
+		ep->ep.name = ep_name[i];
+		ep->ep.maxpacket = ~0;
+		ep->ep.ops = &iusbc_ep_ops;
+
+		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+		ep_reset(dev->regs, ep);
+	}
+
+	/* set ep0 maxpacket */
+	dev->ep[0].ep.maxpacket = 64; /* ep0_in */
+	dev->ep[1].ep.maxpacket = 64; /* ep0_out */
+
+	dev->ep[0].stopped = 0;
+	dev->ep[1].stopped = 0;
+
+	list_del_init(&dev->ep[0].ep.ep_list);
+	list_del_init(&dev->ep[1].ep.ep_list);
+
+	DEBUG(dev, "<--- iusbc_reinit() \n");
+}
+
+
+static void ep0_start(struct iusbc *dev)
+{
+	u16		val_16;
+	u32		val_32;
+	unsigned	i;
+
+	DEBUG(dev, "---> ep0_start() \n");
+
+	iusbc_reset(dev);
+	iusbc_reinit(dev);
+
+	for (i = 0; i < 2; i++) {
+		struct iusbc_ep	*ep = &dev->ep[i];
+
+		/* ep[0]: ep0-in, ep[1]: ep0-out */
+		ep->is_in = (i == 0 ? 1 : 0);
+
+		/* ep0 ep_type */
+		ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
+		/* linear mode only, control mode is useless */
+		ep->dma_mode = LINEAR_MODE;
+
+		/* reset ep0-in/out registers to default value */
+		writew(0, &dev->regs->ep[i].ep_cfg);
+
+		/* set ep0-in/out endpoints valid */
+		val_16 = readw(&dev->regs->ep[i].ep_cfg);
+		val_16 |= INTR_BAD_PID_TYPE
+			| INTR_CRC_ERROR
+			| INTR_FIFO_ERROR
+			| INTR_DMA_ERROR
+			| INTR_TRANS_COMPLETE
+			/* | INTR_PING_NAK_SENT */
+			| INTR_DMA_IOC
+			| ep->dma_mode << 6
+			| ep->ep_type << 4 
+			/* | EP_ENABLE */
+			| EP_VALID;
+
+		writew(val_16, &dev->regs->ep[i].ep_cfg);
+
+		val_16 = readw(&dev->regs->ep[i].ep_cfg);
+		DEBUG(dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16);
+
+		DEBUG(dev, "enabled %s (ep0-%s), max %d, dma_mode: %02x\n",
+			ep->ep.name,
+			ep->is_in ? "in" : "out",
+			ep->ep.maxpacket, ep->dma_mode);
+	}
+
+	/* enable irqs */
+	val_32 = readl(&dev->regs->int_ctrl);
+	val_32 |= RESET_INTR_ENABLE
+		| CONNECT_INTR_ENABLE
+		| SUSPEND_INTR_ENABLE
+		/* | EP3_OUT_INTR_ENABLE */
+		/* | EP3_IN_INTR_ENABLE */
+		/* | EP2_OUT_INTR_ENABLE */
+		| EP2_IN_INTR_ENABLE
+		| EP1_OUT_INTR_ENABLE
+		| EP1_IN_INTR_ENABLE
+		| EP0_OUT_INTR_ENABLE
+		| EP0_IN_INTR_ENABLE;
+
+	writel(val_32, &dev->regs->int_ctrl);
+	val_32 = readl(&dev->regs->int_ctrl);
+	DEBUG(dev, "ep0_start: enable irqs, int_ctrl = 0x%08x\n",
+			val_32);
+
+	dev->ep0state = EP0_IDLE;
+	VDEBUG(dev, "ep0state: EP0_IDLE\n");
+
+	DEBUG(dev, "<--- ep0_start() \n");
+}
+
+
+static void iusbc_do_tasklet(unsigned long arg);
+
+static void device_start(struct iusbc *dev)
+{
+	u32	val_32;
+
+	DEBUG(dev, "---> device_start() \n");
+
+	/* reset all registers */ 
+	writel(0, &dev->regs->dev_ctrl);
+
+	/* PCI enable: write 1 to DeviceEnable */
+	writel(DEVICE_ENABLE, &dev->regs->dev_ctrl);	
+	/* FIXME: 5 ms is not enough? */
+	mdelay(5);
+	val_32 = readl(&dev->regs->dev_ctrl);
+	if (!(val_32 & DEVICE_ENABLE))
+		ERROR(dev, "hardware reset error\n");
+
+	/* hardware transfer to running state now */
+	val_32 |= DEVICE_ENABLE
+		/* | CONNECTION_ENABLE */
+		| SIGNAL_RESUME
+		| CHARGE_ENABLE;
+
+	/* module parameter: force_fullspeed */
+	if (force_fullspeed) {
+		val_32 |= FORCE_FULLSPEED;
+		dev->force_fullspeed = 1;
+	} else {
+		/* disable DMAs in high speed mode */
+#ifdef DMA_DISABLED
+		val_32 |= DMA1_DISABLED
+			| DMA2_DISABLED
+			| DMA3_DISABLED;
+#endif
+		dev->force_fullspeed = 0;
+	}
+
+	writel(val_32, &dev->regs->dev_ctrl);
+	val_32 = readl(&dev->regs->dev_ctrl);
+	DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32);
+
+	/* check device status */
+	val_32 = readl(&dev->regs->dev_sts);
+	DEBUG(dev, "device_start: dev_sts = 0x%08x\n", val_32);
+
+	if (val_32 & CONNECTED) {
+		dev->connected = 1;
+		VDEBUG(dev, "device_start: USB attached\n");
+	} else {
+		dev->connected = 0;
+		VDEBUG(dev, "device_start: USB detached\n");
+	}
+
+	if (val_32 & SUSPEND)
+		dev->suspended = 1;
+	else 
+		dev->suspended = 0;
+
+ 	/* set device reset flag */
+	dev->is_reset = 0;
+
+	iusbc_pullup(&dev->gadget, 1);
+
+	/* init irq tasklet */
+	tasklet_init(&dev->iusbc_tasklet,
+			iusbc_do_tasklet, (unsigned long) dev);
+
+	/* enable ep0 and host detection */
+	ep0_start(dev);
+
+	DEBUG(dev, "<--- device_start() \n");
+}
+
+
+/* when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests.  then usb traffic follows until a
+ * disconnect is reported.  then a host may connect again, or
+ * the driver might get unbound.
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct iusbc		*dev = the_controller;
+	int			retval;
+	unsigned		i;
+
+	if (!driver || !driver->bind || !driver->disconnect || !driver->setup)
+		return -EINVAL;
+
+	if (!dev)
+		return -ENODEV;
+
+	DEBUG(dev, "---> usb_gadget_register_driver() \n");
+
+	if (dev->driver)
+		return -EBUSY;
+
+	dev->irqs = 0;
+
+	/* 2 ep0, 3 data eps */
+	for (i = 0; i < 5; i++)
+		dev->ep[i].irqs = 0;
+
+	/* hook up the driver ... */
+	driver->driver.bus = NULL;
+	dev->driver = driver;
+	dev->gadget.dev.driver = &driver->driver;
+
+	retval = driver->bind(&dev->gadget);
+	if (retval) {
+		DEBUG(dev, "bind to driver %s --> %d\n",
+				driver->driver.name, retval);
+		dev->driver = NULL;
+		dev->gadget.dev.driver = NULL;
+		return retval;
+	}
+
+	retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
+	if (retval)
+		goto err_unbind;
+
+	retval = device_create_file(&dev->pdev->dev, &dev_attr_queues);
+	if (retval)
+		goto err_func;
+	
+	device_start(dev);
+
+	INFO(dev, "register driver: %s\n", driver->driver.name);
+	DEBUG(dev, "<--- usb_gadget_register_driver() \n");
+
+	return 0;
+
+err_func:
+	device_remove_file(&dev->pdev->dev, &dev_attr_function);
+
+err_unbind:
+	driver->unbind(&dev->gadget);
+	dev->gadget.dev.driver = NULL;
+	dev->driver = NULL;
+
+	DEBUG(dev, "<--- usb_gadget_register_driver() \n");
+
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+
+static void
+stop_activity(struct iusbc *dev, struct usb_gadget_driver *driver)
+{
+	unsigned	i;
+
+	DEBUG(dev, "---> stop_activity() \n");
+
+	/* don't disconnect if it's not connected */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+
+	/* stop hardware; prevent new request submissions;
+	 * and kill any outstanding requests.
+	 */
+	iusbc_reset(dev);
+
+	/* we need to mark ep0state to disconnect to avoid upper layer to start
+ 	 * next transfer immediately after the following nuke operation, the
+ 	 * iusbc_queue function need to check ep0state before issue a transfer
+ 	 */
+	dev->ep0state = EP0_DISCONNECT;
+
+	/* 2 ep0, 3 data ep */
+	for (i = 0; i < 5; i++)
+		nuke(&dev->ep[i]);
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+
+	iusbc_reinit(dev);
+
+	DEBUG(dev, "<--- stop_activity() \n");
+}
+
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct iusbc	*dev = the_controller;
+	unsigned long	flags;
+
+	DEBUG(dev, "---> usb_gadget_unregister_driver() \n");
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver || !driver->unbind)
+		return -EINVAL;
+
+	/* kill irq tasklet */
+	tasklet_kill(&dev->iusbc_tasklet);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	stop_activity(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	iusbc_pullup(&dev->gadget, 0);
+
+	driver->unbind(&dev->gadget);
+	dev->gadget.dev.driver = NULL;
+	dev->driver = NULL;
+
+	device_remove_file(&dev->pdev->dev, &dev_attr_function);
+	device_remove_file(&dev->pdev->dev, &dev_attr_queues);
+
+	INFO(dev, "unregistered driver '%s'\n", driver->driver.name);
+
+	DEBUG(dev, "<--- usb_gadget_unregister_driver() \n");
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct iusbc_ep *
+get_ep_by_addr(struct iusbc *dev, u16 wIndex)
+{
+	struct iusbc_ep		*ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return &dev->ep[0];
+
+	list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
+		u8	bEndpointAddress;
+		if (!ep->desc)
+			continue;
+
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+
+		if ((wIndex & USB_ENDPOINT_NUMBER_MASK)
+			== (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK))
+			return ep;
+	}
+	return NULL;
+}
+
+
+/* NAK an endpoint */
+static void ep_nak(struct iusbc_ep *ep)
+{
+	u16		val_16;
+	unsigned	i = ep->num;
+
+	DEBUG(ep->dev, "---> ep_nak() \n");
+
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	val_16 &= ~EP_ENABLE;
+	val_16 |= EP_VALID;
+	writew(val_16, &ep->dev->regs->ep[i].ep_cfg);
+
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16);
+
+	DEBUG(ep->dev, "<--- ep_nak() \n");
+}
+
+
+/* ACK an out transfer with a zero length packet (ZLP) */
+static void ep_ack(struct iusbc_ep *ep)
+{
+	u16		val_16;
+	unsigned	i = ep->num;
+
+	DEBUG(ep->dev, "---> ep_ack() \n");
+
+	/* reset data buffer zero length */
+	writew(0, &ep->dev->regs->ep[i].ep_len);
+	val_16 = readw(&ep->dev->regs->ep[i].ep_len);
+	VDEBUG(ep->dev, "%s.ep_len = 0x%04x\n", ep->ep.name, val_16);
+
+	/* validate endpoint, enable DMA */
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	val_16 |= (EP_VALID | EP_ENABLE);
+	writew(val_16, &ep->dev->regs->ep[i].ep_cfg);
+
+	val_16 = readw(&ep->dev->regs->ep[i].ep_cfg);
+	VDEBUG(ep->dev, "enable %s DMA transfer...\n", ep->ep.name);
+	VDEBUG(ep->dev, "%s.ep_cfg = 0x%04x\n", ep->ep.name, val_16);
+
+	DEBUG(ep->dev, "<--- ep_ack() \n");
+}
+
+
+static void ep0_setup(struct iusbc *dev)
+{
+	struct usb_ctrlrequest		ctrl;
+	struct iusbc_ep			*epn;
+	unsigned			i, tmp = 0;
+	u8				addr_new, setup_pkt[8];
+
+	VDEBUG(dev, "---> ep0_setup() \n");
+
+	for (i = 0; i < 8; i++) {
+		setup_pkt[i] = readb(&dev->regs->ep[1].setup_pkt[i]);
+	}
+
+	/* read SETUP packet and enter DATA stage */
+	ctrl.bRequestType = setup_pkt[0];
+	ctrl.bRequest = setup_pkt[1];
+	ctrl.wValue  = cpu_to_le16((setup_pkt[3] << 8)
+			| setup_pkt[2]);
+	ctrl.wIndex  = cpu_to_le16((setup_pkt[5] << 8)
+			| setup_pkt[4]);
+	ctrl.wLength = cpu_to_le16((setup_pkt[7] << 8)
+			| setup_pkt[6]);
+
+	dev->ep[1].stopped = 0;
+
+	/* data stage direction */
+	if (ctrl.bRequestType & USB_DIR_IN) {
+		dev->ep0state = EP0_IN;
+		VDEBUG(dev, "ep0state: EP0_IN\n");
+	} else {
+		dev->ep0state = EP0_OUT;
+		VDEBUG(dev, "ep0state: EP0_OUT\n");
+	}
+
+	/* WORKAROUND: for RNDIS */
+	/* CDC: SEND_ENCAPSULATED_COMMAND */
+	if ((ctrl.bRequestType == 0x21) && (ctrl.bRequest == 0x00)) {
+		goto delegate;
+	}
+	/* CDC: GET_ENCAPSULATED_COMMAND */
+	if ((ctrl.bRequestType == 0xa1) && (ctrl.bRequest == 0x01)) {
+		goto delegate;
+	}
+
+	switch (ctrl.bRequest) {
+	/* GET_STATUS is handled by software */
+	case USB_REQ_GET_STATUS:
+		DEBUG(dev, "SETUP: USB_REQ_GET_STATUS\n");
+		switch (ctrl.bRequestType &
+				__constant_cpu_to_le16(USB_RECIP_MASK)) {
+		case USB_RECIP_DEVICE:
+			/* bit 0: USB_DEVICE_SELF_POWERED
+			 * bit 1: USB_DEVICE_REMOTE_WAKEUP
+			 */
+			if (dev->enable_wakeup) {
+				dev->status_d =
+					__constant_cpu_to_le16(1 << 1 | 1);
+			} else {
+				dev->status_d = __constant_cpu_to_le16(1);
+			}
+			DEBUG(dev, "device status 0x%04x\n", dev->status_d);
+			break;
+		case USB_RECIP_INTERFACE:
+			/* all bits zero */
+			dev->status_d = __constant_cpu_to_le16(0);
+			DEBUG(dev, "interface status 0x%04x\n", dev->status_d);
+			break;
+		case USB_RECIP_ENDPOINT:
+			if ((epn = get_ep_by_addr(dev,
+					le16_to_cpu(ctrl.wIndex))) == 0)
+				goto stall;
+			if (epn->stopped) {	/* halted */
+				dev->status_d = __constant_cpu_to_le16(1);
+			} else {
+				dev->status_d = __constant_cpu_to_le16(0);
+			}
+			DEBUG(dev, "%s endpoint status 0x%04x\n",
+					epn->ep.name, dev->status_d);
+			break;
+		}
+		/* GET_STATUS is partially handled in gadget driver */
+		goto delegate;
+
+	case USB_REQ_CLEAR_FEATURE:
+		DEBUG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n");
+		switch (ctrl.bRequestType) {
+		case USB_RECIP_DEVICE:
+			if (ctrl.wValue == __constant_cpu_to_le16(
+						USB_DEVICE_REMOTE_WAKEUP)) {
+				dev->enable_wakeup = 0;
+				DEBUG(dev, "CLEAR_FEATURE: "
+					"remote wakeup disabled\n");
+				goto end;
+			} else {
+				DEBUG(dev, "unsupported CLEAR_FEATURE\n");
+				goto stall;
+			}
+			break;
+		case USB_RECIP_INTERFACE:
+			DEBUG(dev, "unsupported CLEAR_FEATURE\n");
+			goto stall;
+		case USB_RECIP_ENDPOINT:
+			if (ctrl.wValue != __constant_cpu_to_le16(
+						USB_ENDPOINT_HALT)
+					|| le16_to_cpu(ctrl.wLength) != 0)
+				goto stall;
+			if ((epn = get_ep_by_addr(dev,
+					le16_to_cpu(ctrl.wIndex))) == 0)
+				goto stall;
+			clear_halt(epn);
+			ep_ack(&dev->ep[0]);
+
+			dev->ep0state = EP0_STATUS;
+			VDEBUG(dev, "ep0state: EP0_STATUS\n");
+
+			DEBUG(dev, "%s clear halt\n", epn->ep.name);
+			goto end;
+		}
+		break;
+
+	case USB_REQ_SET_FEATURE:
+		DEBUG (dev, "SETUP: USB_REQ_SET_FEATURE\n");
+		switch (ctrl.bRequestType) {
+		case USB_RECIP_DEVICE:
+			if (ctrl.wValue == __constant_cpu_to_le16(
+						USB_DEVICE_REMOTE_WAKEUP)) {
+				dev->enable_wakeup = 1;
+				DEBUG(dev, "SET_FEATURE: "
+					"remote wakeup enabled\n");
+				goto end;
+			} else {
+				DEBUG(dev, "unsupported SET_FEATURE\n");
+				goto stall;
+			}
+			break;
+		case USB_RECIP_INTERFACE:
+			DEBUG(dev, "unsupported SET_FEATURE\n");
+			goto stall;
+		case USB_RECIP_ENDPOINT:
+			if (ctrl.wValue != __constant_cpu_to_le16(
+						USB_ENDPOINT_HALT)
+					|| le16_to_cpu(ctrl.wLength) != 0)
+				goto stall;
+			if ((epn = get_ep_by_addr(dev,
+					le16_to_cpu(ctrl.wIndex))) == 0)
+				goto stall;
+			set_halt(epn);
+			ep_ack(&dev->ep[0]);
+
+			DEBUG(dev, "%s set halt\n", epn->ep.name);
+			goto end;
+		}
+		break;
+
+	case USB_REQ_SET_ADDRESS:
+		/* hw handles set_address, address range: 1-127 */
+		DEBUG(dev, "SETUP: USB_REQ_SET_ADDRESS\n");
+		if (setup_pkt[1] == USB_REQ_SET_ADDRESS) {
+			addr_new = le16_to_cpu(ctrl.wValue) & 0x7f;
+			DEBUG(dev, "addr_new = 0x%02x\n", addr_new);
+
+			/* hardware didn't ACK SET_ADDRESS */
+			ep_ack(&dev->ep[0]);
+		}
+		goto end;
+
+	case USB_REQ_GET_DESCRIPTOR:
+		DEBUG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n");
+		goto delegate;
+
+	case USB_REQ_SET_DESCRIPTOR:
+		DEBUG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n");
+		goto stall;
+		break;
+
+	case USB_REQ_GET_CONFIGURATION:
+		DEBUG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n");
+		goto delegate;
+
+	case USB_REQ_SET_CONFIGURATION:
+		DEBUG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n");
+		goto delegate;
+
+	case USB_REQ_GET_INTERFACE:
+		DEBUG(dev, "SETUP: USB_REQ_GET_INTERFACE\n");
+		goto delegate;
+
+	case USB_REQ_SET_INTERFACE:
+		DEBUG(dev, "SETUP: USB_REQ_SET_INTERFACE\n");
+		goto delegate;
+
+	case USB_REQ_SYNCH_FRAME:
+		DEBUG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n");
+		goto stall;
+		break;
+	default:
+		/* delegate usb standard requests to the gadget driver.
+		 * it may respond after this irq handler returns.
+		 */
+		goto delegate;
+delegate:
+		DEBUG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+			ctrl.bRequestType, ctrl.bRequest,
+			le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex),
+			le16_to_cpu(ctrl.wLength));
+
+		dev->ep[1].responded = 0;
+
+		/* WORKAROUND: for RNDIS */
+		/* CDC: SEND_ENCAPSULATED_COMMAND */
+		if ((ctrl.bRequestType == 0x21)
+				&& (ctrl.bRequest == 0x00)) {
+			/* CDC: SEND_ENCAPSULATED_COMMAND */
+			DEBUG(dev, "CDC: SEND_ENCAPSULATED_COMMAND\n");
+			dev->gadget.ep0 = &dev->ep[1].ep;
+			spin_unlock(&dev->lock);
+			tmp = dev->driver->setup(&dev->gadget, &ctrl);
+			spin_lock(&dev->lock);
+
+			/* switch back to ep0-in */
+			dev->gadget.ep0 = &dev->ep[0].ep;
+
+			/* hardware didn't ACK */
+			ep_ack(&dev->ep[0]);
+		} else { 
+			dev->gadget.ep0 = &dev->ep[0].ep;
+			spin_unlock(&dev->lock);
+			tmp = dev->driver->setup(&dev->gadget, &ctrl);
+			spin_lock(&dev->lock);
+
+			/* CDC: GET_ENCAPSULATED_COMMAND */
+			if ((ctrl.bRequestType == 0xa1)
+				&& (ctrl.bRequest == 0x01)) {
+				DEBUG(dev, "CDC: GET_ENCAPSULATED_COMMAND\n");
+
+				/* hardware didn't ACK */
+				ep_ack(&dev->ep[1]);
+			}
+		}
+		break;
+	}
+
+	/* stall ep0-out on error */
+	if (unlikely(tmp < 0)) {
+stall:
+		DEBUG(dev, "req %02x.%02x protocol STALL; err %d\n",
+				ctrl.bRequestType, ctrl.bRequest, tmp);
+		dev->ep[1].stopped = 1;
+		dev->ep0state = EP0_STALL;
+		VDEBUG(dev, "ep0state: EP0_STALL\n");
+	}
+end:
+	VDEBUG(dev, "<--- ep0_setup() \n");
+}
+
+
+static void handle_device_irqs(struct iusbc *dev)
+{
+	u32			stat;
+	volatile u32		dev_sts;
+	unsigned		is_connected = 0;
+
+	DEBUG(dev, "---> handle_device_irqs() \n");
+
+	stat = dev->int_sts;
+
+	/* get device status, set USB speed */
+	if ((stat & RESET_INTR) || (stat & CONNECT_INTR)
+			|| (stat & SUSPEND_INTR)) {
+		/* check device status */
+		dev_sts = readl(&dev->regs->dev_sts);
+		DEBUG(dev, "handle_device_irqs: dev_sts = 0x%08x\n",
+				dev_sts);
+
+		if (dev_sts & CONNECTED) {
+			is_connected = 1;
+			DEBUG(dev, "device connected\n");
+
+			/* check suspend/resume status now */ 
+			if (dev_sts & SUSPEND)
+				dev->suspended = 1;
+			else 
+				dev->suspended = 0;
+
+			/* RATE: high/full speed flag
+			 * 1 clock cycle after CONNECT,
+			 * read one more time until RATE bit set
+			 */
+			dev_sts = readl(&dev->regs->dev_sts);
+			DEBUG(dev, "read for RATE: dev_sts = 0x%08x\n",
+					dev_sts);
+			if (dev_sts & RATE) {
+				if (dev->force_fullspeed) {
+					dev->gadget.speed = USB_SPEED_FULL;
+					DEBUG(dev, "speed: USB_SPEED_FULL\n");
+				} else { 
+					dev->gadget.speed = USB_SPEED_HIGH;
+					DEBUG(dev, "speed: USB_SPEED_HIGH\n");
+				}
+			} else {
+				dev->gadget.speed = USB_SPEED_FULL;
+				DEBUG(dev, "speed: USB_SPEED_FULL\n");
+			}
+		} else {	/* disconnected */
+			is_connected = 0;
+			DEBUG(dev, "device disconnected\n");
+		}
+	}
+
+	/* USB reset interrupt indication */
+	if ((stat & RESET_INTR) && (!dev->is_reset)) {
+		DEBUG(dev, "USB Reset interrupt: stat = 0x%08x\n", stat);
+		/* ACK RESET_INTR */
+		stat &= ~RESET_INTR;
+		dev->irqs++;
+		VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs);
+
+		/* set device reset flag */
+		dev->is_reset = 1;
+
+		stop_activity(dev, dev->driver);
+		ep0_start(dev);
+		VDEBUG(dev, "reset: ep0_start()\n");
+
+		goto end;
+	}
+
+
+	/* connect interrupt indication */
+	if (stat & CONNECT_INTR) {
+		DEBUG(dev, "CONNECT interrupt: stat = 0x%08x\n", stat);
+		/* ACK CONNECT_INTR */
+		stat &= ~CONNECT_INTR;
+		dev->irqs++;
+		VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs);
+
+		/* connected status has changed */
+		if (dev->connected != is_connected) {
+			DEBUG(dev, "connected status has changed\n");
+			dev->connected = is_connected;
+			if (is_connected) {
+				ep0_start(dev);
+				DEBUG(dev, "connect %s\n", dev->driver->driver.name);
+			} else { /* disconnected */
+				/* set device reset flag */
+				dev->is_reset = 0;
+				stop_activity(dev, dev->driver);
+				DEBUG(dev, "disconnect %s\n", dev->driver->driver.name);
+				dev->ep0state = EP0_DISCONNECT;
+				VDEBUG(dev, "ep0state: EP0_DISCONNECT\n");
+			}
+		}
+	}
+	
+	/* host suspend interrupt indication */
+	if (stat & SUSPEND_INTR) {
+		DEBUG(dev, "SUSPEND interrupt: stat = 0x%08x\n", stat);
+		/* ACK SUSPEND_INTR */
+		stat &= ~SUSPEND_INTR;
+		dev->irqs++;
+		VDEBUG(dev, "dev->irqs: %lu\n", dev->irqs);
+
+		/* call gadget driver suspend/resume routines */
+		if (dev->suspended) {
+			if (dev->driver->suspend) {
+				spin_unlock(&dev->lock);
+				dev->driver->suspend(&dev->gadget);
+				spin_lock(&dev->lock);
+			}
+			DEBUG(dev, "suspend %s\n", dev->driver->driver.name);
+		} else {
+			if (dev->driver->resume) {
+				spin_unlock(&dev->lock);
+				dev->driver->resume(&dev->gadget);
+				spin_lock(&dev->lock);
+			}
+			DEBUG(dev, "resume %s\n", dev->driver->driver.name);
+		}
+	}
+
+	/* if haven't USB Reset yet, wait for the next USB reset interrupt */
+	if (!dev->is_reset) {
+		DEBUG(dev, "Skip other interrupts before RESET\n");
+	}
+
+end:
+	VDEBUG(dev, "handle device_irq finish: int_sts = 0x%08x, "
+			"stat = 0x%08x\n", dev->int_sts, stat);
+
+	VDEBUG(dev, "<--- handle_device_irqs() \n");
+}
+
+
+static void handle_ep0_irqs(struct iusbc *dev)
+{
+	volatile u16		ep_sts, val_16;
+	u32			stat;
+	u8			setup_pkt_sts;
+	struct iusbc_request	*req;
+
+	VDEBUG(dev, "---> handle_ep0_irqs() \n");
+
+	stat = dev->int_sts;
+	VDEBUG(dev, "stat = 0x%08x\n", stat);
+
+	/* ep0-out interrupt */
+	if (stat & EP0_OUT_INTR) {
+		dev->ep[1].irqs++;
+		VDEBUG(dev, "%s.irqs = %lu\n",
+				dev->ep[1].ep.name ,dev->ep[1].irqs);
+
+		ep_sts = readw(&dev->regs->ep[1].ep_sts);
+		VDEBUG(dev, "%s.ep_sts = 0x%04x\n",
+				dev->ep[1].ep.name, ep_sts);
+
+		/* W1C ep0-out status register */
+		writew(ep_sts, &dev->regs->ep[1].ep_sts);
+
+		if ((ep_sts & BAD_PID_TYPE)
+				|| (ep_sts & CRC_ERROR)
+				|| (ep_sts & FIFO_ERROR)
+				|| (ep_sts & DMA_ERROR)
+				|| (ep_sts & DMA_IOC)) {
+			DEBUG(dev, "%s error: 0x%04x \n",
+					dev->ep[1].ep.name, ep_sts);
+		}
+
+		if (ep_sts & TRANS_COMPLETE) {
+			VDEBUG(dev, "handle ep0-out interrupt\n");
+
+			setup_pkt_sts = readb(&dev->regs->ep[1].setup_pkt_sts);
+			VDEBUG(dev, "setup_pkt_sts = 0x%02x\n", setup_pkt_sts);
+			/* ep0-out SETUP packet */
+			if (setup_pkt_sts) {
+				VDEBUG(dev, "ep0-out SETUP packet\n");
+
+				/* W1C ep0-out Setup Packet Status Register */ 
+				writeb(1, &dev->regs->ep[1].setup_pkt_sts);
+
+				/* read ep0-out Setup Packet Register
+				 * then handle ep0-out SETUP packet 
+				 */
+				ep0_setup(dev);
+			} else {
+				/* ep0-out standard OUT packet */
+				DEBUG(dev, "ep0-out OUT packet\n");
+				if (!list_empty(&dev->ep[1].queue)) {
+					req = list_entry(dev->ep[1].queue.next,
+							struct iusbc_request,
+							queue);
+					VDEBUG(dev, "dmacount = %d\n",
+							req->td->dmacount);
+					dma_done(&dev->ep[1], req, 0);
+					VDEBUG(dev, "%s dma_done()\n",
+						dev->ep[1].ep.name);
+				}
+
+				/* handle next standard OUT packet */
+				if (!list_empty(&dev->ep[1].queue)) {
+					restart_dma(&dev->ep[1]);
+					VDEBUG(dev, "%s restart_dma()\n",
+						dev->ep[1].ep.name);
+				}
+			}
+		} else {
+			/* WORKAROUND: FIFO_ERROR TC=0  */ 
+			if (ep_sts & FIFO_ERROR)
+				DEBUG(dev, "ep0-out FIFO_ERROR, TC=0\n");
+		}
+
+		/* enable DMA again */
+		val_16 = readw(&dev->regs->ep[1].ep_cfg);
+		val_16 |= EP_ENABLE;
+		writew(val_16, &dev->regs->ep[1].ep_cfg);
+
+		val_16 = readw(&dev->regs->ep[1].ep_cfg);
+		VDEBUG(dev, "enable %s DMA transfer...\n",
+				dev->ep[1].ep.name);
+		VDEBUG(dev, "%s EP_ENABLE again, ep_cfg=0x%04x\n",
+				dev->ep[1].ep.name, val_16);
+	}
+
+	/* ep0-in interrupt */
+	if (stat & EP0_IN_INTR) {
+		dev->ep[0].irqs++;
+		VDEBUG(dev, "%s.irqs = %lu\n",
+				dev->ep[0].ep.name, dev->ep[0].irqs);
+
+		ep_sts = readw(&dev->regs->ep[0].ep_sts);
+		VDEBUG(dev, "%s.ep_sts = 0x%04x\n",
+				dev->ep[0].ep.name, ep_sts);
+
+		/* W1C ep0-in status register */
+		writew(ep_sts, &dev->regs->ep[0].ep_sts);
+
+		if ((ep_sts & BAD_PID_TYPE)
+				|| (ep_sts & CRC_ERROR)
+				|| (ep_sts & FIFO_ERROR)
+				|| (ep_sts & DMA_ERROR)
+				|| (ep_sts & DMA_IOC)) {
+			DEBUG(dev, "%s error: 0x%04x \n",
+					dev->ep[0].ep.name, ep_sts);
+		}
+
+		if (ep_sts & TRANS_COMPLETE) {
+			VDEBUG(dev, "handle ep0-in interrupt\n");
+			if (!list_empty(&dev->ep[0].queue)) {
+				req = list_entry(dev->ep[0].queue.next,
+						struct iusbc_request,
+						queue);
+				VDEBUG(dev, "dmacount = %d\n", req->td->dmacount);
+				dma_done(&dev->ep[0], req, 0);
+				VDEBUG(dev, "%s dma_done()\n",
+						dev->ep[0].ep.name);
+			}
+
+			/* handle next standard IN packet */
+			if (!list_empty(&dev->ep[0].queue)) {
+				restart_dma(&dev->ep[0]);
+				VDEBUG(dev, "%s restart_dma()\n",
+						dev->ep[0].ep.name);
+			}
+		} else {
+			if (ep_sts & FIFO_ERROR)
+				DEBUG(dev, "ep0-in FIFO_ERROR, TC=0\n");
+		}
+
+	}
+
+	VDEBUG(dev, "<--- handle_ep0_irqs() \n");
+}
+
+
+static void handle_ep_irqs(struct iusbc *dev)
+{
+	volatile u16		ep_sts;
+	u32			stat;
+	unsigned		i;
+	struct iusbc_request	*req;
+
+	VDEBUG(dev, "---> handle_ep_irqs() \n");
+
+	stat = dev->int_sts;
+	VDEBUG(dev, "stat = 0x%08x\n", stat);
+
+	/* ep1in-bulk, ep1out-bulk and ep2in-int */
+	for (i = 2; i < 5; i++) { 
+		if ((1 << i) & stat) {
+			dev->ep[i].irqs++;
+			ep_sts = readw(&dev->regs->ep[i].ep_sts);
+			if (ep_sts)
+				VDEBUG(dev, "%s.ep_sts = 0x%04x\n",
+					dev->ep[i].ep.name, ep_sts);
+
+			/* W1C ep status register */
+			writew(ep_sts, &dev->regs->ep[i].ep_sts);
+
+			if ((ep_sts & BAD_PID_TYPE)
+					|| (ep_sts & CRC_ERROR)
+					|| (ep_sts & FIFO_ERROR)
+					|| (ep_sts & DMA_ERROR)
+					|| (ep_sts & DMA_IOC)) {
+				DEBUG(dev, "%s error: 0x%04x \n",
+					dev->ep[i].ep.name, ep_sts);
+			}
+
+			if (ep_sts & TRANS_COMPLETE) {
+				VDEBUG(dev, "handle %s interrupt\n",
+						dev->ep[i].ep.name);
+				VDEBUG(dev, "data ep dma TRANS_COMPLETE\n");
+				if (!list_empty(&dev->ep[i].queue)) {
+					req = list_entry(dev->ep[i].queue.next,
+							struct iusbc_request,
+							queue);
+					VDEBUG(dev, "dmacount = %d\n",
+							req->td->dmacount);
+					dma_done(&dev->ep[i], req, 0);
+					VDEBUG(dev, "%s dma_done()\n",
+						dev->ep[i].ep.name);
+				}
+
+				/* handle next standard OUT and IN packet */
+				if (!list_empty(&dev->ep[i].queue)) {
+					restart_dma(&dev->ep[i]);
+					VDEBUG(dev, "%s restart_dma()\n",
+						dev->ep[i].ep.name);
+				}
+			} else {
+				if (ep_sts & FIFO_ERROR)
+					DEBUG(dev, "%s FIFO_ERROR, TC=0\n",
+							dev->ep[i].ep.name);
+			}
+		}
+	}
+
+	VDEBUG(dev, "<--- handle_ep_irqs() \n");
+}
+
+
+static void iusbc_do_tasklet(unsigned long arg)
+{
+	u32		val_32;
+	struct iusbc	*dev;
+	dev = (struct iusbc *) arg;
+	DEBUG(dev, "---> iusbc_do_tasklet() \n");
+
+	spin_lock(&dev->lock);
+
+	/* disable irqs, will re-enable later */
+	writel(0, &dev->regs->int_ctrl);
+
+	/* device-wide reset, connect, suspend */
+	if (dev->int_sts & (RESET_INTR | CONNECT_INTR | SUSPEND_INTR)) {
+		DEBUG(dev, "iusbc_do_tasklet -> handle_device_irqs\n");
+		handle_device_irqs(dev);
+	}
+
+	/* ep0-in/out control requests and interrupt */
+	if (dev->int_sts & (EP0_IN_INTR | EP0_OUT_INTR)) {
+		DEBUG(dev, "iusbc_do_tasklet -> handle_ep0_irqs\n");
+		handle_ep0_irqs(dev);
+	}
+
+	/* data endpoints requests interrupt */
+	if (dev->int_sts & (EP1_IN_INTR | EP1_OUT_INTR | EP2_IN_INTR)) {
+		DEBUG(dev, "iusbc_do_tasklet -> handle_ep_irqs\n");
+		handle_ep_irqs(dev);
+	}
+
+	/* enable irqs again */
+	val_32 = 0;
+	val_32 |= RESET_INTR_ENABLE
+		| CONNECT_INTR_ENABLE
+		| SUSPEND_INTR_ENABLE
+		/* | EP3_OUT_INTR_ENABLE */
+		/* | EP3_IN_INTR_ENABLE */
+		/* | EP2_OUT_INTR_ENABLE */
+		| EP2_IN_INTR_ENABLE
+		| EP1_OUT_INTR_ENABLE
+		| EP1_IN_INTR_ENABLE
+		| EP0_OUT_INTR_ENABLE
+		| EP0_IN_INTR_ENABLE;
+
+	writel(val_32, &dev->regs->int_ctrl);
+	val_32 = readl(&dev->regs->int_ctrl);
+	DEBUG(dev, "enable irqs again in iusbc_do_tasklet(), "
+			"int_ctrl = 0x%08x\n", val_32);
+
+	spin_unlock(&dev->lock);
+
+	DEBUG(dev, "<--- iusbc_do_tasklet() \n");
+}
+
+
+static irqreturn_t iusbc_irq(int irq, void *_dev)
+{
+	struct iusbc	*dev = _dev;
+	u32		int_sts,
+			int_ctrl,
+			val_32;
+
+	VDEBUG(dev, "---> iusbc_irq() \n");
+
+	/* interrupt control */
+	int_ctrl = readl(&dev->regs->int_ctrl);
+	VDEBUG(dev, "int_ctrl = 0x%08x\n", int_ctrl);
+
+	/* interrupt status */
+	int_sts = readl(&dev->regs->int_sts);
+	VDEBUG(dev, "int_sts = 0x%08x\n", int_sts);
+
+	if (!int_sts || !int_ctrl) {
+		VDEBUG(dev, "handle IRQ_NONE\n");
+		VDEBUG(dev, "<--- iusbc_irq() \n");
+		return IRQ_NONE;
+	}
+
+	/* disable irqs, will re-enable later */
+	writel(0, &dev->regs->int_ctrl);
+
+	/* W1C interrupt status register */
+	writel(int_sts, &dev->regs->int_sts);
+	val_32 = readl(&dev->regs->int_sts);
+	VDEBUG(dev, "W1C: regs->int_sts = 0x%08x\n", val_32);
+
+	/* for iusbc_tasklet */
+	dev->int_sts = int_sts;
+
+	/* check device status */
+	val_32 = readl(&dev->regs->dev_sts);
+	DEBUG(dev, "iusbc_irq: dev_sts = 0x%08x\n", val_32);
+
+	/* schedule irq tasklet */
+	tasklet_schedule(&dev->iusbc_tasklet);
+
+	VDEBUG(dev, "<--- iusbc_irq() \n");
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void gadget_release(struct device *_dev)
+{
+	struct iusbc	*dev;
+#ifdef VERBOSE
+	printk(KERN_DEBUG "---> gadget_release() \n");
+#endif
+
+	dev = dev_get_drvdata(_dev);
+	kfree(dev);
+
+#ifdef VERBOSE
+	printk(KERN_DEBUG "<--- gadget_release() \n");
+#endif
+}
+
+
+/* tear down the binding between this driver and the pci device */
+static void iusbc_remove(struct pci_dev *pdev)
+{
+	struct iusbc		*dev;
+
+	dev = pci_get_drvdata(pdev);
+
+	BUG_ON(dev->driver);
+
+	VDEBUG(dev, "---> iusbc_remove() \n");
+
+	/* then clean up the resources we allocated during probe() */
+	if (dev->requests) {
+		unsigned	i;
+		/* 2 ep0, 3 data ep */
+		for (i = 0; i < 5; i++) {
+			if (!dev->ep[i].dummy)
+				continue;
+
+			pci_pool_free(dev->requests, dev->ep[i].dummy,
+					dev->ep[i].td_dma);
+		}
+		pci_pool_destroy(dev->requests);
+	}
+
+	if (dev->got_irq)
+		free_irq(pdev->irq, dev);
+
+	if (dev->regs)
+		iounmap(dev->regs);
+
+	if (dev->region)
+		release_mem_region(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0));
+
+	if (dev->enabled)
+		pci_disable_device(pdev);
+
+	device_unregister(&dev->gadget.dev);
+	device_remove_file(&pdev->dev, &dev_attr_registers);
+	pci_set_drvdata(pdev, NULL);
+
+	INFO(dev, "unbind\n");
+
+	the_controller = NULL;
+
+	VDEBUG(dev, "<--- iusbc_remove() \n");
+}
+
+
+/* wrap this driver around the specified device, but
+ * don't respond over USB until a gadget driver binds to us.
+ */
+static int iusbc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct iusbc		*dev;
+	unsigned long		resource, len;
+	void			__iomem *base = NULL;
+	int			retval;
+	unsigned		i;
+	u32			val_32;
+
+	/* if you want to support more than one controller in a system,
+	 * usb_gadget_{register,unregister}_driver() must change.
+	 */
+	if (the_controller) {
+		dev_warn(&pdev->dev, "ignoring\n");
+		return -EBUSY;
+	}
+
+	/* alloc, and start init */
+	dev = kzalloc(sizeof *dev, GFP_KERNEL);
+	if (dev == NULL){
+		retval = -ENOMEM;
+		goto done;
+	}
+
+	pci_set_drvdata(pdev, dev);
+	spin_lock_init(&dev->lock);
+	dev->pdev = pdev;
+
+	DEBUG(dev, "---> iusbc_probe() \n");
+
+	dev->gadget.ops = &iusbc_ops;
+	dev->gadget.is_dualspeed = 1; /* support high/full speed */
+
+	/* the "gadget" abstracts/virtualizes the controller */
+	strcpy(dev->gadget.dev.bus_id, "gadget");
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+	dev->gadget.dev.release = gadget_release;
+	dev->gadget.name = driver_name;
+
+	/* now all the pci goodies ... */
+	if (pci_enable_device(pdev) < 0) {
+	        retval = -ENODEV;
+		goto done;
+	}
+
+	/* WORKAROUND: USB port routing bug */
+	pci_write_config_byte(pdev, 0x40, 0x82);
+
+	dev->enabled = 1;
+
+	/* control register: BAR 0 */
+	resource = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+	if (!request_mem_region(resource, len, driver_name)) {
+		DEBUG(dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto done;
+	}
+	dev->region = 1;
+
+	base = ioremap_nocache(resource, len);
+	if (base == NULL) {
+		DEBUG(dev, "can't map memory\n");
+		retval = -EFAULT;
+		goto done;
+	}
+	dev->regs = (struct iusbc_regs __iomem *) base;
+
+	/* global capabilities, ep number and dma modes */
+	val_32 = readl(&dev->regs->gcap);
+	if (val_32 & TRANSFER_MODE_CAP)
+		dev->transfer_mode_dma = 1;
+
+	if (val_32 & SCATTER_GATHER_MODE_CAP)
+		dev->sg_mode_dma = 1;
+
+	if (val_32 & LINEAR_MODE_CAP)
+		dev->linear_mode_dma = 1;
+
+	if (val_32 & CONTROL_MODE_CAP)
+		dev->control_mode_dma = 1;
+
+	dev->ep_cap = (val_32 >> 28);
+
+	/* reset all registers */ 
+	writel(0, &dev->regs->dev_ctrl);
+
+	/* init usb client controller device */
+	iusbc_reset(dev);
+	iusbc_reinit(dev);
+
+	/* irq setup after old hardware is cleaned up */
+	if (!pdev->irq) {
+		ERROR(dev, "No IRQ. Check PCI setup!\n");
+		retval = -ENODEV;
+		goto done;
+	}
+
+	if (request_irq(pdev->irq, iusbc_irq, IRQF_SHARED, driver_name, dev)
+			!= 0) {
+		ERROR(dev, "request interrupt %d failed\n", pdev->irq);
+		retval = -EBUSY;
+		goto done;
+	}
+	dev->got_irq = 1;
+
+	/* ------------------------------------------------------------------ */
+	/* DMA setup
+	 * NOTE: we know only the 32 LSBs of dma addresses may be nonzero
+	 */
+	dev->requests = pci_pool_create("requests", pdev,
+		sizeof(struct iusbc_dma),
+		0 /* no alignment requirements */,
+		0 /* or page-crossing issues */);
+
+	if (!dev->requests) {
+		DEBUG(dev, "can't get request pool\n");
+		retval = -ENOMEM;
+		goto done;
+	}
+
+	/* assgined DMA */
+	/* 2 ep0, 3 data ep */
+	for (i = 0; i < 5 ; i++) {
+		struct iusbc_dma	*td;
+		td = pci_pool_alloc(dev->requests,
+				GFP_KERNEL,
+				&dev->ep[i].td_dma);
+
+		if (!td) {
+			DEBUG(dev, "can't get dummy %d\n", i);
+			retval = -ENOMEM;
+			goto done;
+		}
+
+		td->dmacount = 0;	/* not VALID */
+		td->dmaaddr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
+
+		dev->ep[i].dummy = td;
+	}
+
+	/* enables bus-mastering for device dev */
+	pci_set_master(pdev);
+
+	/* ------------------------------------------------------------------ */
+	/* done */
+	INFO(dev, "%s\n", driver_desc);
+	INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base);
+	INFO(dev, "version: " DRIVER_VERSION "\n");
+	INFO(dev, "support (max) %d endpoints\n", dev->ep_cap * 2);
+
+#ifdef VERBOSE
+	/* only for debugging, print mapped memory registers */
+	VDEBUG(dev, "After iusbc_probe(), print register values:\n");
+	print_all_registers(dev->regs);
+#endif
+
+	the_controller = dev;
+	retval = device_register(&dev->gadget.dev);
+
+	if (retval)
+		goto done;
+
+	retval = device_create_file(&pdev->dev, &dev_attr_registers);
+
+	if (retval)
+		goto done;
+
+	DEBUG(dev, "<--- iusbc_probe() \n");
+
+	return 0;
+
+done:
+	if (dev)
+		iusbc_remove(pdev);
+
+	DEBUG(dev, "<--- iusbc_probe() \n");
+
+	return retval;
+}
+
+
+#ifdef CONFIG_PM
+/* client suspend */
+static int iusbc_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct iusbc	*dev;
+	unsigned long	flags;
+
+	dev = pci_get_drvdata(pdev);
+
+	DEBUG(dev, "---> iusbc_suspend() \n");
+
+	tasklet_kill(&dev->iusbc_tasklet);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	stop_activity(dev, dev->driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	iusbc_pullup(&dev->gadget, 0);
+
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	DEBUG(dev, "<--- iusbc_suspend() \n");
+
+	return 0;
+}
+
+/* client resume */
+static int iusbc_resume(struct pci_dev *pdev)
+{
+	struct iusbc	*dev;
+
+	dev = pci_get_drvdata(pdev);
+
+	DEBUG(dev, "---> iusbc_resume() \n");
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	device_start(dev);
+
+	DEBUG(dev, "<--- iusbc_resume() \n");
+
+	return 0;
+}
+#endif
+
+
+static void iusbc_shutdown(struct pci_dev *pdev)
+{
+	struct iusbc	*dev;
+	u32		val_32;
+
+	dev = pci_get_drvdata(pdev);
+
+	DEBUG(dev, "---> iusbc_shutdown() \n");
+
+	/* disable irqs */
+	writel(0, &dev->regs->int_ctrl);
+
+	/* reset all registers */ 
+	writel(0, &dev->regs->dev_ctrl);
+
+	val_32 = readl(&dev->regs->dev_ctrl);
+	DEBUG(dev, "dev_ctrl = 0x%08x\n", val_32);
+
+	DEBUG(dev, "<--- iusbc_shutdown() \n");
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id pci_ids [] = { {
+	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0x80),
+	.class_mask =	~0,
+	.vendor =	0x8086, /* Intel */
+	.device =	0x8118, /* Poulsbo USB Client Controller */
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
+}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver iusbc_pci_driver = {
+	.name =		(char *) driver_name,
+	.id_table =	pci_ids,
+
+	.probe =	iusbc_probe,
+	.remove =	iusbc_remove,
+
+#ifdef CONFIG_PM
+	.suspend =	iusbc_suspend,	
+	.resume =	iusbc_resume,
+#endif
+
+	.shutdown =	iusbc_shutdown,
+};
+
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Xiaochen Shen: xiaochen.shen@intel.com");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+
+static int __init init(void)
+{
+	return pci_register_driver(&iusbc_pci_driver);
+}
+module_init(init);
+
+
+static void __exit cleanup(void)
+{
+	/* in case deferred_free tasklet not finished */
+	spin_lock(&buflock);
+	while (!list_empty(&buffers)) {
+		spin_unlock(&buflock);
+		msleep(1);
+		spin_lock(&buflock);
+	}
+	spin_unlock(&buflock);
+	pci_unregister_driver(&iusbc_pci_driver);
+}
+module_exit(cleanup);
+
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/iusbc.h linux-2.6.24.7-rt20-atom/drivers/usb/gadget/iusbc.h
--- linux-2.6.24.7-rt20/drivers/usb/gadget/iusbc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/iusbc.h	2008-09-28 11:32:46.000000000 +0200
@@ -0,0 +1,218 @@
+/*
+ * Intel Poulsbo USB Client Controller Driver
+ * Copyright (C) 2006-07, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/interrupt.h>
+
+/*
+ * MEMORY SPACE REGISTERS
+ */
+
+struct iusbc_ep_regs {	/* 0x20 bytes */
+	u32		ep_base_low_32;
+	u32		ep_base_hi_32;
+	u16		ep_len;
+	u16		ep_pib;
+	u16		ep_dil;
+	u16		ep_tiq;
+	u16		ep_max;
+	u16		ep_sts;
+#define		BAD_PID_TYPE		(1 << 15)
+#define		CRC_ERROR		(1 << 14)
+#define		FIFO_ERROR		(1 << 13)
+#define		DMA_ERROR		(1 << 12)
+#define		TRANS_COMPLETE		(1 << 11)
+#define		PING_NAK_SENT		(1 << 10)
+#define		DMA_IOC			(1 << 9)
+	u16		ep_cfg;
+#define		INTR_BAD_PID_TYPE	(1 << 15)
+#define		INTR_CRC_ERROR		(1 << 14)
+#define		INTR_FIFO_ERROR		(1 << 13)
+#define		INTR_DMA_ERROR		(1 << 12)
+#define		INTR_TRANS_COMPLETE	(1 << 11)
+#define		INTR_PING_NAK_SENT	(1 << 10)
+#define		INTR_DMA_IOC		(1 << 9)
+#define		LINEAR_MODE		0	
+#define		SCATTER_GATHER_MODE	1
+#define		TRANSFER_MODE		2
+#define		CONTROL_MODE		3
+#define		EP_ENABLE		(1 << 1)
+#define		EP_VALID		(1 << 0)
+	u8		_unused;
+	u8		setup_pkt_sts;
+#define		SETUPPACKET_VALID	(1 << 0)
+	u8		setup_pkt[8];
+} __attribute__ ((packed));
+
+
+struct iusbc_regs {
+	/* offset 0x0000 */
+	u32		gcap;
+#define		DMA_IOC_CAP		(1 << 4)
+#define		TRANSFER_MODE_CAP	(1 << 3)
+#define		SCATTER_GATHER_MODE_CAP	(1 << 2)
+#define		LINEAR_MODE_CAP		(1 << 1)
+#define		CONTROL_MODE_CAP	(1 << 0)
+	u8		_unused0[0x100-0x004];	
+
+	/* offset 0x0100 */
+	u32		dev_sts;
+#define		RATE			(1 << 3)
+#define		CONNECTED		(1 << 1)
+#define		SUSPEND			(1 << 0)
+	u16		frame;
+	u8		_unused1[0x10c-0x106];
+	
+	/* offset 0x010c */
+	u32		int_sts;
+#define		RESET_INTR		(1 << 18)
+#define		CONNECT_INTR		(1 << 17)
+#define		SUSPEND_INTR		(1 << 16)
+#define		EP3_OUT_INTR		(1 << 7)
+#define		EP3_IN_INTR		(1 << 6)
+#define		EP2_OUT_INTR		(1 << 5)
+#define		EP2_IN_INTR		(1 << 4)
+#define		EP1_OUT_INTR		(1 << 3)
+#define		EP1_IN_INTR		(1 << 2)
+#define		EP0_OUT_INTR		(1 << 1)
+#define		EP0_IN_INTR		(1 << 0)
+	u32		int_ctrl;
+#define		RESET_INTR_ENABLE	(1 << 18)
+#define		CONNECT_INTR_ENABLE	(1 << 17)
+#define		SUSPEND_INTR_ENABLE	(1 << 16)
+#define		EP3_OUT_INTR_ENABLE	(1 << 7)
+#define		EP3_IN_INTR_ENABLE	(1 << 6)
+#define		EP2_OUT_INTR_ENABLE	(1 << 5)
+#define		EP2_IN_INTR_ENABLE	(1 << 4)
+#define		EP1_OUT_INTR_ENABLE	(1 << 3)
+#define		EP1_IN_INTR_ENABLE	(1 << 2)
+#define		EP0_OUT_INTR_ENABLE	(1 << 1)
+#define		EP0_IN_INTR_ENABLE	(1 << 0)
+	u32		dev_ctrl;
+#define		DEVICE_ENABLE		(1 << 31)
+#define		CONNECTION_ENABLE	(1 << 30)
+#define		DMA3_DISABLED		(1 << 15)
+#define		DMA2_DISABLED		(1 << 14)
+#define		DMA1_DISABLED		(1 << 13)
+#define		DMA0_DISABLED		(1 << 12)
+#define		CPU_SET_ADDRESS		(1 << 11)
+#define		DISABLE_NYET		(1 << 9)
+#define		TEST_MODE		(1 << 8)
+#define		SIGNAL_RESUME		(1 << 4)
+#define		CHARGE_ENABLE		(5 << 1)
+#define		FORCE_FULLSPEED		(1 << 0)
+	u8		_unused2[0x200-0x118];
+
+	/* offset: 0x200, 0x220, ..., 0x2e0 */
+	struct iusbc_ep_regs	ep[8];
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* DRIVER DATA STRUCTURES and UTILITIES */
+
+/* FIXME: for scatter/gather mode DMA */
+struct iusbc_dma {
+	__le16		dmacount;
+	__le32		dmaaddr;		/* the buffer */
+	__le32		dmadesc;		/* next dma descriptor */
+	__le32		_reserved;
+} __attribute__ ((aligned (16)));
+
+struct iusbc_ep {
+	struct usb_ep				ep;
+	struct iusbc_dma			*dummy;
+	dma_addr_t				td_dma;	/* of dummy */
+	struct iusbc				*dev;
+	unsigned long				irqs;
+
+	/* analogous to a host-side qh */
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+	unsigned				num : 8,
+						fifo_size : 12,
+						in_fifo_validate : 1,
+						out_overflow : 1,
+						stopped : 1,
+						is_in : 1,
+						is_iso : 1,
+						responded : 1,
+						dma_mode : 2,
+						ep_type : 2;
+};
+
+struct iusbc_request {
+	struct usb_request			req;
+	struct iusbc_dma			*td;
+	dma_addr_t				td_dma;
+	struct list_head			queue;
+	unsigned				mapped : 1,
+						valid : 1;
+};
+
+enum ep0state {
+	EP0_DISCONNECT,		/* no host */
+	EP0_IDLE,		/* between STATUS ack and SETUP report */
+	EP0_IN, EP0_OUT, 	/* data stage */
+	EP0_STATUS,		/* status stage */
+	EP0_STALL,		/* data or status stages */
+	EP0_SUSPEND,		/* usb suspend */
+};
+
+struct iusbc {
+	/* each pci device provides one gadget, several endpoints */
+	struct usb_gadget		gadget;
+	spinlock_t			lock;
+	struct iusbc_ep			ep[8];
+	struct usb_gadget_driver 	*driver;
+	enum ep0state			ep0state;
+	unsigned			ep_cap;
+	unsigned			enabled : 1,
+					powered : 1,
+					enable_wakeup : 1,
+					force_fullspeed : 1,
+					rate : 1,
+					connected : 1,
+					suspended : 1,
+					got_irq : 1,
+					region : 1,
+					transfer_mode_dma : 1,
+					sg_mode_dma : 1,
+					linear_mode_dma : 1,
+					control_mode_dma : 1,
+					is_reset : 1;
+
+	/* pci state used to access those endpoints */
+	struct pci_dev			*pdev;
+	struct iusbc_regs		__iomem *regs;
+	struct pci_pool			*requests;
+
+	/* statistics... */
+	unsigned long			irqs;
+
+	/* 16 bits status data for GET_STATUS */
+	__le16				status_d;
+
+	/* device irq tasklet */
+	struct tasklet_struct		iusbc_tasklet;
+
+	/* interrupt status register value */
+	volatile u32			int_sts;
+};
+
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/Kconfig linux-2.6.24.7-rt20-atom/drivers/usb/gadget/Kconfig
--- linux-2.6.24.7-rt20/drivers/usb/gadget/Kconfig	2008-10-06 08:30:26.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/Kconfig	2008-09-28 11:32:46.000000000 +0200
@@ -324,6 +324,27 @@
 	depends on USB_GADGET_AT91
 	default USB_GADGET
 
+config USB_GADGET_IUSBC
+	boolean "Intel USB Client Controller"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	  Intel USB client controller is a PCI based USB peripheral controller
+	  which supports both full and high speed USB 2.0 data transfers.
+
+	  It has three IN and three OUT configurable endpoints, as well
+	  as endpoint zero (for control transfers).
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "iusbc" and force all
+	  gadget drivers to also be dynamically linked.
+
+config USB_IUSBC
+	tristate
+	depends on USB_GADGET_IUSBC
+	default USB_GADGET
+	select	USB_GADGET_SELECTED
+
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/Makefile linux-2.6.24.7-rt20-atom/drivers/usb/gadget/Makefile
--- linux-2.6.24.7-rt20/drivers/usb/gadget/Makefile	2008-10-06 08:30:26.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/Makefile	2008-09-28 11:32:46.000000000 +0200
@@ -17,6 +17,7 @@
 obj-$(CONFIG_USB_ATMEL_USBA)	+= atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
+obj-$(CONFIG_USB_IUSBC)	+= iusbc.o
 
 #
 # USB gadget drivers
diff -urN linux-2.6.24.7-rt20/drivers/usb/gadget/rndis.c linux-2.6.24.7-rt20-atom/drivers/usb/gadget/rndis.c
--- linux-2.6.24.7-rt20/drivers/usb/gadget/rndis.c	2008-10-06 08:30:26.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/gadget/rndis.c	2008-09-28 11:32:46.000000000 +0200
@@ -40,7 +40,7 @@
 
 #undef	RNDIS_PM
 #undef	RNDIS_WAKEUP
-#undef	VERBOSE
+#define	VERBOSE
 
 #include "rndis.h"
 
@@ -52,14 +52,14 @@
  * and will be happier if you provide the host_addr module parameter.
  */
 
-#if 0
+#if 1
 #define DBG(str,args...) do { \
 	if (rndis_debug) \
 		printk(KERN_DEBUG str , ## args ); \
 	} while (0)
-static int rndis_debug = 0;
+static int rndis_debug = 2;
 
-module_param (rndis_debug, int, 0);
+module_param (rndis_debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC (rndis_debug, "enable debugging");
 
 #else
@@ -898,7 +898,7 @@
 
 static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
 {
-	u32			BufLength, BufOffset;
+	u32			BufLength, BufOffset, i;
 	rndis_set_cmplt_type	*resp;
 	rndis_resp_t		*r;
 
diff -urN linux-2.6.24.7-rt20/drivers/usb/host/pci-quirks.c linux-2.6.24.7-rt20-atom/drivers/usb/host/pci-quirks.c
--- linux-2.6.24.7-rt20/drivers/usb/host/pci-quirks.c	2008-10-06 08:30:27.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/host/pci-quirks.c	2008-09-28 11:33:49.000000000 +0200
@@ -51,6 +51,17 @@
 #define EHCI_USBLEGCTLSTS	4		/* legacy control/status */
 #define EHCI_USBLEGCTLSTS_SOOE	(1 << 13)	/* SMI on ownership change */
 
+void uhci_clear_usb_int(unsigned long base)
+{
+    outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD);
+    mb();
+    udelay(5);
+    outw(0, base + UHCI_USBINTR);
+    outw(0, base + UHCI_USBCMD);
+    mb();
+    return;
+}
+EXPORT_SYMBOL (uhci_clear_usb_int);
 
 /*
  * Make sure the controller is completely inactive, unable to
diff -urN linux-2.6.24.7-rt20/drivers/usb/host/uhci-hcd.c linux-2.6.24.7-rt20-atom/drivers/usb/host/uhci-hcd.c
--- linux-2.6.24.7-rt20/drivers/usb/host/uhci-hcd.c	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/drivers/usb/host/uhci-hcd.c	2008-09-28 11:33:49.000000000 +0200
@@ -898,6 +898,18 @@
 
 MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
 
+extern void uhci_clear_usb_int(unsigned long base);
+static int usb_hcd_resume_early(struct pci_dev *dev)
+{
+	struct usb_hcd  *hcd;
+	struct uhci_hcd *uhci;
+
+	hcd = pci_get_drvdata(dev);
+	uhci = hcd_to_uhci(hcd);
+	uhci_clear_usb_int(uhci->io_addr);
+	return 0;
+}
+
 static struct pci_driver uhci_pci_driver = {
 	.name =		(char *)hcd_name,
 	.id_table =	uhci_pci_ids,
@@ -907,6 +919,7 @@
 	.shutdown =	uhci_shutdown,
 
 #ifdef	CONFIG_PM
+	.resume_early =	usb_hcd_resume_early,
 	.suspend =	usb_hcd_pci_suspend,
 	.resume =	usb_hcd_pci_resume,
 #endif	/* PM */
diff -urN linux-2.6.24.7-rt20/include/acpi/acpi_bus.h linux-2.6.24.7-rt20-atom/include/acpi/acpi_bus.h
--- linux-2.6.24.7-rt20/include/acpi/acpi_bus.h	2008-10-06 08:30:32.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/include/acpi/acpi_bus.h	2008-09-28 11:30:55.000000000 +0200
@@ -321,6 +321,8 @@
 
 extern struct kset acpi_subsys;
 extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
+void acpi_bus_private_data_handler(acpi_handle, u32, void *);
+int acpi_bus_get_private_data(acpi_handle, void **);
 /*
  * External Functions
  */
diff -urN linux-2.6.24.7-rt20/include/acpi/processor.h linux-2.6.24.7-rt20-atom/include/acpi/processor.h
--- linux-2.6.24.7-rt20/include/acpi/processor.h	2008-10-06 08:30:32.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/include/acpi/processor.h	2008-09-28 11:30:55.000000000 +0200
@@ -4,7 +4,7 @@
 #include <linux/kernel.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
-
+#include <linux/thermal.h>
 #include <asm/acpi.h>
 
 #define ACPI_PROCESSOR_BUSY_METRIC	10
@@ -218,7 +218,7 @@
 	struct acpi_processor_performance *performance;
 	struct acpi_processor_throttling throttling;
 	struct acpi_processor_limit limit;
-
+	struct thermal_cooling_device *cdev;
 	/* the _PDC objects for this processor, if any */
 	struct acpi_object_list *pdc;
 };
@@ -330,7 +330,7 @@
 /* in processor_thermal.c */
 int acpi_processor_get_limit_info(struct acpi_processor *pr);
 extern struct file_operations acpi_processor_limit_fops;
-
+extern struct thermal_cooling_device_ops processor_cooling_ops;
 #ifdef CONFIG_CPU_FREQ
 void acpi_thermal_cpufreq_init(void);
 void acpi_thermal_cpufreq_exit(void);
diff -urN linux-2.6.24.7-rt20/include/linux/mmc/core.h linux-2.6.24.7-rt20-atom/include/linux/mmc/core.h
--- linux-2.6.24.7-rt20/include/linux/mmc/core.h	2008-04-17 04:49:44.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/include/linux/mmc/core.h	2008-09-28 11:32:59.000000000 +0200
@@ -150,4 +150,20 @@
 	__mmc_claim_host(host, NULL);
 }
 
+/* feng add for temply use */
+#define DBG_2622 1
+
+#ifdef DBG_2622
+#define umd_dbg(f, x...) \
+	printk(KERN_INFO "[%s()]: " f "\n", __func__,##x)
+#define umd_enter() \
+	printk(KERN_INFO "[%s()]: enter\n", __func__)
+#define umd_exit() \
+	printk(KERN_INFO "[%s()]: exit\n", __func__)
+#else
+#define umd_dbg(f, x...)  do{} while(0)
+#define umd_enter()  do{} while(0)
+#define umd_exit()  do{} while(0)
+#endif /* end of DBG_2622 */
+
 #endif
diff -urN linux-2.6.24.7-rt20/include/linux/pci_ids.h linux-2.6.24.7-rt20-atom/include/linux/pci_ids.h
--- linux-2.6.24.7-rt20/include/linux/pci_ids.h	2008-10-06 08:30:34.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/include/linux/pci_ids.h	2008-09-28 11:31:44.000000000 +0200
@@ -2371,6 +2371,20 @@
 #define PCI_DEVICE_ID_INTEL_82443GX_0	0x71a0
 #define PCI_DEVICE_ID_INTEL_82443GX_2	0x71a2
 #define PCI_DEVICE_ID_INTEL_82372FB_1	0x7601
+#define PCI_DEVICE_ID_INTEL_POULSBO_HC  0x8100
+#define PCI_DEVICE_ID_INTEL_POULSBO_PE1 0x8110
+#define PCI_DEVICE_ID_INTEL_POULSBO_PE2 0x8112
+#define PCI_DEVICE_ID_INTEL_POULSBO_UC1 0x8114
+#define PCI_DEVICE_ID_INTEL_POULSBO_UC2 0x8115
+#define PCI_DEVICE_ID_INTEL_POULSBO_UC3 0x8116
+#define PCI_DEVICE_ID_INTEL_POULSBO_EC  0x8117
+#define PCI_DEVICE_ID_INTEL_POULSBO_UT  0x8118
+#define PCI_DEVICE_ID_INTEL_POULSBO_LPC 0x8119
+#define PCI_DEVICE_ID_INTEL_POULSBO_IDE 0x811a
+#define PCI_DEVICE_ID_INTEL_POULSBO_HDA 0x811b
+#define PCI_DEVICE_ID_INTEL_POULSBO_SD1 0x811c
+#define PCI_DEVICE_ID_INTEL_POULSBO_SD2 0x811d
+#define PCI_DEVICE_ID_INTEL_POULSBO_SD3 0x811e
 #define PCI_DEVICE_ID_INTEL_82454GX	0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
diff -urN linux-2.6.24.7-rt20/include/linux/thermal.h linux-2.6.24.7-rt20-atom/include/linux/thermal.h
--- linux-2.6.24.7-rt20/include/linux/thermal.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/include/linux/thermal.h	2008-09-28 11:30:55.000000000 +0200
@@ -0,0 +1,94 @@
+/*
+ *  thermal.h  ($Revision: 0 $)
+ *
+ *  Copyright (C) 2008  Intel Corp
+ *  Copyright (C) 2008  Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008  Sujith Thomas <sujith.thomas@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __THERMAL_H__
+#define __THERMAL_H__
+
+#include <linux/idr.h>
+#include <linux/device.h>
+
+struct thermal_zone_device;
+struct thermal_cooling_device;
+
+struct thermal_zone_device_ops {
+	int (*bind) (struct thermal_zone_device *,
+		     struct thermal_cooling_device *);
+	int (*unbind) (struct thermal_zone_device *,
+		       struct thermal_cooling_device *);
+	int (*get_temp) (struct thermal_zone_device *, char *);
+	int (*get_mode) (struct thermal_zone_device *, char *);
+	int (*set_mode) (struct thermal_zone_device *, const char *);
+	int (*get_trip_type) (struct thermal_zone_device *, int, char *);
+	int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+};
+
+struct thermal_cooling_device_ops {
+	int (*get_max_state) (struct thermal_cooling_device *, char *);
+	int (*get_cur_state) (struct thermal_cooling_device *, char *);
+	int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
+};
+
+#define THERMAL_TRIPS_NONE -1
+#define THERMAL_MAX_TRIPS 10
+#define THERMAL_NAME_LENGTH 20
+struct thermal_cooling_device {
+	int id;
+	char type[THERMAL_NAME_LENGTH];
+	struct device device;
+	void *devdata;
+	struct thermal_cooling_device_ops *ops;
+	struct list_head node;
+};
+
+#define KELVIN_TO_CELSIUS(t)	(long)(((long)t-2732 >= 0) ?	\
+				((long)t-2732+5)/10 : ((long)t-2732-5)/10)
+#define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
+
+struct thermal_zone_device {
+	int id;
+	char type[THERMAL_NAME_LENGTH];
+	struct device device;
+	void *devdata;
+	int trips;
+	struct thermal_zone_device_ops *ops;
+	struct list_head cooling_devices;
+	struct idr idr;
+	struct mutex lock;	/* protect cooling devices list */
+	struct list_head node;
+};
+
+struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
+					struct thermal_zone_device_ops *);
+void thermal_zone_device_unregister(struct thermal_zone_device *);
+
+int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
+				     struct thermal_cooling_device *);
+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
+				       struct thermal_cooling_device *);
+
+struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
+					struct thermal_cooling_device_ops *);
+void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+
+#endif				/* __THERMAL_H__ */
diff -urN linux-2.6.24.7-rt20/include/sound/core.h linux-2.6.24.7-rt20-atom/include/sound/core.h
--- linux-2.6.24.7-rt20/include/sound/core.h	2008-10-06 08:30:34.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/include/sound/core.h	2008-09-28 23:51:34.000000000 +0200
@@ -22,12 +22,22 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/sched.h>		/* wake_up() */
 #include <linux/mutex.h>		/* struct mutex */
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/pm.h>			/* pm_message_t */
 #include <linux/device.h>
 
+/* number of supported soundcards */
+#ifdef CONFIG_SND_DYNAMIC_MINORS
+#define SNDRV_CARDS 32
+#else
+#define SNDRV_CARDS 8		/* don't change - minor numbers */
+#endif
+
+#define CONFIG_SND_MAJOR	116	/* standard configuration */
+
 /* forward declarations */
 #ifdef CONFIG_PCI
 struct pci_dev;
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_codec.c linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_codec.c
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_codec.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_codec.c	2008-09-28 23:33:40.000000000 +0200
@@ -19,7 +19,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -52,12 +51,18 @@
 
 /* codec vendor labels */
 static struct hda_vendor_id hda_vendor_ids[] = {
-	{ 0x10ec, "Realtek" },
+	{ 0x1002, "ATI" },
 	{ 0x1057, "Motorola" },
+	{ 0x1095, "Silicon Image" },
+	{ 0x10ec, "Realtek" },
 	{ 0x1106, "VIA" },
+	{ 0x111d, "IDT" },
+	{ 0x11c1, "LSI" },
 	{ 0x11d4, "Analog Devices" },
 	{ 0x13f6, "C-Media" },
 	{ 0x14f1, "Conexant" },
+	{ 0x17e8, "Chrontel" },
+	{ 0x1854, "LG" },
 	{ 0x434d, "C-Media" },
 	{ 0x8384, "SigmaTel" },
 	{} /* terminator */
@@ -429,6 +434,10 @@
 	for (tbl = hda_preset_tables; *tbl; tbl++) {
 		for (preset = *tbl; preset->id; preset++) {
 			u32 mask = preset->mask;
+			if (preset->afg && preset->afg != codec->afg)
+				continue;
+			if (preset->mfg && preset->mfg != codec->mfg)
+				continue;
 			if (!mask)
 				mask = ~0;
 			if (preset->id == (codec->vendor_id & mask) &&
@@ -765,7 +774,7 @@
 /*
  * query AMP capabilities for the given widget and direction
  */
-static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
+u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
 	struct hda_amp_info *info;
 
@@ -933,7 +942,8 @@
 	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
 	if (!caps) {
 		printk(KERN_WARNING "hda_codec: "
-		       "num_steps = 0 for NID=0x%x\n", nid);
+		       "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
+		       kcontrol->id.name);
 		return -EINVAL;
 	}
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -1012,6 +1022,80 @@
 	return 0;
 }
 
+/*
+ * set (static) TLV for virtual master volume; recalculated as max 0dB
+ */
+void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
+			     unsigned int *tlv)
+{
+	u32 caps;
+	int nums, step;
+
+	caps = query_amp_caps(codec, nid, dir);
+	nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
+	step = (step + 1) * 25;
+	tlv[0] = SNDRV_CTL_TLVT_DB_SCALE;
+	tlv[1] = 2 * sizeof(unsigned int);
+	tlv[2] = -nums * step;
+	tlv[3] = step;
+}
+
+/* find a mixer control element with the given name */
+static struct snd_kcontrol *
+_snd_hda_find_mixer_ctl(struct hda_codec *codec,
+			const char *name, int idx)
+{
+	struct snd_ctl_elem_id id;
+	memset(&id, 0, sizeof(id));
+	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	id.index = idx;
+	strcpy(id.name, name);
+	return snd_ctl_find_id(codec->bus->card, &id);
+}
+
+struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
+					    const char *name)
+{
+	return _snd_hda_find_mixer_ctl(codec, name, 0);
+}
+
+/* create a virtual master control and add slaves */
+int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+			unsigned int *tlv, const char **slaves)
+{
+	struct snd_kcontrol *kctl;
+	const char **s;
+	int err;
+
+	for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
+		;
+	if (!*s) {
+		snd_printdd("No slave found for %s\n", name);
+		return 0;
+	}
+	kctl = snd_ctl_make_virtual_master(name, tlv);
+	if (!kctl)
+		return -ENOMEM;
+	err = snd_ctl_add(codec->bus->card, kctl);
+	if (err < 0)
+		return err;
+	
+	for (s = slaves; *s; s++) {
+		struct snd_kcontrol *sctl;
+
+		sctl = snd_hda_find_mixer_ctl(codec, *s);
+		if (!sctl) {
+			snd_printdd("Cannot find slave %s, skipped\n", *s);
+			continue;
+		}
+		err = snd_ctl_add_slave(kctl, sctl);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
 /* switch */
 int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_info *uinfo)
@@ -1410,6 +1494,8 @@
 	{ } /* end */
 };
 
+#define SPDIF_MAX_IDX	4	/* 4 instances should be enough to probe */
+
 /**
  * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls
  * @codec: the HDA codec
@@ -1425,21 +1511,70 @@
 	int err;
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol_new *dig_mix;
+	int idx;
 
+	for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
+		if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch",
+					     idx))
+			break;
+	}
+	if (idx >= SPDIF_MAX_IDX) {
+		printk(KERN_ERR "hda_codec: too many IEC958 outputs\n");
+		return -EBUSY;
+	}
 	for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
 		kctl = snd_ctl_new1(dig_mix, codec);
+		kctl->id.index = idx;
 		kctl->private_value = nid;
 		err = snd_ctl_add(codec->bus->card, kctl);
 		if (err < 0)
 			return err;
 	}
 	codec->spdif_ctls =
-		snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+		snd_hda_codec_read(codec, nid, 0,
+				   AC_VERB_GET_DIGI_CONVERT_1, 0);
 	codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
 	return 0;
 }
 
 /*
+ * SPDIF sharing with analog output
+ */
+static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = mout->share_spdif;
+	return 0;
+}
+
+static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
+	mout->share_spdif = !!ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static struct snd_kcontrol_new spdif_share_sw = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Default PCM Playback Switch",
+	.info = snd_ctl_boolean_mono_info,
+	.get = spdif_share_sw_get,
+	.put = spdif_share_sw_put,
+};
+
+int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
+				  struct hda_multi_out *mout)
+{
+	if (!mout->dig_out_nid)
+		return 0;
+	/* ATTENTION: here mout is passed as private_data, instead of codec */
+	return snd_ctl_add(codec->bus->card,
+			   snd_ctl_new1(&spdif_share_sw, mout));
+}
+
+/*
  * SPDIF input
  */
 
@@ -1481,7 +1616,7 @@
 	unsigned short val;
 	unsigned int sbits;
 
-	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+	val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
 	sbits = convert_to_spdif_status(val);
 	ucontrol->value.iec958.status[0] = sbits;
 	ucontrol->value.iec958.status[1] = sbits >> 8;
@@ -1523,7 +1658,17 @@
 	int err;
 	struct snd_kcontrol *kctl;
 	struct snd_kcontrol_new *dig_mix;
+	int idx;
 
+	for (idx = 0; idx < SPDIF_MAX_IDX; idx++) {
+		if (!_snd_hda_find_mixer_ctl(codec, "IEC958 Capture Switch",
+					     idx))
+			break;
+	}
+	if (idx >= SPDIF_MAX_IDX) {
+		printk(KERN_ERR "hda_codec: too many IEC958 inputs\n");
+		return -EBUSY;
+	}
 	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) {
 		kctl = snd_ctl_new1(dig_mix, codec);
 		kctl->private_value = nid;
@@ -1532,7 +1677,8 @@
 			return err;
 	}
 	codec->spdif_in_enable =
-		snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) &
+		snd_hda_codec_read(codec, nid, 0,
+				   AC_VERB_GET_DIGI_CONVERT_1, 0) &
 		AC_DIG1_ENABLE;
 	return 0;
 }
@@ -1622,6 +1768,7 @@
 
 	snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
 			    power_state);
+	msleep(10); /* partial workaround for "azx_get_response timeout" */
 
 	nid = codec->start_nid;
 	for (i = 0; i < codec->num_nodes; i++, nid++) {
@@ -2336,7 +2483,8 @@
 	unsigned int mode;
 
 	mode = ucontrol->value.enumerated.item[0];
-	snd_assert(mode < num_chmodes, return -EINVAL);
+	if (mode >= num_chmodes)
+		return -EINVAL;
 	if (*max_channelsp == chmode[mode].channels)
 		return 0;
 	/* change the current channel setting */
@@ -2451,9 +2599,36 @@
  */
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
 				  struct hda_multi_out *mout,
-				  struct snd_pcm_substream *substream)
+				  struct snd_pcm_substream *substream,
+				  struct hda_pcm_stream *hinfo)
 {
-	substream->runtime->hw.channels_max = mout->max_channels;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	runtime->hw.channels_max = mout->max_channels;
+	if (mout->dig_out_nid) {
+		if (!mout->analog_rates) {
+			mout->analog_rates = hinfo->rates;
+			mout->analog_formats = hinfo->formats;
+			mout->analog_maxbps = hinfo->maxbps;
+		} else {
+			runtime->hw.rates = mout->analog_rates;
+			runtime->hw.formats = mout->analog_formats;
+			hinfo->maxbps = mout->analog_maxbps;
+		}
+		if (!mout->spdif_rates) {
+			snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
+						    &mout->spdif_rates,
+						    &mout->spdif_formats,
+						    &mout->spdif_maxbps);
+		}
+		mutex_lock(&codec->spdif_mutex);
+		if (mout->share_spdif) {
+			runtime->hw.rates &= mout->spdif_rates;
+			runtime->hw.formats &= mout->spdif_formats;
+			if (mout->spdif_maxbps < hinfo->maxbps)
+				hinfo->maxbps = mout->spdif_maxbps;
+		}
+	}
+	mutex_unlock(&codec->spdif_mutex);
 	return snd_pcm_hw_constraint_step(substream->runtime, 0,
 					  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
 }
@@ -2473,7 +2648,8 @@
 	int i;
 
 	mutex_lock(&codec->spdif_mutex);
-	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+	if (mout->dig_out_nid && mout->share_spdif &&
+	    mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
 		if (chs == 2 &&
 		    snd_hda_is_supported_format(codec, mout->dig_out_nid,
 						format) &&
@@ -2602,20 +2778,21 @@
 				 struct auto_pin_cfg *cfg,
 				 hda_nid_t *ignore_nids)
 {
-	hda_nid_t nid, nid_start;
-	int nodes;
+	hda_nid_t nid, end_nid;
 	short seq, assoc_line_out, assoc_speaker;
 	short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
 	short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
+	short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
 
 	memset(cfg, 0, sizeof(*cfg));
 
 	memset(sequences_line_out, 0, sizeof(sequences_line_out));
 	memset(sequences_speaker, 0, sizeof(sequences_speaker));
+	memset(sequences_hp, 0, sizeof(sequences_hp));
 	assoc_line_out = assoc_speaker = 0;
 
-	nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
-	for (nid = nid_start; nid < nodes + nid_start; nid++) {
+	end_nid = codec->start_nid + codec->num_nodes;
+	for (nid = codec->start_nid; nid < end_nid; nid++) {
 		unsigned int wid_caps = get_wcaps(codec, nid);
 		unsigned int wid_type =
 			(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
@@ -2638,6 +2815,10 @@
 		case AC_JACK_LINE_OUT:
 			seq = get_defcfg_sequence(def_conf);
 			assoc = get_defcfg_association(def_conf);
+
+			if (!(wid_caps & AC_WCAP_STEREO))
+				if (!cfg->mono_out_pin)
+					cfg->mono_out_pin = nid;
 			if (!assoc)
 				continue;
 			if (!assoc_line_out)
@@ -2666,9 +2847,12 @@
 			cfg->speaker_outs++;
 			break;
 		case AC_JACK_HP_OUT:
+			seq = get_defcfg_sequence(def_conf);
+			assoc = get_defcfg_association(def_conf);
 			if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
 				continue;
 			cfg->hp_pins[cfg->hp_outs] = nid;
+			sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
 			cfg->hp_outs++;
 			break;
 		case AC_JACK_MIC_IN: {
@@ -2707,12 +2891,53 @@
 		}
 	}
 
+	/* FIX-UP:
+	 * If no line-out is defined but multiple HPs are found,
+	 * some of them might be the real line-outs.
+	 */
+	if (!cfg->line_outs && cfg->hp_outs > 1) {
+		int i = 0;
+		while (i < cfg->hp_outs) {
+			/* The real HPs should have the sequence 0x0f */
+			if ((sequences_hp[i] & 0x0f) == 0x0f) {
+				i++;
+				continue;
+			}
+			/* Move it to the line-out table */
+			cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
+			sequences_line_out[cfg->line_outs] = sequences_hp[i];
+			cfg->line_outs++;
+			cfg->hp_outs--;
+			memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
+				sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
+			memmove(sequences_hp + i - 1, sequences_hp + i,
+				sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
+		}
+	}
+
 	/* sort by sequence */
 	sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
 			      cfg->line_outs);
 	sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
 			      cfg->speaker_outs);
+	sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
+			      cfg->hp_outs);
 	
+	/* if we have only one mic, make it AUTO_PIN_MIC */
+	if (!cfg->input_pins[AUTO_PIN_MIC] &&
+	    cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
+		cfg->input_pins[AUTO_PIN_MIC] =
+			cfg->input_pins[AUTO_PIN_FRONT_MIC];
+		cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
+	}
+	/* ditto for line-in */
+	if (!cfg->input_pins[AUTO_PIN_LINE] &&
+	    cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
+		cfg->input_pins[AUTO_PIN_LINE] =
+			cfg->input_pins[AUTO_PIN_FRONT_LINE];
+		cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
+	}
+
 	/*
 	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
 	 * as a primary output
@@ -2766,6 +2991,7 @@
 		   cfg->hp_outs, cfg->hp_pins[0],
 		   cfg->hp_pins[1], cfg->hp_pins[2],
 		   cfg->hp_pins[3], cfg->hp_pins[4]);
+	snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
 	snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
 		   " cd=0x%x, aux=0x%x\n",
 		   cfg->input_pins[AUTO_PIN_MIC],
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_codec.h linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_codec.h
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_codec.h	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_codec.h	2008-09-28 23:33:40.000000000 +0200
@@ -77,12 +77,16 @@
 #define AC_VERB_GET_PIN_SENSE			0x0f09
 #define AC_VERB_GET_BEEP_CONTROL		0x0f0a
 #define AC_VERB_GET_EAPD_BTLENABLE		0x0f0c
-#define AC_VERB_GET_DIGI_CONVERT		0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_1		0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_2		0x0f0e
 #define AC_VERB_GET_VOLUME_KNOB_CONTROL		0x0f0f
 /* f10-f1a: GPIO */
 #define AC_VERB_GET_GPIO_DATA			0x0f15
 #define AC_VERB_GET_GPIO_MASK			0x0f16
 #define AC_VERB_GET_GPIO_DIRECTION		0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK		0x0f18
+#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK	0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK		0x0f1a
 #define AC_VERB_GET_CONFIG_DEFAULT		0x0f1c
 /* f20: AFG/MFG */
 #define AC_VERB_GET_SUBSYSTEM_ID		0x0f20
@@ -110,6 +114,9 @@
 #define AC_VERB_SET_GPIO_DATA			0x715
 #define AC_VERB_SET_GPIO_MASK			0x716
 #define AC_VERB_SET_GPIO_DIRECTION		0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK		0x718
+#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK	0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK		0x71a
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0	0x71c
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1	0x71d
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2	0x71e
@@ -135,6 +142,7 @@
 #define AC_PAR_PROC_CAP			0x10
 #define AC_PAR_GPIO_CAP			0x11
 #define AC_PAR_AMP_OUT_CAP		0x12
+#define AC_PAR_VOL_KNB_CAP		0x13
 
 /*
  * AC_VERB_PARAMETERS results (32bit)
@@ -181,6 +189,27 @@
 #define AC_SUPFMT_FLOAT32		(1<<1)
 #define AC_SUPFMT_AC3			(1<<2)
 
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT		(0xff<<0)
+#define AC_GPIO_O_COUNT			(0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT		8
+#define AC_GPIO_I_COUNT			(0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT		16
+#define AC_GPIO_UNSOLICITED		(1<<30)
+#define AC_GPIO_WAKE			(1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL			(0xf<<0)
+#define AC_CONV_STREAM			(0xf<<4)
+#define AC_CONV_STREAM_SHIFT		4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT			(0xf<<0)
+
+/* Unsolicited response */
+#define AC_UNSOL_TAG			(0x3f<<0)
+#define AC_UNSOL_ENABLED		(1<<7)
+
 /* Pin widget capabilies */
 #define AC_PINCAP_IMP_SENSE		(1<<0)	/* impedance sense capable */
 #define AC_PINCAP_TRIG_REQ		(1<<1)	/* trigger required */
@@ -189,6 +218,10 @@
 #define AC_PINCAP_OUT			(1<<4)	/* output capable */
 #define AC_PINCAP_IN			(1<<5)	/* input capable */
 #define AC_PINCAP_BALANCE		(1<<6)	/* balanced I/O capable */
+/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
+ *       but is marked reserved in the Intel HDA specification.
+ */
+#define AC_PINCAP_LR_SWAP		(1<<7)	/* L/R swap */
 #define AC_PINCAP_VREF			(0x37<<8)
 #define AC_PINCAP_VREF_SHIFT		8
 #define AC_PINCAP_EAPD			(1<<16)	/* EAPD capable */
@@ -222,6 +255,9 @@
 #define AC_PWRST_D3SUP			(1<<3)
 
 /* Power state values */
+#define AC_PWRST_SETTING		(0xf<<0)
+#define AC_PWRST_ACTUAL			(0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT		4
 #define AC_PWRST_D0			0x00
 #define AC_PWRST_D1			0x01
 #define AC_PWRST_D2			0x02
@@ -230,10 +266,11 @@
 /* Processing capabilies */
 #define AC_PCAP_BENIGN			(1<<0)
 #define AC_PCAP_NUM_COEF		(0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT		8
 
 /* Volume knobs capabilities */
 #define AC_KNBCAP_NUM_STEPS		(0x7f<<0)
-#define AC_KNBCAP_DELTA			(1<<8)
+#define AC_KNBCAP_DELTA			(1<<7)
 
 /*
  * Control Parameters
@@ -266,6 +303,9 @@
 #define AC_DIG1_PROFESSIONAL		(1<<6)
 #define AC_DIG1_LEVEL			(1<<7)
 
+/* DIGITAL2 bits */
+#define AC_DIG2_CC			(0x7f<<0)
+
 /* Pin widget control - 8bit */
 #define AC_PINCTL_VREFEN		(0x7<<0)
 #define AC_PINCTL_VREF_HIZ		0	/* Hi-Z */
@@ -280,12 +320,22 @@
 /* Unsolicited response - 8bit */
 #define AC_USRSP_EN			(1<<7)
 
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK	(0x7fffffff)
+#define AC_PINSENSE_PRESENCE		(1<<31)
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED		(1<<0)
+#define AC_EAPDBTL_EAPD			(1<<1)
+#define AC_EAPDBTL_LR_SWAP		(1<<2)
+
 /* configuration default - 32bit */
 #define AC_DEFCFG_SEQUENCE		(0xf<<0)
 #define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
 #define AC_DEFCFG_ASSOC_SHIFT		4
 #define AC_DEFCFG_MISC			(0xf<<8)
 #define AC_DEFCFG_MISC_SHIFT		8
+#define AC_DEFCFG_MISC_NO_PRESENCE	(1<<0)
 #define AC_DEFCFG_COLOR			(0xf<<12)
 #define AC_DEFCFG_COLOR_SHIFT		12
 #define AC_DEFCFG_CONN_TYPE		(0xf<<16)
@@ -417,7 +467,7 @@
 	/* free the private data */
 	void (*private_free)(struct hda_bus *);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-	/* notify power-up/down from codec to contoller */
+	/* notify power-up/down from codec to controller */
 	void (*pm_notify)(struct hda_codec *codec);
 #endif
 };
@@ -456,6 +506,9 @@
 	struct hda_bus_unsolicited *unsol;
 
 	struct snd_info_entry *proc;
+
+	/* misc op flags */
+	unsigned int needs_damn_long_delay :1;
 };
 
 /*
@@ -470,6 +523,7 @@
 	unsigned int subs;
 	unsigned int subs_mask;
 	unsigned int rev;
+	hda_nid_t afg, mfg;
 	const char *name;
 	int (*patch)(struct hda_codec *codec);
 };
@@ -536,11 +590,21 @@
 	struct hda_pcm_ops ops;
 };
 
+/* PCM types */
+enum {
+	HDA_PCM_TYPE_AUDIO,
+	HDA_PCM_TYPE_SPDIF,
+	HDA_PCM_TYPE_HDMI,
+	HDA_PCM_TYPE_MODEM,
+	HDA_PCM_NTYPES
+};
+
 /* for PCM creation */
 struct hda_pcm {
 	char *name;
 	struct hda_pcm_stream stream[2];
-	unsigned int is_modem;	/* modem codec? */
+	unsigned int pcm_type;	/* HDA_PCM_TYPE_XXX */
+	int device;	/* assigned device number */
 };
 
 /* codec information */
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_generic.c linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_generic.c
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_generic.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_generic.c	2008-09-28 23:33:39.000000000 +0200
@@ -20,7 +20,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_hwdep.c linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_hwdep.c
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_hwdep.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_hwdep.c	2008-09-28 23:33:39.000000000 +0200
@@ -18,7 +18,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_intel.c linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_intel.c
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_intel.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_intel.c	2008-09-28 23:33:41.000000000 +0200
@@ -34,7 +34,6 @@
  * 
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -50,31 +49,40 @@
 #include "hda_codec.h"
 
 
-static int index = SNDRV_DEFAULT_IDX1;
-static char *id = SNDRV_DEFAULT_STR1;
-static char *model;
-static int position_fix;
-static int probe_mask = -1;
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static char *model[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS];
+static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int single_cmd;
 static int enable_msi;
 
-module_param(index, int, 0444);
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
-module_param(id, charp, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
-module_param(model, charp, 0444);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
+module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
-module_param(position_fix, int, 0444);
+module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
 		 "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
-module_param(probe_mask, int, 0444);
+module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
 		 "(for debugging only).");
-module_param(enable_msi, int, 0);
+module_param(enable_msi, int, 0444);
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
+/* For workaround Poulsbo SI bugs, it affects stream descriptor offset and
+ * corresponding control bits
+ */
+static int sd_offset_fixup= 0;
+static int sd_bit_fixup=0;
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 /* power_save option is defined in hda_codec.c */
 
@@ -87,10 +95,6 @@
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif
 
-/* just for backward compatibility */
-static int enable;
-module_param(enable, bool, 0444);
-
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
 			 "{Intel, ICH6M},"
@@ -98,12 +102,20 @@
 			 "{Intel, ESB2},"
 			 "{Intel, ICH8},"
 			 "{Intel, ICH9},"
+			 "{Intel, ICH10},"
+			 "{Intel, SCH},"
 			 "{ATI, SB450},"
 			 "{ATI, SB600},"
 			 "{ATI, RS600},"
 			 "{ATI, RS690},"
 			 "{ATI, RS780},"
 			 "{ATI, R600},"
+			 "{ATI, RV630},"
+			 "{ATI, RV610},"
+			 "{ATI, RV670},"
+			 "{ATI, RV635},"
+			 "{ATI, RV620},"
+			 "{ATI, RV770},"
 			 "{VIA, VT8251},"
 			 "{VIA, VT8237A},"
 			 "{SiS, SIS966},"
@@ -200,14 +212,13 @@
 #define MAX_AZX_DEV		16
 
 /* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE		PAGE_ALIGN(8192)
-#define AZX_MAX_FRAG		(BDL_SIZE / (MAX_AZX_DEV * 16))
+#define BDL_SIZE		4096
+#define AZX_MAX_BDL_ENTRIES	(BDL_SIZE / 16)
+#define AZX_MAX_FRAG		32
 /* max buffer size - no h/w limit, you can increase as you like */
 #define AZX_MAX_BUF_SIZE	(1024*1024*1024)
 /* max number of PCM devics per card */
-#define AZX_MAX_AUDIO_PCMS	6
-#define AZX_MAX_MODEM_PCMS	2
-#define AZX_MAX_PCMS		(AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS)
+#define AZX_MAX_PCMS		8
 
 /* RIRB int mask: overrun[2], response[0] */
 #define RIRB_INT_RESPONSE	0x01
@@ -269,16 +280,23 @@
 #define NVIDIA_HDA_TRANSREG_ADDR      0x4e
 #define NVIDIA_HDA_ENABLE_COHBITS     0x0f
 
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
 /*
  */
 
 struct azx_dev {
-	u32 *bdl;		/* virtual address of the BDL */
-	dma_addr_t bdl_addr;	/* physical address of the BDL */
+	struct snd_dma_buffer bdl; /* BDL buffer */
 	u32 *posbuf;		/* position buffer pointer */
 
 	unsigned int bufsize;	/* size of the play buffer in bytes */
-	unsigned int fragsize;	/* size of each period in bytes */
 	unsigned int frags;	/* number for period in the play buffer */
 	unsigned int fifo_size;	/* FIFO size */
 
@@ -339,7 +357,6 @@
 	struct azx_dev *azx_dev;
 
 	/* PCM */
-	unsigned int pcm_devs;
 	struct snd_pcm *pcm[AZX_MAX_PCMS];
 
 	/* HD codec */
@@ -350,8 +367,7 @@
 	struct azx_rb corb;
 	struct azx_rb rirb;
 
-	/* BDL, CORB/RIRB and position buffers */
-	struct snd_dma_buffer bdl;
+	/* CORB/RIRB and position buffers */
 	struct snd_dma_buffer rb;
 	struct snd_dma_buffer posbuf;
 
@@ -370,6 +386,7 @@
 /* driver types */
 enum {
 	AZX_DRIVER_ICH,
+	AZX_DRIVER_SCH,
 	AZX_DRIVER_ATI,
 	AZX_DRIVER_ATIHDMI,
 	AZX_DRIVER_VIA,
@@ -380,6 +397,7 @@
 
 static char *driver_short_names[] __devinitdata = {
 	[AZX_DRIVER_ICH] = "HDA Intel",
+	[AZX_DRIVER_SCH] = "HDA Intel MID",
 	[AZX_DRIVER_ATI] = "HDA ATI SB",
 	[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
 	[AZX_DRIVER_VIA] = "HDA VIA VT82xx",
@@ -547,7 +565,7 @@
 
  again:
 	timeout = jiffies + msecs_to_jiffies(1000);
-	do {
+	for (;;) {
 		if (chip->polling_mode) {
 			spin_lock_irq(&chip->reg_lock);
 			azx_update_rirb(chip);
@@ -555,8 +573,15 @@
 		}
 		if (!chip->rirb.cmds)
 			return chip->rirb.res; /* the last value */
-		schedule_timeout_uninterruptible(1);
-	} while (time_after_eq(timeout, jiffies));
+		if (time_after(jiffies, timeout))
+			break;
+		if (codec->bus->needs_damn_long_delay)
+			msleep(2); /* temporary workaround */
+		else {
+			udelay(10);
+			cond_resched();
+		}
+	}
 
 	if (chip->msi) {
 		snd_printk(KERN_WARNING "hda_intel: No response from codec, "
@@ -618,8 +643,9 @@
 		}
 		udelay(1);
 	}
-	snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
-		   azx_readw(chip, IRS), val);
+	if (printk_ratelimit())
+		snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+			   azx_readw(chip, IRS), val);
 	return -EIO;
 }
 
@@ -635,8 +661,9 @@
 			return azx_readl(chip, IR);
 		udelay(1);
 	}
-	snd_printd(SFX "get_response timeout: IRS=0x%x\n",
-		   azx_readw(chip, IRS));
+	if (printk_ratelimit())
+		snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+			   azx_readw(chip, IRS));
 	return (unsigned int)-1;
 }
 
@@ -788,8 +815,20 @@
 static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
 {
 	/* enable SIE */
-	azx_writeb(chip, INTCTL,
-		   azx_readb(chip, INTCTL) | (1 << azx_dev->index));
+	if (!sd_bit_fixup) {
+		azx_writeb(chip, INTCTL,
+			azx_readb(chip, INTCTL) | (1 << azx_dev->index));
+	}
+	else {
+		if (azx_dev->index < sd_bit_fixup) {
+			azx_writel(chip, INTCTL,
+				azx_readl(chip, INTCTL) | (1 << azx_dev->index));
+		} else {
+			azx_writel(chip, INTCTL,
+				azx_readl(chip, INTCTL) | (1 << (azx_dev->index+sd_bit_fixup)));
+		}
+	}
+
 	/* set DMA start and interrupt mask */
 	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
 		      SD_CTL_DMA_START | SD_INT_MASK);
@@ -803,8 +842,18 @@
 		      ~(SD_CTL_DMA_START | SD_INT_MASK));
 	azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
 	/* disable SIE */
-	azx_writeb(chip, INTCTL,
-		   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+	if (!sd_bit_fixup) {
+		azx_writeb(chip, INTCTL,
+			azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+	} else {
+		if (azx_dev->index < sd_bit_fixup ) {
+			azx_writeb(chip, INTCTL,
+		   		azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
+		} else {
+			 azx_writeb(chip, INTCTL,
+				azx_readb(chip, INTCTL) & ~(1 << (azx_dev->index+sd_bit_fixup)));
+		}
+	}
 }
 
 
@@ -851,6 +900,8 @@
 
 static void azx_init_pci(struct azx *chip)
 {
+	unsigned short snoop;
+
 	/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
 	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS
 	 * Ensuring these bits are 0 clears playback static on some HD Audio
@@ -871,6 +922,19 @@
 				NVIDIA_HDA_TRANSREG_ADDR,
 				0x0f, NVIDIA_HDA_ENABLE_COHBITS);
 		break;
+	case AZX_DRIVER_SCH:
+		pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
+		if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) {
+			pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \
+				snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP));
+			pci_read_config_word(chip->pci,
+				INTEL_SCH_HDA_DEVC, &snoop);
+			snd_printdd("HDA snoop disabled, enabling ... %s\n",\
+				(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \
+				? "Failed" : "OK");
+		}
+		break;
+
         }
 }
 
@@ -928,30 +992,57 @@
 /*
  * set up BDL entries
  */
-static void azx_setup_periods(struct azx_dev *azx_dev)
+static int azx_setup_periods(struct snd_pcm_substream *substream,
+			     struct azx_dev *azx_dev)
 {
-	u32 *bdl = azx_dev->bdl;
-	dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr;
-	int idx;
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+	u32 *bdl;
+	int i, ofs, periods, period_bytes;
 
 	/* reset BDL address */
 	azx_sd_writel(azx_dev, SD_BDLPL, 0);
 	azx_sd_writel(azx_dev, SD_BDLPU, 0);
 
-	/* program the initial BDL entries */
-	for (idx = 0; idx < azx_dev->frags; idx++) {
-		unsigned int off = idx << 2; /* 4 dword step */
-		dma_addr_t addr = dma_addr + idx * azx_dev->fragsize;
-		/* program the address field of the BDL entry */
-		bdl[off] = cpu_to_le32((u32)addr);
-		bdl[off+1] = cpu_to_le32(upper_32bit(addr));
-
-		/* program the size field of the BDL entry */
-		bdl[off+2] = cpu_to_le32(azx_dev->fragsize);
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	periods = azx_dev->bufsize / period_bytes;
 
-		/* program the IOC to enable interrupt when buffer completes */
-		bdl[off+3] = cpu_to_le32(0x01);
+	/* program the initial BDL entries */
+	bdl = (u32 *)azx_dev->bdl.area;
+	ofs = 0;
+	azx_dev->frags = 0;
+	for (i = 0; i < periods; i++) {
+		int size, rest;
+		if (i >= AZX_MAX_BDL_ENTRIES) {
+			snd_printk(KERN_ERR "Too many BDL entries: "
+				   "buffer=%d, period=%d\n",
+				   azx_dev->bufsize, period_bytes);
+			/* reset */
+			azx_sd_writel(azx_dev, SD_BDLPL, 0);
+			azx_sd_writel(azx_dev, SD_BDLPU, 0);
+			return -EINVAL;
+		}
+		rest = period_bytes;
+		do {
+			dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
+			/* program the address field of the BDL entry */
+			bdl[0] = cpu_to_le32((u32)addr);
+			bdl[1] = cpu_to_le32(upper_32bit(addr));
+			/* program the size field of the BDL entry */
+			size = PAGE_SIZE - (ofs % PAGE_SIZE);
+			if (rest < size)
+				size = rest;
+			bdl[2] = cpu_to_le32(size);
+			/* program the IOC to enable interrupt
+			 * only when the whole fragment is processed
+			 */
+			rest -= size;
+			bdl[3] = rest ? 0 : cpu_to_le32(0x01);
+			bdl += 4;
+			azx_dev->frags++;
+			ofs += size;
+		} while (rest > 0);
 	}
+	return 0;
 }
 
 /*
@@ -1000,9 +1091,9 @@
 
 	/* program the BDL address */
 	/* lower BDL address */
-	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr);
+	azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
 	/* upper BDL address */
-	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr));
+	azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr));
 
 	/* enable the position buffer */
 	if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
@@ -1023,6 +1114,7 @@
 
 static unsigned int azx_max_codecs[] __devinitdata = {
 	[AZX_DRIVER_ICH] = 3,
+	[AZX_DRIVER_SCH] = 3,
 	[AZX_DRIVER_ATI] = 4,
 	[AZX_DRIVER_ATIHDMI] = 4,
 	[AZX_DRIVER_VIA] = 3,		/* FIXME: correct? */
@@ -1031,7 +1123,8 @@
 	[AZX_DRIVER_NVIDIA] = 3,	/* FIXME: correct? */
 };
 
-static int __devinit azx_codec_create(struct azx *chip, const char *model)
+static int __devinit azx_codec_create(struct azx *chip, const char *model,
+				      unsigned int codec_probe_mask)
 {
 	struct hda_bus_template bus_temp;
 	int c, codecs, audio_codecs, err;
@@ -1052,7 +1145,7 @@
 
 	codecs = audio_codecs = 0;
 	for (c = 0; c < AZX_MAX_CODECS; c++) {
-		if ((chip->codec_mask & (1 << c)) & probe_mask) {
+		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
 			struct hda_codec *codec;
 			err = snd_hda_codec_new(chip->bus, c, &codec);
 			if (err < 0)
@@ -1065,7 +1158,7 @@
 	if (!audio_codecs) {
 		/* probe additional slots if no codec is found */
 		for (; c < azx_max_codecs[chip->driver_type]; c++) {
-			if ((chip->codec_mask & (1 << c)) & probe_mask) {
+			if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
 				err = snd_hda_codec_new(chip->bus, c, NULL);
 				if (err < 0)
 					continue;
@@ -1236,8 +1329,6 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
-	azx_dev->fragsize = snd_pcm_lib_period_bytes(substream);
-	azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize;
 	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
 							 runtime->channels,
 							 runtime->format,
@@ -1249,10 +1340,10 @@
 		return -EINVAL;
 	}
 
-	snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, "
-		    "format=0x%x\n",
-		    azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val);
-	azx_setup_periods(azx_dev);
+	snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
+		    azx_dev->bufsize, azx_dev->format_val);
+	if (azx_setup_periods(substream, azx_dev) < 0)
+		return -EINVAL;
 	azx_setup_controller(chip, azx_dev);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1339,6 +1430,7 @@
 	.prepare = azx_pcm_prepare,
 	.trigger = azx_pcm_trigger,
 	.pointer = azx_pcm_pointer,
+	.page = snd_pcm_sgbuf_ops_page,
 };
 
 static void azx_pcm_free(struct snd_pcm *pcm)
@@ -1347,7 +1439,7 @@
 }
 
 static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
-				      struct hda_pcm *cpcm, int pcm_dev)
+				      struct hda_pcm *cpcm)
 {
 	int err;
 	struct snd_pcm *pcm;
@@ -1361,7 +1453,7 @@
 
 	snd_assert(cpcm->name, return -EINVAL);
 
-	err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
+	err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
 			  cpcm->stream[0].substreams,
 			  cpcm->stream[1].substreams,
 			  &pcm);
@@ -1381,62 +1473,70 @@
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
 	if (cpcm->stream[1].substreams)
 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 					      snd_dma_pci_data(chip->pci),
 					      1024 * 64, 1024 * 1024);
-	chip->pcm[pcm_dev] = pcm;
-	if (chip->pcm_devs < pcm_dev + 1)
-		chip->pcm_devs = pcm_dev + 1;
-
+	chip->pcm[cpcm->device] = pcm;
 	return 0;
 }
 
 static int __devinit azx_pcm_create(struct azx *chip)
 {
+	static const char *dev_name[HDA_PCM_NTYPES] = {
+		"Audio", "SPDIF", "HDMI", "Modem"
+	};
+	/* starting device index for each PCM type */
+	static int dev_idx[HDA_PCM_NTYPES] = {
+		[HDA_PCM_TYPE_AUDIO] = 0,
+		[HDA_PCM_TYPE_SPDIF] = 1,
+		[HDA_PCM_TYPE_HDMI] = 3,
+		[HDA_PCM_TYPE_MODEM] = 6
+	};
+	/* normal audio device indices; not linear to keep compatibility */
+	static int audio_idx[4] = { 0, 2, 4, 5 };
 	struct hda_codec *codec;
 	int c, err;
-	int pcm_dev;
+	int num_devs[HDA_PCM_NTYPES];
 
 	err = snd_hda_build_pcms(chip->bus);
 	if (err < 0)
 		return err;
 
 	/* create audio PCMs */
-	pcm_dev = 0;
-	list_for_each_entry(codec, &chip->bus->codec_list, list) {
-		for (c = 0; c < codec->num_pcms; c++) {
-			if (codec->pcm_info[c].is_modem)
-				continue; /* create later */
-			if (pcm_dev >= AZX_MAX_AUDIO_PCMS) {
-				snd_printk(KERN_ERR SFX
-					   "Too many audio PCMs\n");
-				return -EINVAL;
-			}
-			err = create_codec_pcm(chip, codec,
-					       &codec->pcm_info[c], pcm_dev);
-			if (err < 0)
-				return err;
-			pcm_dev++;
-		}
-	}
-
-	/* create modem PCMs */
-	pcm_dev = AZX_MAX_AUDIO_PCMS;
+	memset(num_devs, 0, sizeof(num_devs));
 	list_for_each_entry(codec, &chip->bus->codec_list, list) {
 		for (c = 0; c < codec->num_pcms; c++) {
-			if (!codec->pcm_info[c].is_modem)
-				continue; /* already created */
-			if (pcm_dev >= AZX_MAX_PCMS) {
-				snd_printk(KERN_ERR SFX
-					   "Too many modem PCMs\n");
-				return -EINVAL;
+			struct hda_pcm *cpcm = &codec->pcm_info[c];
+			int type = cpcm->pcm_type;
+			switch (type) {
+			case HDA_PCM_TYPE_AUDIO:
+				if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
+					snd_printk(KERN_WARNING
+						   "Too many audio devices\n");
+					continue;
+				}
+				cpcm->device = audio_idx[num_devs[type]];
+				break;
+			case HDA_PCM_TYPE_SPDIF:
+			case HDA_PCM_TYPE_HDMI:
+			case HDA_PCM_TYPE_MODEM:
+				if (num_devs[type]) {
+					snd_printk(KERN_WARNING
+						   "%s already defined\n",
+						   dev_name[type]);
+					continue;
+				}
+				cpcm->device = dev_idx[type];
+				break;
+			default:
+				snd_printk(KERN_WARNING
+					   "Invalid PCM type %d\n", type);
+				continue;
 			}
-			err = create_codec_pcm(chip, codec,
-					       &codec->pcm_info[c], pcm_dev);
+			num_devs[type]++;
+			err = create_codec_pcm(chip, codec, cpcm);
 			if (err < 0)
 				return err;
-			chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM;
-			pcm_dev++;
 		}
 	}
 	return 0;
@@ -1463,15 +1563,24 @@
 	 * and initialize
 	 */
 	for (i = 0; i < chip->num_streams; i++) {
-		unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
 		struct azx_dev *azx_dev = &chip->azx_dev[i];
-		azx_dev->bdl = (u32 *)(chip->bdl.area + off);
-		azx_dev->bdl_addr = chip->bdl.addr + off;
-		azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
 		/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-		azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
-		/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
-		azx_dev->sd_int_sta_mask = 1 << i;
+		if (!sd_bit_fixup) {
+			azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
+			azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+			/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
+			azx_dev->sd_int_sta_mask = 1 << i;
+		} else {
+			if (i<sd_bit_fixup) {
+				azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8);
+				azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
+				azx_dev->sd_int_sta_mask = 1 << i;
+			} else {
+				azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80 + sd_offset_fixup);
+				azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + (2+i) * 8);
+				azx_dev->sd_int_sta_mask = 1 << (i+sd_bit_fixup);
+			}
+		}
 		/* stream tag: must be non-zero and unique */
 		azx_dev->index = i;
 		azx_dev->stream_tag = i + 1;
@@ -1548,7 +1657,7 @@
 	int i;
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-	for (i = 0; i < chip->pcm_devs; i++)
+	for (i = 0; i < AZX_MAX_PCMS; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
 	if (chip->initialized)
 		snd_hda_suspend(chip->bus, state);
@@ -1602,8 +1711,9 @@
  */
 static int azx_free(struct azx *chip)
 {
+	int i;
+
 	if (chip->initialized) {
-		int i;
 		for (i = 0; i < chip->num_streams; i++)
 			azx_stream_stop(chip, &chip->azx_dev[i]);
 		azx_stop_chip(chip);
@@ -1618,8 +1728,11 @@
 	if (chip->remap_addr)
 		iounmap(chip->remap_addr);
 
-	if (chip->bdl.area)
-		snd_dma_free_pages(&chip->bdl);
+	if (chip->azx_dev) {
+		for (i = 0; i < chip->num_streams; i++)
+			if (chip->azx_dev[i].bdl.area)
+				snd_dma_free_pages(&chip->azx_dev[i].bdl);
+	}
 	if (chip->rb.area)
 		snd_dma_free_pages(&chip->rb);
 	if (chip->posbuf.area)
@@ -1676,18 +1789,18 @@
 	{}
 };
 
-static void __devinit check_probe_mask(struct azx *chip)
+static void __devinit check_probe_mask(struct azx *chip, int dev)
 {
 	const struct snd_pci_quirk *q;
 
-	if (probe_mask == -1) {
+	if (probe_mask[dev] == -1) {
 		q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
 		if (q) {
 			printk(KERN_INFO
 			       "hda_intel: probe_mask set to 0x%x "
 			       "for device %04x:%04x\n",
 			       q->value, q->subvendor, q->subdevice);
-			probe_mask = q->value;
+			probe_mask[dev] = q->value;
 		}
 	}
 }
@@ -1697,17 +1810,19 @@
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-				int driver_type,
+				int dev, int driver_type,
 				struct azx **rchip)
 {
 	struct azx *chip;
-	int err;
+	int i, err;
+	unsigned short gcap;
+	unsigned short stepping;
 	static struct snd_device_ops ops = {
 		.dev_free = azx_dev_free,
 	};
 
 	*rchip = NULL;
-	
+
 	err = pci_enable_device(pci);
 	if (err < 0)
 		return err;
@@ -1727,8 +1842,8 @@
 	chip->driver_type = driver_type;
 	chip->msi = enable_msi;
 
-	chip->position_fix = check_position_fix(chip, position_fix);
-	check_probe_mask(chip);
+	chip->position_fix = check_position_fix(chip, position_fix[dev]);
+	check_probe_mask(chip, dev);
 
 	chip->single_cmd = single_cmd;
 
@@ -1769,25 +1884,66 @@
 	pci_set_master(pci);
 	synchronize_irq(chip->irq);
 
-	switch (chip->driver_type) {
-	case AZX_DRIVER_ULI:
-		chip->playback_streams = ULI_NUM_PLAYBACK;
-		chip->capture_streams = ULI_NUM_CAPTURE;
-		chip->playback_index_offset = ULI_PLAYBACK_INDEX;
-		chip->capture_index_offset = ULI_CAPTURE_INDEX;
-		break;
-	case AZX_DRIVER_ATIHDMI:
-		chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
-		chip->capture_streams = ATIHDMI_NUM_CAPTURE;
-		chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
-		chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
-		break;
-	default:
-		chip->playback_streams = ICH6_NUM_PLAYBACK;
-		chip->capture_streams = ICH6_NUM_CAPTURE;
-		chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
-		chip->capture_index_offset = ICH6_CAPTURE_INDEX;
-		break;
+	gcap = azx_readw(chip, GCAP);
+	snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+
+	/* allow 64bit DMA address if supported by H/W */
+	if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_64BIT_MASK))
+		pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK);
+
+	if (gcap) {
+		/* read number of streams from GCAP register instead of using
+		 * hardcoded value
+		 */
+		chip->playback_streams = (gcap & (0xF << 12)) >> 12;
+		chip->capture_streams = (gcap & (0xF << 8)) >> 8;
+		chip->playback_index_offset = chip->capture_streams;
+		chip->capture_index_offset = 0;
+		/* do fixup for poulsbo */
+		if (pci->device == PCI_DEVICE_ID_INTEL_POULSBO_HDA) {
+			snd_printk(KERN_INFO "Do fixup for Poulsbo ");
+			pci_bus_read_config_word(pci->bus, 0, 0x8, &stepping);
+			switch (stepping) {
+			case 0:
+				/* A2 has wrong OSD0 offset and control bits */
+				snd_printk(KERN_INFO "A2 stepping\n");
+				sd_offset_fixup = 0x40;
+				sd_bit_fixup = 0x2;
+				break;
+			case 2:
+			case 3:
+			case 4:
+				/* B0/1 and C0 moved OSD0 offset but not control bits */
+				snd_printk(KERN_INFO "B0/1 or C0 stepping\n");
+				sd_bit_fixup = 0x2;
+				break;
+			default:
+				break;
+			}
+		}
+	} else {
+		/* gcap didn't give any info, switching to old method */
+
+		switch (chip->driver_type) {
+		case AZX_DRIVER_ULI:
+			chip->playback_streams = ULI_NUM_PLAYBACK;
+			chip->capture_streams = ULI_NUM_CAPTURE;
+			chip->playback_index_offset = ULI_PLAYBACK_INDEX;
+			chip->capture_index_offset = ULI_CAPTURE_INDEX;
+			break;
+		case AZX_DRIVER_ATIHDMI:
+			chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+			chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+			chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
+			chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
+			break;
+		default:
+			chip->playback_streams = ICH6_NUM_PLAYBACK;
+			chip->capture_streams = ICH6_NUM_CAPTURE;
+			chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
+			chip->capture_index_offset = ICH6_CAPTURE_INDEX;
+			break;
+		}
 	}
 	chip->num_streams = chip->playback_streams + chip->capture_streams;
 	chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
@@ -1797,13 +1953,15 @@
 		goto errout;
 	}
 
-	/* allocate memory for the BDL for each stream */
-	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
-				  snd_dma_pci_data(chip->pci),
-				  BDL_SIZE, &chip->bdl);
-	if (err < 0) {
-		snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
-		goto errout;
+	for (i = 0; i < chip->num_streams; i++) {
+		/* allocate memory for the BDL for each stream */
+		err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
+					  snd_dma_pci_data(chip->pci),
+					  BDL_SIZE, &chip->azx_dev[i].bdl);
+		if (err < 0) {
+			snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
+			goto errout;
+		}
 	}
 	/* allocate memory for the position buffer */
 	err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
@@ -1869,17 +2027,25 @@
 static int __devinit azx_probe(struct pci_dev *pci,
 			       const struct pci_device_id *pci_id)
 {
+	static int dev;
 	struct snd_card *card;
 	struct azx *chip;
 	int err;
 
-	card = snd_card_new(index, id, THIS_MODULE, 0);
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
 	if (!card) {
 		snd_printk(KERN_ERR SFX "Error creating card!\n");
 		return -ENOMEM;
 	}
 
-	err = azx_create(card, pci, pci_id->driver_data, &chip);
+	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
 	if (err < 0) {
 		snd_card_free(card);
 		return err;
@@ -1887,7 +2053,7 @@
 	card->private_data = chip;
 
 	/* create codec instances */
-	err = azx_codec_create(chip, model);
+	err = azx_codec_create(chip, model[dev], probe_mask[dev]);
 	if (err < 0) {
 		snd_card_free(card);
 		return err;
@@ -1919,6 +2085,7 @@
 	chip->running = 1;
 	power_down_all_codecs(chip);
 
+	dev++;
 	return err;
 }
 
@@ -1936,12 +2103,24 @@
 	{ 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
 	{ 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
 	{ 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
+	{ 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
+	{ 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
+	{ 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SCH }, /* SCH*/
 	{ 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
 	{ 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
 	{ 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
 	{ 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
-	{ 0x1002, 0x960c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
+	{ 0x1002, 0x960f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
 	{ 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */
+	{ 0x1002, 0xaa08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV630 HDMI */
+	{ 0x1002, 0xaa10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV610 HDMI */
+	{ 0x1002, 0xaa18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV670 HDMI */
+	{ 0x1002, 0xaa20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV635 HDMI */
+	{ 0x1002, 0xaa28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV620 HDMI */
+	{ 0x1002, 0xaa30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV770 HDMI */
+	{ 0x1002, 0xaa38, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV730 HDMI */
+	{ 0x1002, 0xaa40, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV710 HDMI */
+	{ 0x1002, 0xaa48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV740 HDMI */
 	{ 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
 	{ 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
 	{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_local.h linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_local.h
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_local.h	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_local.h	2008-09-28 23:33:40.000000000 +0200
@@ -90,6 +90,13 @@
 void snd_hda_codec_resume_amp(struct hda_codec *codec);
 #endif
 
+void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
+			     unsigned int *tlv);
+struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
+					    const char *name);
+int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+			unsigned int *tlv, const char **slaves);
+
 /* amp value bits */
 #define HDA_AMP_MUTE	0x80
 #define HDA_AMP_UNMUTE	0x00
@@ -221,8 +228,18 @@
 	int max_channels;	/* currently supported analog channels */
 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
 	int no_share_stream;	/* don't share a stream with multiple pins */
+	int share_spdif;	/* share SPDIF pin */
+	/* PCM information for both analog and SPDIF DACs */
+	unsigned int analog_rates;
+	unsigned int analog_maxbps;
+	u64 analog_formats;
+	unsigned int spdif_rates;
+	unsigned int spdif_maxbps;
+	u64 spdif_formats;
 };
 
+int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
+				  struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_open(struct hda_codec *codec,
 			       struct hda_multi_out *mout);
 int snd_hda_multi_out_dig_close(struct hda_codec *codec,
@@ -234,7 +251,8 @@
 				  struct snd_pcm_substream *substream);
 int snd_hda_multi_out_analog_open(struct hda_codec *codec,
 				  struct hda_multi_out *mout,
-				  struct snd_pcm_substream *substream);
+				  struct snd_pcm_substream *substream,
+				  struct hda_pcm_stream *hinfo);
 int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
 				     struct hda_multi_out *mout,
 				     unsigned int stream_tag,
@@ -325,6 +343,7 @@
 	hda_nid_t input_pins[AUTO_PIN_LAST];
 	hda_nid_t dig_out_pin;
 	hda_nid_t dig_in_pin;
+	hda_nid_t mono_out_pin;
 };
 
 #define get_defcfg_connect(cfg) \
@@ -363,10 +382,11 @@
 {
 	if (nid < codec->start_nid ||
 	    nid >= codec->start_nid + codec->num_nodes)
-		return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+		return 0;
 	return codec->wcaps[nid - codec->start_nid];
 }
 
+u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 			      unsigned int caps);
 
@@ -398,4 +418,11 @@
 				 hda_nid_t nid);
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
+/*
+ * virtual master control
+ */
+struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+						 const unsigned int *tlv);
+int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave);
+		      
 #endif /* __SOUND_HDA_LOCAL_H */
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/hda_proc.c linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_proc.c
--- linux-2.6.24.7-rt20/sound/pci/hda/hda_proc.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/hda_proc.c	2008-09-28 23:33:40.000000000 +0200
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -203,7 +202,8 @@
 }
 
 static void print_pin_caps(struct snd_info_buffer *buffer,
-			   struct hda_codec *codec, hda_nid_t nid)
+			   struct hda_codec *codec, hda_nid_t nid,
+			   int *supports_vref)
 {
 	static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
 	static char *jack_types[16] = {
@@ -213,7 +213,7 @@
 		"SPDIF In", "Digitial In", "Reserved", "Other"
 	};
 	static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
-	unsigned int caps;
+	unsigned int caps, val;
 
 	caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
 	snd_iprintf(buffer, "  Pincap 0x08%x:", caps);
@@ -227,7 +227,45 @@
 		snd_iprintf(buffer, " EAPD");
 	if (caps & AC_PINCAP_PRES_DETECT)
 		snd_iprintf(buffer, " Detect");
+	if (caps & AC_PINCAP_BALANCE)
+		snd_iprintf(buffer, " Balanced");
+	if (caps & AC_PINCAP_LR_SWAP)
+		snd_iprintf(buffer, " R/L");
+	if (caps & AC_PINCAP_TRIG_REQ)
+		snd_iprintf(buffer, " Trigger");
+	if (caps & AC_PINCAP_IMP_SENSE)
+		snd_iprintf(buffer, " ImpSense");
 	snd_iprintf(buffer, "\n");
+	if (caps & AC_PINCAP_VREF) {
+		unsigned int vref =
+			(caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+		snd_iprintf(buffer, "    Vref caps:");
+		if (vref & AC_PINCAP_VREF_HIZ)
+			snd_iprintf(buffer, " HIZ");
+		if (vref & AC_PINCAP_VREF_50)
+			snd_iprintf(buffer, " 50");
+		if (vref & AC_PINCAP_VREF_GRD)
+			snd_iprintf(buffer, " GRD");
+		if (vref & AC_PINCAP_VREF_80)
+			snd_iprintf(buffer, " 80");
+		if (vref & AC_PINCAP_VREF_100)
+			snd_iprintf(buffer, " 100");
+		snd_iprintf(buffer, "\n");
+		*supports_vref = 1;
+	} else
+		*supports_vref = 0;
+	if (caps & AC_PINCAP_EAPD) {
+		val = snd_hda_codec_read(codec, nid, 0,
+					 AC_VERB_GET_EAPD_BTLENABLE, 0);
+		snd_iprintf(buffer, "  EAPD 0x%x:", val);
+		if (val & AC_EAPDBTL_BALANCED)
+			snd_iprintf(buffer, " BALANCED");
+		if (val & AC_EAPDBTL_EAPD)
+			snd_iprintf(buffer, " EAPD");
+		if (val & AC_EAPDBTL_LR_SWAP)
+			snd_iprintf(buffer, " R/L");
+		snd_iprintf(buffer, "\n");
+	}
 	caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
 	snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
 		    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
@@ -237,8 +275,233 @@
 	snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
 		    get_jack_connection(caps),
 		    get_jack_color(caps));
+	/* Default association and sequence values refer to default grouping
+	 * of pin complexes and their sequence within the group. This is used
+	 * for priority and resource allocation.
+	 */
+	snd_iprintf(buffer, "    DefAssociation = 0x%x, Sequence = 0x%x\n",
+		    (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT,
+		    caps & AC_DEFCFG_SEQUENCE);
+	if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) &
+	    AC_DEFCFG_MISC_NO_PRESENCE) {
+		/* Miscellaneous bit indicates external hardware does not
+		 * support presence detection even if the pin complex
+		 * indicates it is supported.
+		 */
+		snd_iprintf(buffer, "    Misc = NO_PRESENCE\n");
+	}
+}
+
+static void print_pin_ctls(struct snd_info_buffer *buffer,
+			   struct hda_codec *codec, hda_nid_t nid,
+			   int supports_vref)
+{
+	unsigned int pinctls;
+
+	pinctls = snd_hda_codec_read(codec, nid, 0,
+				     AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+	snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
+	if (pinctls & AC_PINCTL_IN_EN)
+		snd_iprintf(buffer, " IN");
+	if (pinctls & AC_PINCTL_OUT_EN)
+		snd_iprintf(buffer, " OUT");
+	if (pinctls & AC_PINCTL_HP_EN)
+		snd_iprintf(buffer, " HP");
+	if (supports_vref) {
+		int vref = pinctls & AC_PINCTL_VREFEN;
+		switch (vref) {
+		case AC_PINCTL_VREF_HIZ:
+			snd_iprintf(buffer, " VREF_HIZ");
+			break;
+		case AC_PINCTL_VREF_50:
+			snd_iprintf(buffer, " VREF_50");
+			break;
+		case AC_PINCTL_VREF_GRD:
+			snd_iprintf(buffer, " VREF_GRD");
+			break;
+		case AC_PINCTL_VREF_80:
+			snd_iprintf(buffer, " VREF_80");
+			break;
+		case AC_PINCTL_VREF_100:
+			snd_iprintf(buffer, " VREF_100");
+			break;
+		}
+	}
+	snd_iprintf(buffer, "\n");
+}
+
+static void print_vol_knob(struct snd_info_buffer *buffer,
+			   struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int cap = snd_hda_param_read(codec, nid,
+					      AC_PAR_VOL_KNB_CAP);
+	snd_iprintf(buffer, "  Volume-Knob: delta=%d, steps=%d, ",
+		    (cap >> 7) & 1, cap & 0x7f);
+	cap = snd_hda_codec_read(codec, nid, 0,
+				 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+	snd_iprintf(buffer, "direct=%d, val=%d\n",
+		    (cap >> 7) & 1, cap & 0x7f);
+}
+
+static void print_audio_io(struct snd_info_buffer *buffer,
+			   struct hda_codec *codec, hda_nid_t nid,
+			   unsigned int wid_type)
+{
+	int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+	snd_iprintf(buffer,
+		    "  Converter: stream=%d, channel=%d\n",
+		    (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
+		    conv & AC_CONV_CHANNEL);
+
+	if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) {
+		int sdi = snd_hda_codec_read(codec, nid, 0,
+					     AC_VERB_GET_SDI_SELECT, 0);
+		snd_iprintf(buffer, "  SDI-Select: %d\n",
+			    sdi & AC_SDI_SELECT);
+	}
+}
+
+static void print_digital_conv(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
+						AC_VERB_GET_DIGI_CONVERT_1, 0);
+	unsigned int digi2 = snd_hda_codec_read(codec, nid, 0,
+						AC_VERB_GET_DIGI_CONVERT_2, 0);
+	snd_iprintf(buffer, "  Digital:");
+	if (digi1 & AC_DIG1_ENABLE)
+		snd_iprintf(buffer, " Enabled");
+	if (digi1 & AC_DIG1_V)
+		snd_iprintf(buffer, " Validity");
+	if (digi1 & AC_DIG1_VCFG)
+		snd_iprintf(buffer, " ValidityCfg");
+	if (digi1 & AC_DIG1_EMPHASIS)
+		snd_iprintf(buffer, " Preemphasis");
+	if (digi1 & AC_DIG1_COPYRIGHT)
+		snd_iprintf(buffer, " Copyright");
+	if (digi1 & AC_DIG1_NONAUDIO)
+		snd_iprintf(buffer, " Non-Audio");
+	if (digi1 & AC_DIG1_PROFESSIONAL)
+		snd_iprintf(buffer, " Pro");
+	if (digi1 & AC_DIG1_LEVEL)
+		snd_iprintf(buffer, " GenLevel");
+	snd_iprintf(buffer, "\n");
+	snd_iprintf(buffer, "  Digital category: 0x%x\n", digi2 & AC_DIG2_CC);
 }
 
+static const char *get_pwr_state(u32 state)
+{
+	static const char *buf[4] = {
+		"D0", "D1", "D2", "D3"
+	};
+	if (state < 4)
+		return buf[state];
+	return "UNKNOWN";
+}
+
+static void print_power_state(struct snd_info_buffer *buffer,
+			      struct hda_codec *codec, hda_nid_t nid)
+{
+	int pwr = snd_hda_codec_read(codec, nid, 0,
+				     AC_VERB_GET_POWER_STATE, 0);
+	snd_iprintf(buffer, "  Power: setting=%s, actual=%s\n",
+		    get_pwr_state(pwr & AC_PWRST_SETTING),
+		    get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
+				  AC_PWRST_ACTUAL_SHIFT));
+}
+
+static void print_unsol_cap(struct snd_info_buffer *buffer,
+			      struct hda_codec *codec, hda_nid_t nid)
+{
+	int unsol = snd_hda_codec_read(codec, nid, 0,
+				       AC_VERB_GET_UNSOLICITED_RESPONSE, 0);
+	snd_iprintf(buffer,
+		    "  Unsolicited: tag=%02x, enabled=%d\n",
+		    unsol & AC_UNSOL_TAG,
+		    (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
+}
+
+static void print_proc_caps(struct snd_info_buffer *buffer,
+			    struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int proc_caps = snd_hda_param_read(codec, nid,
+						    AC_PAR_PROC_CAP);
+	snd_iprintf(buffer, "  Processing caps: benign=%d, ncoeff=%d\n",
+		    proc_caps & AC_PCAP_BENIGN,
+		    (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT);
+}
+
+static void print_conn_list(struct snd_info_buffer *buffer,
+			    struct hda_codec *codec, hda_nid_t nid,
+			    unsigned int wid_type, hda_nid_t *conn,
+			    int conn_len)
+{
+	int c, curr = -1;
+
+	if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+		curr = snd_hda_codec_read(codec, nid, 0,
+					  AC_VERB_GET_CONNECT_SEL, 0);
+	snd_iprintf(buffer, "  Connection: %d\n", conn_len);
+	if (conn_len > 0) {
+		snd_iprintf(buffer, "    ");
+		for (c = 0; c < conn_len; c++) {
+			snd_iprintf(buffer, " 0x%02x", conn[c]);
+			if (c == curr)
+				snd_iprintf(buffer, "*");
+		}
+		snd_iprintf(buffer, "\n");
+	}
+}
+
+static void print_realtek_coef(struct snd_info_buffer *buffer,
+			       struct hda_codec *codec, hda_nid_t nid)
+{
+	int coeff = snd_hda_codec_read(codec, nid, 0,
+				       AC_VERB_GET_PROC_COEF, 0);
+	snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
+	coeff = snd_hda_codec_read(codec, nid, 0,
+				   AC_VERB_GET_COEF_INDEX, 0);
+	snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
+}
+
+static void print_gpio(struct snd_info_buffer *buffer,
+		       struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int gpio =
+		snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+	unsigned int enable, direction, wake, unsol, sticky, data;
+	int i, max;
+	snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
+		    "unsolicited=%d, wake=%d\n",
+		    gpio & AC_GPIO_IO_COUNT,
+		    (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
+		    (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
+		    (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
+		    (gpio & AC_GPIO_WAKE) ? 1 : 0);
+	max = gpio & AC_GPIO_IO_COUNT;
+	enable = snd_hda_codec_read(codec, nid, 0,
+				    AC_VERB_GET_GPIO_MASK, 0);
+	direction = snd_hda_codec_read(codec, nid, 0,
+				       AC_VERB_GET_GPIO_DIRECTION, 0);
+	wake = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_GPIO_WAKE_MASK, 0);
+	unsol  = snd_hda_codec_read(codec, nid, 0,
+				    AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
+	sticky = snd_hda_codec_read(codec, nid, 0,
+				    AC_VERB_GET_GPIO_STICKY_MASK, 0);
+	data = snd_hda_codec_read(codec, nid, 0,
+				  AC_VERB_GET_GPIO_DATA, 0);
+	for (i = 0; i < max; ++i)
+		snd_iprintf(buffer,
+			    "  IO[%d]: enable=%d, dir=%d, wake=%d, "
+			    "sticky=%d, data=%d\n", i,
+			    (enable & (1<<i)) ? 1 : 0,
+			    (direction & (1<<i)) ? 1 : 0,
+			    (wake & (1<<i)) ? 1 : 0,
+			    (sticky & (1<<i)) ? 1 : 0,
+			    (data & (1<<i)) ? 1 : 0);
+	/* FIXME: add GPO and GPI pin information */
+}
 
 static void print_codec_info(struct snd_info_entry *entry,
 			     struct snd_info_buffer *buffer)
@@ -276,14 +539,17 @@
 		snd_hda_power_down(codec);
 		return;
 	}
+
+	print_gpio(buffer, codec, codec->afg);
+
 	for (i = 0; i < nodes; i++, nid++) {
 		unsigned int wid_caps =
 			snd_hda_param_read(codec, nid,
 					   AC_PAR_AUDIO_WIDGET_CAP);
 		unsigned int wid_type =
 			(wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-		int conn_len = 0; 
 		hda_nid_t conn[HDA_MAX_CONNECTIONS];
+		int conn_len = 0;
 
 		snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
 			    get_wid_type_name(wid_type), wid_caps);
@@ -297,8 +563,18 @@
 			snd_iprintf(buffer, " Amp-In");
 		if (wid_caps & AC_WCAP_OUT_AMP)
 			snd_iprintf(buffer, " Amp-Out");
+		if (wid_caps & AC_WCAP_STRIPE)
+			snd_iprintf(buffer, " Stripe");
+		if (wid_caps & AC_WCAP_LR_SWAP)
+			snd_iprintf(buffer, " R/L");
 		snd_iprintf(buffer, "\n");
 
+		/* volume knob is a special widget that always have connection
+		 * list
+		 */
+		if (wid_type == AC_WID_VOL_KNB)
+			wid_caps |= AC_WCAP_CONN_LIST;
+
 		if (wid_caps & AC_WCAP_CONN_LIST)
 			conn_len = snd_hda_get_connections(codec, nid, conn,
 							   HDA_MAX_CONNECTIONS);
@@ -308,7 +584,8 @@
 			print_amp_caps(buffer, codec, nid, HDA_INPUT);
 			snd_iprintf(buffer, "  Amp-In vals: ");
 			print_amp_vals(buffer, codec, nid, HDA_INPUT,
-				       wid_caps & AC_WCAP_STEREO, conn_len);
+				       wid_caps & AC_WCAP_STEREO,
+				       wid_type == AC_WID_PIN ? 1 : conn_len);
 		}
 		if (wid_caps & AC_WCAP_OUT_AMP) {
 			snd_iprintf(buffer, "  Amp-Out caps: ");
@@ -318,48 +595,49 @@
 				       wid_caps & AC_WCAP_STEREO, 1);
 		}
 
-		if (wid_type == AC_WID_PIN) {
-			unsigned int pinctls;
-			print_pin_caps(buffer, codec, nid);
-			pinctls = snd_hda_codec_read(codec, nid, 0,
-					     AC_VERB_GET_PIN_WIDGET_CONTROL,
-						     0);
-			snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
-			if (pinctls & AC_PINCTL_IN_EN)
-				snd_iprintf(buffer, " IN");
-			if (pinctls & AC_PINCTL_OUT_EN)
-				snd_iprintf(buffer, " OUT");
-			if (pinctls & AC_PINCTL_HP_EN)
-				snd_iprintf(buffer, " HP");
-			snd_iprintf(buffer, "\n");
+		switch (wid_type) {
+		case AC_WID_PIN: {
+			int supports_vref;
+			print_pin_caps(buffer, codec, nid, &supports_vref);
+			print_pin_ctls(buffer, codec, nid, supports_vref);
+			break;
 		}
-
-		if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
-		    (wid_caps & AC_WCAP_FORMAT_OVRD)) {
-			snd_iprintf(buffer, "  PCM:\n");
-			print_pcm_caps(buffer, codec, nid);
+		case AC_WID_VOL_KNB:
+			print_vol_knob(buffer, codec, nid);
+			break;
+		case AC_WID_AUD_OUT:
+		case AC_WID_AUD_IN:
+			print_audio_io(buffer, codec, nid, wid_type);
+			if (wid_caps & AC_WCAP_DIGITAL)
+				print_digital_conv(buffer, codec, nid);
+			if (wid_caps & AC_WCAP_FORMAT_OVRD) {
+				snd_iprintf(buffer, "  PCM:\n");
+				print_pcm_caps(buffer, codec, nid);
+			}
+			break;
 		}
 
+		if (wid_caps & AC_WCAP_UNSOL_CAP)
+			print_unsol_cap(buffer, codec, nid);
+
 		if (wid_caps & AC_WCAP_POWER)
-			snd_iprintf(buffer, "  Power: 0x%x\n",
-				    snd_hda_codec_read(codec, nid, 0,
-						       AC_VERB_GET_POWER_STATE,
-						       0));
-
-		if (wid_caps & AC_WCAP_CONN_LIST) {
-			int c, curr = -1;
-			if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
-				curr = snd_hda_codec_read(codec, nid, 0,
-					AC_VERB_GET_CONNECT_SEL, 0);
-			snd_iprintf(buffer, "  Connection: %d\n", conn_len);
-			snd_iprintf(buffer, "    ");
-			for (c = 0; c < conn_len; c++) {
-				snd_iprintf(buffer, " 0x%02x", conn[c]);
-				if (c == curr)
-					snd_iprintf(buffer, "*");
-			}
-			snd_iprintf(buffer, "\n");
-		}
+			print_power_state(buffer, codec, nid);
+
+		if (wid_caps & AC_WCAP_DELAY)
+			snd_iprintf(buffer, "  Delay: %d samples\n",
+				    (wid_caps & AC_WCAP_DELAY) >>
+				    AC_WCAP_DELAY_SHIFT);
+
+		if (wid_caps & AC_WCAP_CONN_LIST)
+			print_conn_list(buffer, codec, nid, wid_type,
+					conn, conn_len);
+
+		if (wid_caps & AC_WCAP_PROC_WID)
+			print_proc_caps(buffer, codec, nid);
+
+		/* NID 0x20 == Realtek Define Registers */
+		if (codec->vendor_id == 0x10ec && nid == 0x20)
+			print_realtek_coef(buffer, codec, nid);
 	}
 	snd_hda_power_down(codec);
 }
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/Makefile linux-2.6.24.7-rt20-atom/sound/pci/hda/Makefile
--- linux-2.6.24.7-rt20/sound/pci/hda/Makefile	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/Makefile	2008-09-28 23:33:39.000000000 +0200
@@ -2,7 +2,7 @@
 # since snd-hda-intel is the only driver using hda-codec,
 # merge it into a single module although it was originally
 # designed to be individual modules
-snd-hda-intel-y += hda_codec.o
+snd-hda-intel-y += hda_codec.o vmaster.o
 snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_analog.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_analog.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_analog.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_analog.c	2008-09-28 23:33:40.000000000 +0200
@@ -19,7 +19,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -79,6 +78,11 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 #endif
+	/* for virtual master */
+	hda_nid_t vmaster_nid;
+	u32 vmaster_tlv[4];
+	const char **slave_vols;
+	const char **slave_sws;
 };
 
 /*
@@ -126,6 +130,32 @@
 	return 0;
 }
 
+static const char *ad_slave_vols[] = {
+	"Front Playback Volume",
+	"Surround Playback Volume",
+	"Center Playback Volume",
+	"LFE Playback Volume",
+	"Side Playback Volume",
+	"Headphone Playback Volume",
+	"Mono Playback Volume",
+	"Speaker Playback Volume",
+	"IEC958 Playback Volume",
+	NULL
+};
+
+static const char *ad_slave_sws[] = {
+	"Front Playback Switch",
+	"Surround Playback Switch",
+	"Center Playback Switch",
+	"LFE Playback Switch",
+	"Side Playback Switch",
+	"Headphone Playback Switch",
+	"Mono Playback Switch",
+	"Speaker Playback Switch",
+	"IEC958 Playback Switch",
+	NULL
+};
+
 static int ad198x_build_controls(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec = codec->spec;
@@ -141,12 +171,38 @@
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	} 
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
 		if (err < 0)
 			return err;
 	}
+
+	/* if we have no master control, let's create it */
+	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
+					HDA_OUTPUT, spec->vmaster_tlv);
+		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+					  spec->vmaster_tlv,
+					  (spec->slave_vols ?
+					   spec->slave_vols : ad_slave_vols));
+		if (err < 0)
+			return err;
+	}
+	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+					  NULL,
+					  (spec->slave_sws ?
+					   spec->slave_sws : ad_slave_sws));
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -166,7 +222,8 @@
 				    struct snd_pcm_substream *substream)
 {
 	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -308,6 +365,7 @@
 		info++;
 		codec->num_pcms++;
 		info->name = "AD198x Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
 		if (spec->dig_in_nid) {
@@ -370,7 +428,7 @@
 	int invert = (kcontrol->private_value >> 8) & 1;
 	hda_nid_t nid = kcontrol->private_value & 0xff;
 	unsigned int eapd;
-	eapd = ucontrol->value.integer.value[0];
+	eapd = !!ucontrol->value.integer.value[0];
 	if (invert)
 		eapd = !eapd;
 	if (eapd == spec->cur_eapd)
@@ -560,13 +618,19 @@
 	},
 };
 
+static struct hda_input_mux ad1986a_automic_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Mix", 0x5 },
+	},
+};
+
 static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
 	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
 	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
@@ -590,6 +654,33 @@
 	{ } /* end */
 };
 
+/* re-connect the mic boost input according to the jack sensing */
+static void ad1986a_automic(struct hda_codec *codec)
+{
+	unsigned int present;
+	present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0);
+	/* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
+	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
+			    (present & AC_PINSENSE_PRESENCE) ? 0 : 2);
+}
+
+#define AD1986A_MIC_EVENT		0x36
+
+static void ad1986a_automic_unsol_event(struct hda_codec *codec,
+					    unsigned int res)
+{
+	if ((res >> 26) != AD1986A_MIC_EVENT)
+		return;
+	ad1986a_automic(codec);
+}
+
+static int ad1986a_automic_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1986a_automic(codec);
+	return 0;
+}
+
 /* laptop-automute - 2ch only */
 
 static void ad1986a_update_hp(struct hda_codec *codec)
@@ -793,6 +884,15 @@
 	{}
 };
 
+static struct hda_verb ad1986a_automic_verbs[] = {
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
+	{0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
+	{}
+};
+
 /* Ultra initialization */
 static struct hda_verb ad1986a_ultra_init[] = {
 	/* eapd initialization */
@@ -833,27 +933,29 @@
 
 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
+	SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
 	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
+	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
 	SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
 	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
@@ -872,6 +974,13 @@
 };
 #endif
 
+static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int conf = snd_hda_codec_read(codec, nid, 0,
+					       AC_VERB_GET_CONFIG_DEFAULT, 0);
+	return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
+}
+
 static int patch_ad1986a(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
@@ -898,6 +1007,7 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = ad1986a_loopbacks;
 #endif
+	spec->vmaster_nid = 0x1b;
 
 	codec->patch_ops = ad198x_patch_ops;
 
@@ -925,13 +1035,17 @@
 		break;
 	case AD1986A_LAPTOP_EAPD:
 		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
-		spec->num_init_verbs = 2;
+		spec->num_init_verbs = 3;
 		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+		spec->init_verbs[2] = ad1986a_automic_verbs;
 		spec->multiout.max_channels = 2;
 		spec->multiout.num_dacs = 1;
 		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
+		if (!is_jack_available(codec, 0x25))
+			spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1986a_automic_capture_source;
+		codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
+		codec->patch_ops.init = ad1986a_automic_init;
 		break;
 	case AD1986A_LAPTOP_AUTOMUTE:
 		spec->mixers[0] = ad1986a_laptop_automute_mixers;
@@ -941,7 +1055,8 @@
 		spec->multiout.max_channels = 2;
 		spec->multiout.num_dacs = 1;
 		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		spec->multiout.dig_out_nid = 0;
+		if (!is_jack_available(codec, 0x25))
+			spec->multiout.dig_out_nid = 0;
 		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
 		codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
 		codec->patch_ops.init = ad1986a_hp_init;
@@ -1020,6 +1135,8 @@
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ad198x_spec *spec = codec->spec;
 
+	if (ucontrol->value.enumerated.item[0] > 1)
+		return -EINVAL;
 	if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
 		spec->spdif_route = ucontrol->value.enumerated.item[0];
 		snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
@@ -1138,6 +1255,7 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = ad1983_loopbacks;
 #endif
+	spec->vmaster_nid = 0x05;
 
 	codec->patch_ops = ad198x_patch_ops;
 
@@ -1299,7 +1417,10 @@
 
 	if (! ad198x_eapd_put(kcontrol, ucontrol))
 		return 0;
-
+	/* change speaker pin appropriately */
+	snd_hda_codec_write(codec, 0x05, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    spec->cur_eapd ? PIN_OUT : 0);
 	/* toggle HP mute appropriately */
 	snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
 				 HDA_AMP_MUTE,
@@ -1496,14 +1617,14 @@
 };
 
 static struct snd_pci_quirk ad1981_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
 	/* All HP models */
 	SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
-	/* HP nx6320 (reversed SSID, H/W bug) */
-	SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
+	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
 	/* Lenovo Thinkpad T60/X60/Z6xx */
 	SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
-	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
-	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
+	/* HP nx6320 (reversed SSID, H/W bug) */
+	SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
 	{}
 };
 
@@ -1534,6 +1655,7 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = ad1981_loopbacks;
 #endif
+	spec->vmaster_nid = 0x05;
 
 	codec->patch_ops = ad198x_patch_ops;
 
@@ -1711,9 +1833,9 @@
 static struct hda_input_mux ad1988_6stack_capture_source = {
 	.num_items = 5,
 	.items = {
-		{ "Front Mic", 0x0 },
-		{ "Line", 0x1 },
-		{ "Mic", 0x4 },
+		{ "Front Mic", 0x1 },	/* port-B */
+		{ "Line", 0x2 },	/* port-C */
+		{ "Mic", 0x4 },		/* port-E */
 		{ "CD", 0x5 },
 		{ "Mix", 0x9 },
 	},
@@ -1722,7 +1844,7 @@
 static struct hda_input_mux ad1988_laptop_capture_source = {
 	.num_items = 3,
 	.items = {
-		{ "Mic/Line", 0x0 },
+		{ "Mic/Line", 0x1 },	/* port-B */
 		{ "CD", 0x5 },
 		{ "Mix", 0x9 },
 	},
@@ -1908,7 +2030,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -1965,6 +2086,8 @@
 	int change;
 
 	val = ucontrol->value.enumerated.item[0];
+	if (val > 3)
+		return -EINVAL;
 	if (!val) {
 		sel = snd_hda_codec_read(codec, 0x1d, 0,
 					 AC_VERB_GET_AMP_GAIN_MUTE,
@@ -2079,6 +2202,8 @@
 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
 	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 	{0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* Analog CD Input */
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
 	{ }
 };
@@ -2720,8 +2845,8 @@
 };
 
 static struct snd_pci_quirk ad1988_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
+	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
 	{}
 };
 
@@ -2843,6 +2968,7 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = ad1988_loopbacks;
 #endif
+	spec->vmaster_nid = 0x04;
 
 	return 0;
 }
@@ -2919,7 +3045,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -3009,6 +3134,20 @@
 };
 #endif
 
+static const char *ad1884_slave_vols[] = {
+	"PCM Playback Volume",
+	"Mic Playback Volume",
+	"Mono Playback Volume",
+	"Front Mic Playback Volume",
+	"Mic Playback Volume",
+	"CD Playback Volume",
+	"Internal Mic Playback Volume",
+	"Docking Mic Playback Volume"
+	"Beep Playback Volume",
+	"IEC958 Playback Volume",
+	NULL
+};
+
 static int patch_ad1884(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
@@ -3036,6 +3175,9 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = ad1884_loopbacks;
 #endif
+	spec->vmaster_nid = 0x04;
+	/* we need to cover all playback volumes */
+	spec->slave_vols = ad1884_slave_vols;
 
 	codec->patch_ops = ad198x_patch_ops;
 
@@ -3046,14 +3188,29 @@
  * Lenovo Thinkpad T61/X61
  */
 static struct hda_input_mux ad1984_thinkpad_capture_source = {
-	.num_items = 3,
+	.num_items = 4,
 	.items = {
 		{ "Mic", 0x0 },
 		{ "Internal Mic", 0x1 },
 		{ "Mix", 0x3 },
+		{ "Docking-Station", 0x4 },
+	},
+};
+
+
+/*
+ * Dell Precision T3400
+ */
+static struct hda_input_mux ad1984_dell_desktop_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Front Mic", 0x0 },
+		{ "Line-In", 0x1 },
+		{ "Mix", 0x3 },
 	},
 };
 
+
 static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
 	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
@@ -3078,7 +3235,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -3087,6 +3243,16 @@
 		.get = ad198x_mux_enum_get,
 		.put = ad198x_mux_enum_put,
 	},
+	/* SPDIF controls */
+	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		/* identical with ad1983 */
+		.info = ad1983_spdif_route_info,
+		.get = ad1983_spdif_route_get,
+		.put = ad1983_spdif_route_put,
+	},
 	{ } /* end */
 };
 
@@ -3104,6 +3270,44 @@
 	{ } /* end */
 };
 
+/*
+ * Dell Precision T3400
+ */
+static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
+	/*
+	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
+	*/
+	HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
 /* Digial MIC ADC NID 0x05 + 0x06 */
 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
 				   struct hda_codec *codec,
@@ -3157,17 +3361,20 @@
 enum {
 	AD1984_BASIC,
 	AD1984_THINKPAD,
+	AD1984_DELL_DESKTOP,
 	AD1984_MODELS
 };
 
 static const char *ad1984_models[AD1984_MODELS] = {
 	[AD1984_BASIC]		= "basic",
 	[AD1984_THINKPAD]	= "thinkpad",
+	[AD1984_DELL_DESKTOP]	= "dell_desktop",
 };
 
 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
 	/* Lenovo Thinkpad T61/X61 */
 	SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+	SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
 	{}
 };
 
@@ -3189,17 +3396,391 @@
 		codec->patch_ops.build_pcms = ad1984_build_pcms;
 		break;
 	case AD1984_THINKPAD:
-		spec->multiout.dig_out_nid = 0;
+		spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
 		spec->input_mux = &ad1984_thinkpad_capture_source;
 		spec->mixers[0] = ad1984_thinkpad_mixers;
 		spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
 		break;
+	case AD1984_DELL_DESKTOP:
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1984_dell_desktop_capture_source;
+		spec->mixers[0] = ad1984_dell_desktop_mixers;
+		break;
 	}
 	return 0;
 }
 
 
 /*
+ * AD1883 / AD1884A / AD1984A / AD1984B
+ *
+ * port-B (0x14) - front mic-in
+ * port-E (0x1c) - rear mic-in
+ * port-F (0x16) - CD / ext out
+ * port-C (0x15) - rear line-in
+ * port-D (0x12) - rear line-out
+ * port-A (0x11) - front hp-out
+ *
+ * AD1984A = AD1884A + digital-mic
+ * AD1883 = equivalent with AD1984A
+ * AD1984B = AD1984A + extra SPDIF-out
+ *
+ * FIXME:
+ * We share the single DAC for both HP and line-outs (see AD1884/1984).
+ */
+
+static hda_nid_t ad1884a_dac_nids[1] = {
+	0x03,
+};
+
+#define ad1884a_adc_nids	ad1884_adc_nids
+#define ad1884a_capsrc_nids	ad1884_capsrc_nids
+
+#define AD1884A_SPDIF_OUT	0x02
+
+static struct hda_input_mux ad1884a_capture_source = {
+	.num_items = 5,
+	.items = {
+		{ "Front Mic", 0x0 },
+		{ "Mic", 0x4 },
+		{ "Line", 0x1 },
+		{ "CD", 0x2 },
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884a_base_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	/* SPDIF controls */
+	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+		/* identical with ad1983 */
+		.info = ad1983_spdif_route_info,
+		.get = ad1983_spdif_route_get,
+		.put = ad1983_spdif_route_put,
+	},
+	{ } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1884a_init_verbs[] = {
+	/* DACs; unmute as default */
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
+	/* Port-A (HP) mixer - route only from analog mixer */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-A pin */
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-D (Line-out) mixer - route only from analog mixer */
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-D pin */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Mono-out mixer - route only from analog mixer */
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Mono-out pin */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-B (front mic) pin */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-C (rear line-in) pin */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Port-E (rear mic) pin */
+	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
+	/* Port-F (CD) pin */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Analog mixer; mute as default */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+	/* Analog Mix output amp */
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* capture sources */
+	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* SPDIF output amp */
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+	{ } /* end */
+};
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list ad1884a_loopbacks[] = {
+	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
+	{ 0x20, HDA_INPUT, 1 }, /* Mic */
+	{ 0x20, HDA_INPUT, 2 }, /* CD */
+	{ 0x20, HDA_INPUT, 4 }, /* Docking */
+	{ } /* end */
+};
+#endif
+
+/*
+ * Laptop model
+ *
+ * Port A: Headphone jack
+ * Port B: MIC jack
+ * Port C: Internal MIC
+ * Port D: Dock Line Out (if enabled)
+ * Port E: Dock Line In (if enabled)
+ * Port F: Internal speakers
+ */
+
+static struct hda_input_mux ad1884a_laptop_capture_source = {
+	.num_items = 4,
+	.items = {
+		{ "Mic", 0x0 },		/* port-B */
+		{ "Internal Mic", 0x1 }, /* port-C */
+		{ "Dock Mic", 0x4 },	/* port-E */
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_input_mux ad1884a_mobile_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x1 }, /* port-C */
+		{ "Mix", 0x3 },
+	},
+};
+
+static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/* mute internal speaker if HP is plugged */
+static void ad1884a_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x11, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
+			    present ? 0x00 : 0x02);
+}
+
+#define AD1884A_HP_EVENT		0x37
+
+/* unsolicited event for HP jack sensing */
+static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	if ((res >> 26) != AD1884A_HP_EVENT)
+		return;
+	ad1884a_hp_automute(codec);
+}
+
+/* initialize jack-sensing, too */
+static int ad1884a_hp_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1884a_hp_automute(codec);
+	return 0;
+}
+
+/* additional verbs for laptop model */
+static struct hda_verb ad1884a_laptop_verbs[] = {
+	/* Port-A (HP) pin - always unmuted */
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Port-F (int speaker) mixer - route only from analog mixer */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* Port-F pin */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* analog mix */
+	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* unsolicited event for pin-sense */
+	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
+	{ } /* end */
+};
+
+/*
+ */
+
+enum {
+	AD1884A_DESKTOP,
+	AD1884A_LAPTOP,
+	AD1884A_MOBILE,
+	AD1884A_MODELS
+};
+
+static const char *ad1884a_models[AD1884A_MODELS] = {
+	[AD1884A_DESKTOP]	= "desktop",
+	[AD1884A_LAPTOP]	= "laptop",
+	[AD1884A_MOBILE]	= "mobile",
+};
+
+static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
+	{}
+};
+
+static int patch_ad1884a(struct hda_codec *codec)
+{
+	struct ad198x_spec *spec;
+	int board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
+	spec->multiout.dac_nids = ad1884a_dac_nids;
+	spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
+	spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
+	spec->adc_nids = ad1884a_adc_nids;
+	spec->capsrc_nids = ad1884a_capsrc_nids;
+	spec->input_mux = &ad1884a_capture_source;
+	spec->num_mixers = 1;
+	spec->mixers[0] = ad1884a_base_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = ad1884a_init_verbs;
+	spec->spdif_route = 0;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	spec->loopback.amplist = ad1884a_loopbacks;
+#endif
+	codec->patch_ops = ad198x_patch_ops;
+
+	/* override some parameters */
+	board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
+						  ad1884a_models,
+						  ad1884a_cfg_tbl);
+	switch (board_config) {
+	case AD1884A_LAPTOP:
+		spec->mixers[0] = ad1884a_laptop_mixers;
+		spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1884a_laptop_capture_source;
+		codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
+		codec->patch_ops.init = ad1884a_hp_init;
+		break;
+	case AD1884A_MOBILE:
+		spec->mixers[0] = ad1884a_mobile_mixers;
+		spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1884a_mobile_capture_source;
+		codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
+		codec->patch_ops.init = ad1884a_hp_init;
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
  * AD1882
  *
  * port-A - front hp-out
@@ -3267,7 +3848,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -3468,6 +4048,7 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = ad1882_loopbacks;
 #endif
+	spec->vmaster_nid = 0x04;
 
 	codec->patch_ops = ad198x_patch_ops;
 
@@ -3498,8 +4079,12 @@
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_analog[] = {
+	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
+	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
 	{ .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
+	{ .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
+	{ .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
 	{ .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
 	{ .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
 	{ .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_atihdmi.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_atihdmi.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_atihdmi.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_atihdmi.c	2008-09-28 23:33:40.000000000 +0200
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -59,6 +58,10 @@
 static int atihdmi_init(struct hda_codec *codec)
 {
 	snd_hda_sequence_write(codec, atihdmi_basic_init);
+	/* SI codec requires to unmute the pin */
+	if (get_wcaps(codec, 0x03) & AC_WCAP_OUT_AMP)
+		snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+				    AMP_OUT_UNMUTE);
 	return 0;
 }
 
@@ -113,6 +116,7 @@
 	codec->pcm_info = info;
 
 	info->name = "ATI HDMI";
+	info->pcm_type = HDA_PCM_TYPE_HDMI;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
 
 	return 0;
@@ -158,6 +162,8 @@
 	{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
 	{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
-	{ .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
+	{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi },
+	{ .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
 	{} /* terminator */
 };
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_cmedia.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_cmedia.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_cmedia.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_cmedia.c	2008-09-28 23:33:40.000000000 +0200
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -186,7 +185,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -331,6 +329,11 @@
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -434,7 +437,8 @@
 				     struct snd_pcm_substream *substream)
 {
 	struct cmi_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -573,6 +577,7 @@
 		codec->num_pcms++;
 		info++;
 		info->name = "CMI9880 Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_conexant.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_conexant.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_conexant.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_conexant.c	2008-09-28 23:33:40.000000000 +0200
@@ -20,7 +20,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -65,6 +64,11 @@
 	hda_nid_t *adc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
+	unsigned int cur_adc_idx;
+	hda_nid_t cur_adc;
+	unsigned int cur_adc_stream_tag;
+	unsigned int cur_adc_format;
+
 	/* capture source */
 	const struct hda_input_mux *input_mux;
 	hda_nid_t *capsrc_nids;
@@ -94,7 +98,8 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct conexant_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -218,6 +223,41 @@
 	/* NID is set in alc_build_pcms */
 };
 
+static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      unsigned int stream_tag,
+				      unsigned int format,
+				      struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
+	spec->cur_adc_stream_tag = stream_tag;
+	spec->cur_adc_format = format;
+	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+	return 0;
+}
+
+static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+				      struct hda_codec *codec,
+				      struct snd_pcm_substream *substream)
+{
+	struct conexant_spec *spec = codec->spec;
+	snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0);
+	spec->cur_adc = 0;
+	return 0;
+}
+
+static struct hda_pcm_stream cx5051_pcm_analog_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0, /* fill later */
+	.ops = {
+		.prepare = cx5051_capture_pcm_prepare,
+		.cleanup = cx5051_capture_pcm_cleanup
+	},
+};
+
 static int conexant_build_pcms(struct hda_codec *codec)
 {
 	struct conexant_spec *spec = codec->spec;
@@ -232,7 +272,12 @@
 		spec->multiout.max_channels;
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
 		spec->multiout.dac_nids[0];
-	info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
+	if (codec->vendor_id == 0x14f15051)
+		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+			cx5051_pcm_analog_capture;
+	else
+		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+			conexant_pcm_analog_capture;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 
@@ -240,6 +285,7 @@
 		info++;
 		codec->num_pcms++;
 		info->name = "Conexant Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
 			conexant_pcm_digital_playback;
 		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
@@ -327,6 +373,11 @@
 						    spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	} 
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
@@ -373,7 +424,7 @@
 	hda_nid_t nid = kcontrol->private_value & 0xff;
 	unsigned int eapd;
 
-	eapd = ucontrol->value.integer.value[0];
+	eapd = !!ucontrol->value.integer.value[0];
 	if (invert)
 		eapd = !eapd;
 	if (eapd == spec->cur_eapd)
@@ -444,7 +495,7 @@
 static hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
 static hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
 static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
-#define CXT5045_SPDIF_OUT	0x13
+#define CXT5045_SPDIF_OUT	0x18
 
 static struct hda_channel_mode cxt5045_modes[1] = {
 	{ 2, NULL },
@@ -454,7 +505,16 @@
 	.num_items = 2,
 	.items = {
 		{ "IntMic", 0x1 },
-		{ "LineIn", 0x2 },
+		{ "ExtMic", 0x2 },
+	}
+};
+
+static struct hda_input_mux cxt5045_capture_source_benq = {
+	.num_items = 3,
+	.items = {
+		{ "IntMic", 0x1 },
+		{ "ExtMic", 0x2 },
+		{ "LineIn", 0x3 },
 	}
 };
 
@@ -577,6 +637,15 @@
 	{}
 };
 
+static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
+	HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT),
+
+	{}
+};
+
 static struct hda_verb cxt5045_init_verbs[] = {
 	/* Line in, Mic */
 	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -596,12 +665,38 @@
 	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
 	 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
 	/* SPDIF route: PCM */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 	{ 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 },
 	/* EAPD */
 	{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ 
 	{ } /* end */
 };
 
+static struct hda_verb cxt5045_benq_init_verbs[] = {
+	/* Int Mic, Mic */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
+	/* Line In,HP, Amp  */
+	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x10, AC_VERB_SET_CONNECT_SEL, 0x1},
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x1},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	/* Record selector: Int mic */
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x1},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
+	 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+	/* SPDIF route: PCM */
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* EAPD */
+	{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+	{ } /* end */
+};
 
 static struct hda_verb cxt5045_hp_sense_init_verbs[] = {
 	/* pin sensing on HP jack */
@@ -695,7 +790,8 @@
 	 * PCM format, copyright asserted, no pre-emphasis and no validity
 	 * control.
 	 */
-	{0x13, AC_VERB_SET_DIGI_CONVERT_1, 0},
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
 	/* Start with output sum widgets muted and their output gains at min */
 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -740,8 +836,10 @@
 
 
 enum {
-	CXT5045_LAPTOP,	 /* Laptops w/ EAPD support */
-	CXT5045_FUJITSU, /* Laptops w/ EAPD support */ 
+	CXT5045_LAPTOP_HPSENSE,
+	CXT5045_LAPTOP_MICSENSE,
+	CXT5045_LAPTOP_HPMICSENSE,
+	CXT5045_BENQ,
 #ifdef CONFIG_SND_DEBUG
 	CXT5045_TEST,
 #endif
@@ -749,23 +847,35 @@
 };
 
 static const char *cxt5045_models[CXT5045_MODELS] = {
-	[CXT5045_LAPTOP]	= "laptop",
-	[CXT5045_FUJITSU]	= "fujitsu",
+	[CXT5045_LAPTOP_HPSENSE]	= "laptop-hpsense",
+	[CXT5045_LAPTOP_MICSENSE]	= "laptop-micsense",
+	[CXT5045_LAPTOP_HPMICSENSE]	= "laptop-hpmicsense",
+	[CXT5045_BENQ]			= "benq",
 #ifdef CONFIG_SND_DEBUG
 	[CXT5045_TEST]		= "test",
 #endif
 };
 
 static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU),
-	SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP),
-	SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP),
+	SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
+	SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
+	SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
+	SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE),
+	SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
+	SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
+	SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
+	SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
+	SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
+	SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE),
 	{}
 };
 
@@ -803,7 +913,7 @@
 						  cxt5045_models,
 						  cxt5045_cfg_tbl);
 	switch (board_config) {
-	case CXT5045_LAPTOP:
+	case CXT5045_LAPTOP_HPSENSE:
 		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
 		spec->input_mux = &cxt5045_capture_source;
 		spec->num_init_verbs = 2;
@@ -811,20 +921,53 @@
 		spec->mixers[0] = cxt5045_mixers;
 		codec->patch_ops.init = cxt5045_init;
 		break;
-	case CXT5045_FUJITSU:
+	case CXT5045_LAPTOP_MICSENSE:
 		spec->input_mux = &cxt5045_capture_source;
 		spec->num_init_verbs = 2;
 		spec->init_verbs[1] = cxt5045_mic_sense_init_verbs;
 		spec->mixers[0] = cxt5045_mixers;
 		codec->patch_ops.init = cxt5045_init;
 		break;
+	default:
+	case CXT5045_LAPTOP_HPMICSENSE:
+		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+		spec->input_mux = &cxt5045_capture_source;
+		spec->num_init_verbs = 3;
+		spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
+		spec->init_verbs[2] = cxt5045_mic_sense_init_verbs;
+		spec->mixers[0] = cxt5045_mixers;
+		codec->patch_ops.init = cxt5045_init;
+		break;
+	case CXT5045_BENQ:
+		codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+		spec->input_mux = &cxt5045_capture_source_benq;
+		spec->num_init_verbs = 1;
+		spec->init_verbs[0] = cxt5045_benq_init_verbs;
+		spec->mixers[0] = cxt5045_mixers;
+		spec->mixers[1] = cxt5045_benq_mixers;
+		spec->num_mixers = 2;
+		codec->patch_ops.init = cxt5045_init;
+		break;
 #ifdef CONFIG_SND_DEBUG
 	case CXT5045_TEST:
 		spec->input_mux = &cxt5045_test_capture_source;
 		spec->mixers[0] = cxt5045_test_mixer;
 		spec->init_verbs[0] = cxt5045_test_init_verbs;
+		break;
+		
 #endif	
 	}
+
+	/*
+	 * Fix max PCM level to 0 dB
+	 * (originall it has 0x2b steps with 0dB offset 0x14)
+	 */
+	snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+				  (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+				  (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+				  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+				  (1 << AC_AMPCAP_MUTE_SHIFT));
+
 	return 0;
 }
 
@@ -933,13 +1076,13 @@
 static void cxt5047_hp_automic(struct hda_codec *codec)
 {
 	static struct hda_verb mic_jack_on[] = {
-		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{}
 	};
 	static struct hda_verb mic_jack_off[] = {
-		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+		{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+		{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 		{}
 	};
 	unsigned int present;
@@ -956,8 +1099,7 @@
 static void cxt5047_hp_unsol_event(struct hda_codec *codec,
 				  unsigned int res)
 {
-	res >>= 26;
-	switch (res) {
+	switch (res >> 26) {
 	case CONEXANT_HP_EVENT:
 		cxt5047_hp_automute(codec);
 		break;
@@ -1095,6 +1237,11 @@
 static struct hda_verb cxt5047_hp_init_verbs[] = {
 	/* pin sensing on HP jack */
 	{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
+	/* 0x13 is actually shared by both HP and speaker;
+	 * setting the connection to 0 (=0x19) makes the master volume control
+	 * working mysteriouslly...
+	 */
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
 	/* Record selector: Ext Mic */
 	{0x12, AC_VERB_SET_CONNECT_SEL,0x03},
 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -1166,6 +1313,17 @@
 		.get = conexant_mux_enum_get,
 		.put = conexant_mux_enum_put,
 	},
+	HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT),
+	HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT),
+
 	{ } /* end */
 };
 
@@ -1255,9 +1413,9 @@
 
 static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
+	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
 	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
 	SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
 	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
 	{}
 };
@@ -1324,10 +1482,260 @@
 	return 0;
 }
 
+/* Conexant 5051 specific */
+static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
+#define CXT5051_SPDIF_OUT	0x1C
+#define CXT5051_PORTB_EVENT	0x38
+#define CXT5051_PORTC_EVENT	0x39
+
+static struct hda_channel_mode cxt5051_modes[1] = {
+	{ 2, NULL },
+};
+
+static void cxt5051_update_speaker(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	unsigned int pinctl;
+	pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
+	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    pinctl);
+}
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (!cxt_eapd_put(kcontrol, ucontrol))
+		return 0;
+	cxt5051_update_speaker(codec);
+	return 1;
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5051_portb_automic(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x17, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) &
+		AC_PINSENSE_PRESENCE;
+	snd_hda_codec_write(codec, 0x14, 0,
+			    AC_VERB_SET_CONNECT_SEL,
+			    present ? 0x01 : 0x00);
+}
+
+/* switch the current ADC according to the jack state */
+static void cxt5051_portc_automic(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+	unsigned int present;
+	hda_nid_t new_adc;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) &
+		AC_PINSENSE_PRESENCE;
+	if (present)
+		spec->cur_adc_idx = 1;
+	else
+		spec->cur_adc_idx = 0;
+	new_adc = spec->adc_nids[spec->cur_adc_idx];
+	if (spec->cur_adc && spec->cur_adc != new_adc) {
+		/* stream is running, let's swap the current ADC */
+		snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0);
+		spec->cur_adc = new_adc;
+		snd_hda_codec_setup_stream(codec, new_adc,
+					   spec->cur_adc_stream_tag, 0,
+					   spec->cur_adc_format);
+	}
+}
+
+/* mute internal speaker if HP is plugged */
+static void cxt5051_hp_automute(struct hda_codec *codec)
+{
+	struct conexant_spec *spec = codec->spec;
+
+	spec->hp_present = snd_hda_codec_read(codec, 0x16, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) &
+		AC_PINSENSE_PRESENCE;
+	cxt5051_update_speaker(codec);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5051_hp_unsol_event(struct hda_codec *codec,
+				   unsigned int res)
+{
+	switch (res >> 26) {
+	case CONEXANT_HP_EVENT:
+		cxt5051_hp_automute(codec);
+		break;
+	case CXT5051_PORTB_EVENT:
+		cxt5051_portb_automic(codec);
+		break;
+	case CXT5051_PORTC_EVENT:
+		cxt5051_portc_automic(codec);
+		break;
+	}
+}
+
+static struct snd_kcontrol_new cxt5051_mixers[] = {
+	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = cxt_eapd_info,
+		.get = cxt_eapd_get,
+		.put = cxt5051_hp_master_sw_put,
+		.private_value = 0x1a,
+	},
+
+	{}
+};
+
+static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
+	HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = cxt_eapd_info,
+		.get = cxt_eapd_get,
+		.put = cxt5051_hp_master_sw_put,
+		.private_value = 0x1a,
+	},
+
+	{}
+};
+
+static struct hda_verb cxt5051_init_verbs[] = {
+	/* Line in, Mic */
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+	/* SPK  */
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* HP, Amp  */
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* DAC1 */	
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Record selector: Int mic */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
+	/* SPDIF route: PCM */
+	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* EAPD */
+	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 
+	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
+	{ } /* end */
+};
+
+/* initialize jack-sensing, too */
+static int cxt5051_init(struct hda_codec *codec)
+{
+	conexant_init(codec);
+	if (codec->patch_ops.unsol_event) {
+		cxt5051_hp_automute(codec);
+		cxt5051_portb_automic(codec);
+		cxt5051_portc_automic(codec);
+	}
+	return 0;
+}
+
+
+enum {
+	CXT5051_LAPTOP,	 /* Laptops w/ EAPD support */
+	CXT5051_HP,	/* no docking */
+	CXT5051_MODELS
+};
+
+static const char *cxt5051_models[CXT5051_MODELS] = {
+	[CXT5051_LAPTOP]	= "laptop",
+	[CXT5051_HP]		= "hp",
+};
+
+static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+		      CXT5051_LAPTOP),
+	SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
+	{}
+};
+
+static int patch_cxt5051(struct hda_codec *codec)
+{
+	struct conexant_spec *spec;
+	int board_config;
+
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (!spec)
+		return -ENOMEM;
+	mutex_init(&spec->amp_mutex);
+	codec->spec = spec;
+
+	codec->patch_ops = conexant_patch_ops;
+	codec->patch_ops.init = cxt5051_init;
+
+	spec->multiout.max_channels = 2;
+	spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids);
+	spec->multiout.dac_nids = cxt5051_dac_nids;
+	spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT;
+	spec->num_adc_nids = 1; /* not 2; via auto-mic switch */
+	spec->adc_nids = cxt5051_adc_nids;
+	spec->num_mixers = 1;
+	spec->mixers[0] = cxt5051_mixers;
+	spec->num_init_verbs = 1;
+	spec->init_verbs[0] = cxt5051_init_verbs;
+	spec->spdif_route = 0;
+	spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes);
+	spec->channel_mode = cxt5051_modes;
+	spec->cur_adc = 0;
+	spec->cur_adc_idx = 0;
+
+	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
+						  cxt5051_models,
+						  cxt5051_cfg_tbl);
+	switch (board_config) {
+	case CXT5051_HP:
+		codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
+		spec->mixers[0] = cxt5051_hp_mixers;
+		break;
+	default:
+	case CXT5051_LAPTOP:
+		codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ */
+
 struct hda_codec_preset snd_hda_preset_conexant[] = {
 	{ .id = 0x14f15045, .name = "CX20549 (Venice)",
 	  .patch = patch_cxt5045 },
 	{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
 	  .patch = patch_cxt5047 },
+	{ .id = 0x14f15051, .name = "CX20561 (Hermosa)",
+	  .patch = patch_cxt5051 },
 	{} /* terminator */
 };
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_realtek.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_realtek.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_realtek.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_realtek.c	2008-09-28 23:33:41.000000000 +0200
@@ -23,7 +23,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -92,22 +91,38 @@
 	ALC262_HP_BPC,
 	ALC262_HP_BPC_D7000_WL,
 	ALC262_HP_BPC_D7000_WF,
+	ALC262_HP_TC_T5735,
+	ALC262_HP_RP5700,
 	ALC262_BENQ_ED8,
 	ALC262_SONY_ASSAMD,
 	ALC262_BENQ_T31,
+	ALC262_ULTRA,
 	ALC262_AUTO,
 	ALC262_MODEL_LAST /* last tag */
 };
 
 /* ALC268 models */
 enum {
+	ALC267_QUANTA_IL1,
 	ALC268_3ST,
 	ALC268_TOSHIBA,
 	ALC268_ACER,
+	ALC268_DELL,
+	ALC268_ZEPTO,
+#ifdef CONFIG_SND_DEBUG
+	ALC268_TEST,
+#endif
 	ALC268_AUTO,
 	ALC268_MODEL_LAST /* last tag */
 };
 
+/* ALC269 models */
+enum {
+	ALC269_BASIC,
+	ALC269_AUTO,
+	ALC269_MODEL_LAST /* last tag */
+};
+
 /* ALC861 models */
 enum {
 	ALC861_3ST,
@@ -144,6 +159,7 @@
 	ALC662_5ST_DIG,
 	ALC662_LENOVO_101E,
 	ALC662_ASUS_EEEPC_P701,
+	ALC662_ASUS_EEEPC_EP20,
 	ALC662_AUTO,
 	ALC662_MODEL_LAST,
 };
@@ -181,8 +197,10 @@
 	ALC883_LENOVO_NB0763,
 	ALC888_LENOVO_MS7195_DIG,
 	ALC883_HAIER_W66,		
-	ALC888_6ST_HP,
 	ALC888_3ST_HP,
+	ALC888_6ST_DELL,
+	ALC883_MITAC,
+	ALC883_CLEVO_M720,
 	ALC883_AUTO,
 	ALC883_MODEL_LAST,
 };
@@ -204,6 +222,8 @@
 	char *stream_name_analog;	/* analog PCM stream */
 	struct hda_pcm_stream *stream_analog_playback;
 	struct hda_pcm_stream *stream_analog_capture;
+	struct hda_pcm_stream *stream_analog_alt_playback;
+	struct hda_pcm_stream *stream_analog_alt_capture;
 
 	char *stream_name_digital;	/* digital PCM stream */
 	struct hda_pcm_stream *stream_digital_playback;
@@ -214,10 +234,12 @@
 					 * max_channels, dacs must be set
 					 * dig_out_nid and hp_nid are optional
 					 */
+	hda_nid_t alt_dac_nid;
 
 	/* capture */
 	unsigned int num_adc_nids;
 	hda_nid_t *adc_nids;
+	hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
 
 	/* capture source */
@@ -247,7 +269,11 @@
 	/* for pin sensing */
 	unsigned int sense_updated: 1;
 	unsigned int jack_present: 1;
+	unsigned int master_sw: 1;
 
+	/* for virtual master */
+	hda_nid_t vmaster_nid;
+	u32 vmaster_tlv[4];
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	struct hda_loopback_check loopback;
 #endif
@@ -267,6 +293,7 @@
 	hda_nid_t hp_nid;		/* optional */
 	unsigned int num_adc_nids;
 	hda_nid_t *adc_nids;
+	hda_nid_t *capsrc_nids;
 	hda_nid_t dig_in_nid;
 	unsigned int num_channel_mode;
 	const struct hda_channel_mode *channel_mode;
@@ -313,9 +340,10 @@
 	struct alc_spec *spec = codec->spec;
 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
+	hda_nid_t nid = spec->capsrc_nids ?
+		spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
 	return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
-				     spec->adc_nids[adc_idx],
-				     &spec->cur_mux[adc_idx]);
+				     nid, &spec->cur_mux[adc_idx]);
 }
 
 
@@ -562,7 +590,7 @@
 	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
 	long *valp = ucontrol->value.integer.value;
 	unsigned int val = snd_hda_codec_read(codec, nid, 0,
-					      AC_VERB_GET_DIGI_CONVERT, 0x00);
+					      AC_VERB_GET_DIGI_CONVERT_1, 0x00);
 
 	*valp = (val & mask) != 0;
 	return 0;
@@ -576,7 +604,7 @@
 	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
 	long val = *ucontrol->value.integer.value;
 	unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
-						    AC_VERB_GET_DIGI_CONVERT,
+						    AC_VERB_GET_DIGI_CONVERT_1,
 						    0x00);
 
 	/* Set/unset the masked control bit(s) as needed */
@@ -598,6 +626,59 @@
 	  .private_value = nid | (mask<<16) }
 #endif   /* CONFIG_SND_DEBUG */
 
+/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
+ * Again, this is only used in the ALC26x test models to help identify when
+ * the EAPD line must be asserted for features to work.
+ */
+#ifdef CONFIG_SND_DEBUG
+#define alc_eapd_ctrl_info	snd_ctl_boolean_mono_info
+
+static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long *valp = ucontrol->value.integer.value;
+	unsigned int val = snd_hda_codec_read(codec, nid, 0,
+					      AC_VERB_GET_EAPD_BTLENABLE, 0x00);
+
+	*valp = (val & mask) != 0;
+	return 0;
+}
+
+static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long val = *ucontrol->value.integer.value;
+	unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+						    AC_VERB_GET_EAPD_BTLENABLE,
+						    0x00);
+
+	/* Set/unset the masked control bit(s) as needed */
+	change = (!val ? 0 : mask) != (ctrl_data & mask);
+	if (!val)
+		ctrl_data &= ~mask;
+	else
+		ctrl_data |= mask;
+	snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+				  ctrl_data);
+
+	return change;
+}
+
+#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .info = alc_eapd_ctrl_info, \
+	  .get = alc_eapd_ctrl_get, \
+	  .put = alc_eapd_ctrl_put, \
+	  .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
 /*
  * set up from the preset table
  */
@@ -631,6 +712,7 @@
 
 	spec->num_adc_nids = preset->num_adc_nids;
 	spec->adc_nids = preset->adc_nids;
+	spec->capsrc_nids = preset->capsrc_nids;
 	spec->dig_in_nid = preset->dig_in_nid;
 
 	spec->unsol_event = preset->unsol_event;
@@ -665,7 +747,6 @@
 static void alc_sku_automute(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
-	unsigned int mute;
 	unsigned int present;
 	unsigned int hp_nid = spec->autocfg.hp_pins[0];
 	unsigned int sp_nid = spec->autocfg.speaker_pins[0];
@@ -675,16 +756,8 @@
 	present = snd_hda_codec_read(codec, hp_nid, 0,
 				     AC_VERB_GET_PIN_SENSE, 0);
 	spec->jack_present = (present & 0x80000000) != 0;
-	if (spec->jack_present) {
-		/* mute internal speaker */
-		snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, HDA_AMP_MUTE);
-	} else {
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0);
-		snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0,
-					 HDA_AMP_MUTE, mute);
-	}
+	snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    spec->jack_present ? 0 : PIN_OUT);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -739,7 +812,7 @@
 	/* check sum */
 	tmp = 0;
 	for (i = 1; i < 16; i++) {
-		if ((ass >> i) && 1)
+		if ((ass >> i) & 1)
 			tmp++;
 	}
 	if (((ass >> 16) & 0xf) != tmp)
@@ -828,10 +901,10 @@
 		break;
 	}
 	
-	/* is laptop and enable the function "Mute internal speaker
+	/* is laptop or Desktop and enable the function "Mute internal speaker
 	 * when the external headphone out jack is plugged"
 	 */
-	if (!(ass & 0x4) || !(ass & 0x8000))
+	if (!(ass & 0x8000))
 		return;
 	/*
 	 * 10~8 : Jack location
@@ -841,9 +914,9 @@
 	 *	        when the external headphone out jack is plugged"
 	 */
 	if (!spec->autocfg.speaker_pins[0]) {
-		if (spec->multiout.dac_nids[0])
+		if (spec->autocfg.line_out_pins[0])
 			spec->autocfg.speaker_pins[0] =
-				spec->multiout.dac_nids[0];
+				spec->autocfg.line_out_pins[0];
 		else
 			return;
 	}
@@ -1009,7 +1082,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -1031,7 +1103,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -1226,7 +1297,6 @@
 };
 
 
-/* FIXME! */
 /*
  * ALC880 F1734 model
  *
@@ -1242,17 +1312,24 @@
 static struct snd_kcontrol_new alc880_f1734_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	{ } /* end */
 };
 
+static struct hda_input_mux alc880_f1734_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x1 },
+		{ "CD", 0x4 },
+	},
+};
+
 
-/* FIXME! */
 /*
  * ALC880 ASUS model
  *
@@ -1289,7 +1366,6 @@
 	{ } /* end */
 };
 
-/* FIXME! */
 /*
  * ALC880 ASUS W1V model
  *
@@ -1327,7 +1403,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -1341,10 +1416,10 @@
 
 /* Uniwill */
 static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
-	HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
@@ -1384,16 +1459,49 @@
 };
 
 static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
-	HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	{ } /* end */
 };
 
 /*
+ * virtual master controls
+ */
+
+/*
+ * slave controls for virtual master
+ */
+static const char *alc_slave_vols[] = {
+	"Front Playback Volume",
+	"Surround Playback Volume",
+	"Center Playback Volume",
+	"LFE Playback Volume",
+	"Side Playback Volume",
+	"Headphone Playback Volume",
+	"Speaker Playback Volume",
+	"Mono Playback Volume",
+	"Line-Out Playback Volume",
+	NULL,
+};
+
+static const char *alc_slave_sws[] = {
+	"Front Playback Switch",
+	"Surround Playback Switch",
+	"Center Playback Switch",
+	"LFE Playback Switch",
+	"Side Playback Switch",
+	"Headphone Playback Switch",
+	"Speaker Playback Switch",
+	"Mono Playback Switch",
+	"IEC958 Playback Switch",
+	NULL,
+};
+
+/*
  * build control elements
  */
 static int alc_build_controls(struct hda_codec *codec)
@@ -1413,12 +1521,34 @@
 						    spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
 		if (err < 0)
 			return err;
 	}
+
+	/* if we have no master control, let's create it */
+	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
+					HDA_OUTPUT, spec->vmaster_tlv);
+		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+					  spec->vmaster_tlv, alc_slave_vols);
+		if (err < 0)
+			return err;
+	}
+	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+					  NULL, alc_slave_sws);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -1790,7 +1920,6 @@
 		alc880_uniwill_p53_dcvol_automute(codec);
 }
 
-/* FIXME! */
 /*
  * F1734 pin configuration:
  * HP = 0x14, speaker-out = 0x15, mic = 0x18
@@ -1816,10 +1945,12 @@
 	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
+	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
+
 	{ }
 };
 
-/* FIXME! */
 /*
  * ASUS pin configuration:
  * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
@@ -1966,9 +2097,8 @@
 };
 
 static struct snd_kcontrol_new alc880_lg_mixer[] = {
-	/* FIXME: it's not really "master" but front channels */
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
@@ -2201,7 +2331,8 @@
 				    struct snd_pcm_substream *substream)
 {
 	struct alc_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -2256,7 +2387,7 @@
 /*
  * Analog capture
  */
-static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
 				      struct hda_codec *codec,
 				      unsigned int stream_tag,
 				      unsigned int format,
@@ -2264,18 +2395,18 @@
 {
 	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
 				   stream_tag, 0, format);
 	return 0;
 }
 
-static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 				      struct hda_codec *codec,
 				      struct snd_pcm_substream *substream)
 {
 	struct alc_spec *spec = codec->spec;
 
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
 				   0, 0, 0);
 	return 0;
 }
@@ -2296,13 +2427,27 @@
 };
 
 static struct hda_pcm_stream alc880_pcm_analog_capture = {
-	.substreams = 2,
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in alc_build_pcms */
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
+	.substreams = 2, /* can be overridden */
 	.channels_min = 2,
 	.channels_max = 2,
 	/* NID is set in alc_build_pcms */
 	.ops = {
-		.prepare = alc880_capture_pcm_prepare,
-		.cleanup = alc880_capture_pcm_cleanup
+		.prepare = alc880_alt_capture_pcm_prepare,
+		.cleanup = alc880_alt_capture_pcm_cleanup
 	},
 };
 
@@ -2326,7 +2471,7 @@
 };
 
 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
-static struct hda_pcm_stream alc_pcm_null_playback = {
+static struct hda_pcm_stream alc_pcm_null_stream = {
 	.substreams = 0,
 	.channels_min = 0,
 	.channels_max = 0,
@@ -2367,6 +2512,7 @@
 		codec->num_pcms = 2;
 		info = spec->pcm_rec + 1;
 		info->name = spec->stream_name_digital;
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid &&
 		    spec->stream_digital_playback) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
@@ -2383,17 +2529,32 @@
 	 * model, configure a second analog capture-only PCM.
 	 */
 	/* Additional Analaog capture for index #2 */
-	if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
-	    spec->adc_nids) {
+	if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
+	    (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
 		codec->num_pcms = 3;
 		info = spec->pcm_rec + 2;
 		info->name = spec->stream_name_analog;
-		/* No playback stream for second PCM */
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
-		if (spec->stream_analog_capture) {
-			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
-			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
+		if (spec->alt_dac_nid) {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+				*spec->stream_analog_alt_playback;
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+				spec->alt_dac_nid;
+		} else {
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+				alc_pcm_null_stream;
+			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
+		}
+		if (spec->num_adc_nids > 1) {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				*spec->stream_analog_alt_capture;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+				spec->adc_nids[1];
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+				spec->num_adc_nids - 1;
+		} else {
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+				alc_pcm_null_stream;
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
 		}
 	}
 
@@ -2723,23 +2884,17 @@
 };
 
 static struct snd_pci_quirk alc880_cfg_tbl[] = {
-	/* Broken BIOS configuration */
-	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
-
+	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
 	SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
-	SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
 	SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
 	SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
 	SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
-
 	SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
-
 	SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
 	SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
 	SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
@@ -2754,54 +2909,50 @@
 	SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
 	SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
 	SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
-	SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS),
-
-	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+	SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
 	SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
+	SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
 	SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
 	SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
-	SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
-	SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
-	SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
-	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
-	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
-	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
 	SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
+	SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
 	SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
-
+	SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
+	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
 	SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
 	SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
-	SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
-
+	SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+	SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
 	SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+	SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
 	SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
-
+	SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
 	SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
 	SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
-	SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
 	SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
-
-	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
+	SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
+	SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
 	SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
 	SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
 	SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
-	SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST),
-
+	SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
+	SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
+	SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
 	{}
 };
 
@@ -2921,7 +3072,9 @@
 		.hp_nid = 0x02,
 		.num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
 		.channel_mode = alc880_2_jack_modes,
-		.input_mux = &alc880_capture_source,
+		.input_mux = &alc880_f1734_capture_source,
+		.unsol_event = alc880_uniwill_p53_unsol_event,
+		.init_hook = alc880_uniwill_p53_hp_automute,
 	},
 	[ALC880_ASUS] = {
 		.mixers = { alc880_asus_mixer },
@@ -3331,15 +3484,21 @@
 	return 0;
 }
 
-static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
-					      hda_nid_t nid, int pin_type,
-					      int dac_idx)
+static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
+			       unsigned int pin_type)
 {
-	/* set as output */
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 			    pin_type);
+	/* unmute pin */
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 			    AMP_OUT_UNMUTE);
+}
+
+static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
+					      hda_nid_t nid, int pin_type,
+					      int dac_idx)
+{
+	alc_set_pin_output(codec, nid, pin_type);
 	/* need the manual connection? */
 	if (alc880_is_multi_pin(nid)) {
 		struct alc_spec *spec = codec->spec;
@@ -3461,9 +3620,12 @@
 /* additional initialization for auto-configuration model */
 static void alc880_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc880_auto_init_multi_out(codec);
 	alc880_auto_init_extra_out(codec);
 	alc880_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
@@ -3511,6 +3673,7 @@
 	spec->stream_name_analog = "ALC880 Analog";
 	spec->stream_analog_playback = &alc880_pcm_analog_playback;
 	spec->stream_analog_capture = &alc880_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC880 Digital";
 	spec->stream_digital_playback = &alc880_pcm_digital_playback;
@@ -3535,6 +3698,8 @@
 		}
 	}
 
+	spec->vmaster_nid = 0x0c;
+
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC880_AUTO)
 		spec->init_hook = alc880_auto_init;
@@ -3691,18 +3856,135 @@
 	{ } /* end */
 };
 
+/* update HP, line and mono out pins according to the master switch */
+static void alc260_hp_master_update(struct hda_codec *codec,
+				    hda_nid_t hp, hda_nid_t line,
+				    hda_nid_t mono)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int val = spec->master_sw ? PIN_HP : 0;
+	/* change HP and line-out pins */
+	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    val);
+	snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    val);
+	/* mono (speaker) depending on the HP jack sense */
+	val = (val && !spec->jack_present) ? PIN_OUT : 0;
+	snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    val);
+}
+
+static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	*ucontrol->value.integer.value = spec->master_sw;
+	return 0;
+}
+
+static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int val = !!*ucontrol->value.integer.value;
+	hda_nid_t hp, line, mono;
+
+	if (val == spec->master_sw)
+		return 0;
+	spec->master_sw = val;
+	hp = (kcontrol->private_value >> 16) & 0xff;
+	line = (kcontrol->private_value >> 8) & 0xff;
+	mono = kcontrol->private_value & 0xff;
+	alc260_hp_master_update(codec, hp, line, mono);
+	return 1;
+}
+
+static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc260_hp_master_sw_get,
+		.put = alc260_hp_master_sw_put,
+		.private_value = (0x0f << 16) | (0x10 << 8) | 0x11
+	},
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
+			      HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_verb alc260_hp_unsol_verbs[] = {
+	{0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{},
+};
+
+static void alc260_hp_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x10, 0,
+				     AC_VERB_GET_PIN_SENSE, 0);
+	spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+	alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
+}
+
+static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc260_hp_automute(codec);
+}
+
 static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc260_hp_master_sw_get,
+		.put = alc260_hp_master_sw_put,
+		.private_value = (0x10 << 16) | (0x15 << 8) | 0x11
+	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
 	HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
+static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{},
+};
+
+static void alc260_hp_3013_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+				     AC_VERB_GET_PIN_SENSE, 0);
+	spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+	alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
+}
+
+static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc260_hp_3013_automute(codec);
+}
+
 /* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12, 
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  */
@@ -3717,8 +3999,8 @@
 	ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
 	{ } /* end */
 };
 
@@ -3749,9 +4031,9 @@
 	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
 	ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
-	HDA_CODEC_VOLUME_MONO("Mono Speaker Playback Volume", 0x0a, 1, 0x0,
+	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
 			      HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Mono Speaker Playback Switch", 0x0a, 1, 2,
+	HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
 			   HDA_INPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
@@ -3812,7 +4094,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -3831,7 +4112,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -4332,6 +4612,12 @@
 	ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
 	ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
 
+	/* A switch allowing EAPD to be enabled.  Some laptops seem to use
+	 * this output to turn on an external amplifier.
+	 */
+	ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
+	ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
+
 	{ } /* end */
 };
 static struct hda_verb alc260_test_init_verbs[] = {
@@ -4417,17 +4703,8 @@
 };
 #endif
 
-static struct hda_pcm_stream alc260_pcm_analog_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-};
-
-static struct hda_pcm_stream alc260_pcm_analog_capture = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-};
+#define alc260_pcm_analog_playback	alc880_pcm_analog_alt_playback
+#define alc260_pcm_analog_capture	alc880_pcm_analog_capture
 
 #define alc260_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc260_pcm_digital_capture	alc880_pcm_digital_capture
@@ -4544,11 +4821,7 @@
 					      hda_nid_t nid, int pin_type,
 					      int sel_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 	/* need the manual connection? */
 	if (nid >= 0x12) {
 		int idx = nid - 0x12;
@@ -4695,8 +4968,11 @@
 /* additional initialization for auto-configuration model */
 static void alc260_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc260_auto_init_multi_out(codec);
 	alc260_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -4744,8 +5020,8 @@
 	SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
 	SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
 	SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
-	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
 	SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
+	SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
 	{}
 };
 
@@ -4765,10 +5041,11 @@
 		.input_mux = &alc260_capture_source,
 	},
 	[ALC260_HP] = {
-		.mixers = { alc260_base_output_mixer,
+		.mixers = { alc260_hp_output_mixer,
 			    alc260_input_mixer,
 			    alc260_capture_alt_mixer },
-		.init_verbs = { alc260_init_verbs },
+		.init_verbs = { alc260_init_verbs,
+				alc260_hp_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
@@ -4776,12 +5053,15 @@
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
+		.unsol_event = alc260_hp_unsol_event,
+		.init_hook = alc260_hp_automute,
 	},
 	[ALC260_HP_3013] = {
 		.mixers = { alc260_hp_3013_mixer,
 			    alc260_input_mixer,
 			    alc260_capture_alt_mixer },
-		.init_verbs = { alc260_hp_3013_init_verbs },
+		.init_verbs = { alc260_hp_3013_init_verbs,
+				alc260_hp_3013_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
@@ -4789,6 +5069,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_capture_source,
+		.unsol_event = alc260_hp_3013_unsol_event,
+		.init_hook = alc260_hp_3013_automute,
 	},
 	[ALC260_FUJITSU_S702X] = {
 		.mixers = { alc260_fujitsu_mixer,
@@ -4906,6 +5188,8 @@
 	spec->stream_digital_playback = &alc260_pcm_digital_playback;
 	spec->stream_digital_capture = &alc260_pcm_digital_capture;
 
+	spec->vmaster_nid = 0x08;
+
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC260_AUTO)
 		spec->init_hook = alc260_auto_init;
@@ -4945,6 +5229,9 @@
 #define alc882_adc_nids		alc880_adc_nids
 #define alc882_adc_nids_alt	alc880_adc_nids_alt
 
+static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
+static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -4967,8 +5254,8 @@
 	struct alc_spec *spec = codec->spec;
 	const struct hda_input_mux *imux = spec->input_mux;
 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
+	hda_nid_t nid = spec->capsrc_nids ?
+		spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
 	unsigned int *cur_val = &spec->cur_mux[adc_idx];
 	unsigned int i, idx;
 
@@ -5106,15 +5393,15 @@
 };
 
 static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
-	HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT),
-	HDA_BIND_MUTE   ("Master Switch", 0x0c, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE  ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+	HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
 	HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
 	{ } /* end */
 };
@@ -5679,7 +5966,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -5702,7 +5988,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -5743,16 +6028,17 @@
 
 static struct snd_pci_quirk alc882_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
-	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
-	SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
 	SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
 	SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
 	SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
 	SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
 	SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
-	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
+	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
+	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+	SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
 	{}
 };
 
@@ -5849,6 +6135,7 @@
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
 		.adc_nids = alc882_adc_nids,
+		.capsrc_nids = alc882_capsrc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -5865,6 +6152,7 @@
 		.dig_out_nid = ALC882_DIGOUT_NID,
 		.num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
 		.adc_nids = alc882_adc_nids,
+		.capsrc_nids = alc882_capsrc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
 		.channel_mode = alc882_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -5920,15 +6208,11 @@
 	struct alc_spec *spec = codec->spec;
 	int idx;
 
+	alc_set_pin_output(codec, nid, pin_type);
 	if (spec->multiout.dac_nids[dac_idx] == 0x25)
 		idx = 4;
 	else
 		idx = spec->multiout.dac_nids[dac_idx] - 2;
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 
 }
@@ -5957,6 +6241,9 @@
 	if (pin) /* connect to front */
 		/* use dac 0 */
 		alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc882_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -5990,7 +6277,7 @@
 	hda_nid_t nid;
 
 	nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
-	if (nid) {
+	if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
 		err = add_control(spec, ALC_CTL_WIDGET_VOL,
 				  "Mic Boost",
 				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
@@ -5998,7 +6285,7 @@
 			return err;
 	}
 	nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
-	if (nid) {
+	if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
 		err = add_control(spec, ALC_CTL_WIDGET_VOL,
 				  "Front Mic Boost",
 				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
@@ -6032,9 +6319,12 @@
 /* additional initialization for auto-configuration model */
 static void alc882_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc882_auto_init_multi_out(codec);
 	alc882_auto_init_hp_out(codec);
 	alc882_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc882(struct hda_codec *codec)
@@ -6061,6 +6351,7 @@
 		case 0x106b1000: /* iMac 24 */
 			board_config = ALC885_IMAC24;
 			break;
+		case 0x106b00a1: /* Macbook */
 		case 0x106b2c00: /* Macbook Pro rev3 */
 			board_config = ALC885_MBP3;
 			break;
@@ -6093,6 +6384,9 @@
 	spec->stream_name_analog = "ALC882 Analog";
 	spec->stream_analog_playback = &alc882_pcm_analog_playback;
 	spec->stream_analog_capture = &alc882_pcm_analog_capture;
+	/* FIXME: setup DAC5 */
+	/*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
+	spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC882 Digital";
 	spec->stream_digital_playback = &alc882_pcm_digital_playback;
@@ -6106,17 +6400,21 @@
 		if (wcap != AC_WID_AUD_IN) {
 			spec->adc_nids = alc882_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
+			spec->capsrc_nids = alc882_capsrc_nids_alt;
 			spec->mixers[spec->num_mixers] =
 				alc882_capture_alt_mixer;
 			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc882_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
+			spec->capsrc_nids = alc882_capsrc_nids;
 			spec->mixers[spec->num_mixers] = alc882_capture_mixer;
 			spec->num_mixers++;
 		}
 	}
 
+	spec->vmaster_nid = 0x0c;
+
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC882_AUTO)
 		spec->init_hook = alc882_auto_init;
@@ -6144,7 +6442,7 @@
 
 static hda_nid_t alc883_dac_nids[4] = {
 	/* front, rear, clfe, rear_surr */
-	0x02, 0x04, 0x03, 0x05
+	0x02, 0x03, 0x04, 0x05
 };
 
 static hda_nid_t alc883_adc_nids[2] = {
@@ -6152,6 +6450,8 @@
 	0x08, 0x09,
 };
 
+static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 
@@ -6185,33 +6485,8 @@
 
 #define alc883_mux_enum_info alc_mux_enum_info
 #define alc883_mux_enum_get alc_mux_enum_get
-
-static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
+/* ALC883 has the ALC882-type input selection */
+#define alc883_mux_enum_put alc882_mux_enum_put
 
 /*
  * 2ch mode
@@ -6340,6 +6615,63 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc883_mitac_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 2,
+		.info = alc883_mux_enum_info,
+		.get = alc883_mux_enum_get,
+		.put = alc883_mux_enum_put,
+	},
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -6508,8 +6840,8 @@
 static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -6580,84 +6912,6 @@
 	{ } /* end */
 };	
 
-static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = alc883_mux_enum_info,
-		.get = alc883_mux_enum_get,
-		.put = alc883_mux_enum_put,
-	},
-	{ } /* end */
-};
-
 static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -6772,6 +7026,82 @@
 	{ }
 };
 
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_mitac_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x15, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+/* auto-toggle front mic */
+/*
+static void alc883_mitac_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	bits = present ? HDA_AMP_MUTE : 0;
+	snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
+}
+*/
+
+static void alc883_mitac_automute(struct hda_codec *codec)
+{
+	alc883_mitac_hp_automute(codec);
+	/* alc883_mitac_mic_automute(codec); */
+}
+
+static void alc883_mitac_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc883_mitac_hp_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		/* alc883_mitac_mic_automute(codec); */
+		break;
+	}
+}
+
+static struct hda_verb alc883_mitac_verbs[] = {
+	/* HP */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	/* Subwoofer */
+	{0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* enable unsolicited event */
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	/* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
+
+	{ } /* end */
+};
+
+static struct hda_verb alc883_clevo_m720_verbs[] = {
+	/* HP */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	/* Int speaker */
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* enable unsolicited event */
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+
+	{ } /* end */
+};
+
 static struct hda_verb alc883_tagra_verbs[] = {
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -6828,18 +7158,15 @@
 	{ } /* end */
 };
 
-static struct hda_verb alc888_6st_hp_verbs[] = {
+static struct hda_verb alc888_3st_hp_verbs[] = {
 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x02},	/* Rear : output 2 (0x0e) */
-	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* CLFE : output 1 (0x0d) */
-	{0x17, AC_VERB_SET_CONNECT_SEL, 0x03},	/* Side : output 3 (0x0f) */
+	{0x16, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
+	{0x18, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
 	{ }
 };
 
-static struct hda_verb alc888_3st_hp_verbs[] = {
-	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},	/* Front: output 0 (0x0c) */
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x01},	/* Rear : output 1 (0x0d) */
-	{0x16, AC_VERB_SET_CONNECT_SEL, 0x02},	/* CLFE : output 2 (0x0e) */
+static struct hda_verb alc888_6st_dell_verbs[] = {
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
 	{ }
 };
 
@@ -6946,29 +7273,71 @@
 		alc883_tagra_automute(codec);
 }
 
-static void alc883_haier_w66_automute(struct hda_codec *codec)
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
 {
 	unsigned int present;
 	unsigned char bits;
 
-	present = snd_hda_codec_read(codec, 0x1b, 0,
-				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-	bits = present ? 0x80 : 0;
+	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	bits = present ? HDA_AMP_MUTE : 0;
 	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-				 0x80, bits);
+				 HDA_AMP_MUTE, bits);
 }
 
-static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
-					 unsigned int res)
+static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
 {
-	if ((res >> 26) == ALC880_HP_EVENT)
-		alc883_haier_w66_automute(codec);
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
+				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 }
 
-static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
+static void alc883_clevo_m720_automute(struct hda_codec *codec)
 {
- 	unsigned int present;
-	unsigned char bits;
+	alc883_clevo_m720_hp_automute(codec);
+	alc883_clevo_m720_mic_automute(codec);
+}
+
+static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc883_clevo_m720_hp_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc883_clevo_m720_mic_automute(codec);
+		break;
+	}
+}
+
+static void alc883_haier_w66_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned char bits;
+
+	present = snd_hda_codec_read(codec, 0x1b, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	bits = present ? 0x80 : 0;
+	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+				 0x80, bits);
+}
+
+static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
+					 unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc883_haier_w66_automute(codec);
+}
+
+static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+	unsigned char bits;
 
  	present = snd_hda_codec_read(codec, 0x14, 0,
 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
@@ -7038,6 +7407,33 @@
 	{ }
 };
 
+static void alc888_6st_dell_front_automute(struct hda_codec *codec)
+{
+ 	unsigned int present;
+ 
+ 	present = snd_hda_codec_read(codec, 0x1b, 0,
+				AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+				HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+				HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+				HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+	snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+				HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
+					     unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		printk("hp_event\n");
+		alc888_6st_dell_front_automute(codec);
+		break;
+	}
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -7096,7 +7492,7 @@
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
 	/* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
 	{ }
 };
@@ -7111,7 +7507,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -7130,6 +7525,7 @@
 /* pcm configuration: identiacal with ALC880 */
 #define alc883_pcm_analog_playback	alc880_pcm_analog_playback
 #define alc883_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc883_pcm_analog_alt_capture	alc880_pcm_analog_alt_capture
 #define alc883_pcm_digital_playback	alc880_pcm_digital_playback
 #define alc883_pcm_digital_capture	alc880_pcm_digital_capture
 
@@ -7152,55 +7548,65 @@
 	[ALC883_LENOVO_NB0763]	= "lenovo-nb0763",
 	[ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
 	[ALC883_HAIER_W66] 	= "haier-w66",
-	[ALC888_6ST_HP]		= "6stack-hp",
 	[ALC888_3ST_HP]		= "3stack-hp",
+	[ALC888_6ST_DELL]	= "6stack-dell",
+	[ALC883_MITAC]		= "mitac",
+	[ALC883_CLEVO_M720]	= "clevo-m720",
 	[ALC883_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc883_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
+	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
+	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
+	SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
+	SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
 	SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
-	SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
-	SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+	SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
+	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+	SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
-	SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
+	SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
-	SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
-	SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
 	SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+	SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
-	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
-	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
-	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
-	SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER),
+	SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
+	SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
+	SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
 	SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
-	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
 	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
-	SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-	SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
-	SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
-	SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+	SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+	SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
 	SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
+	SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
 	SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
-	SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-	SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
-	SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+	SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
 	{}
 };
 
@@ -7211,8 +7617,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
@@ -7224,8 +7628,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
@@ -7237,8 +7639,6 @@
 		.init_verbs = { alc883_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -7250,8 +7650,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
@@ -7263,8 +7661,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -7278,8 +7674,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7296,8 +7690,6 @@
 		.init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7308,8 +7700,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7323,8 +7713,6 @@
 				alc883_medion_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
@@ -7335,8 +7723,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
@@ -7348,19 +7734,27 @@
 		.init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 	},
+	[ALC883_CLEVO_M720] = {
+		.mixers = { alc883_clevo_m720_mixer },
+		.init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.dig_out_nid = ALC883_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
+		.input_mux = &alc883_capture_source,
+		.unsol_event = alc883_clevo_m720_unsol_event,
+		.init_hook = alc883_clevo_m720_automute,
+	},
 	[ALC883_LENOVO_101E_2ch] = {
 		.mixers = { alc883_lenovo_101e_2ch_mixer},
 		.init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_lenovo_101e_capture_source,
@@ -7372,8 +7766,6 @@
 		.init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.need_dac_fix = 1,
@@ -7387,8 +7779,6 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
 		.channel_mode = alc883_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -7402,38 +7792,45 @@
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
 		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
 		.unsol_event = alc883_haier_w66_unsol_event,
 		.init_hook = alc883_haier_w66_automute,
-	},	
-	[ALC888_6ST_HP] = {
-		.mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
-		.init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
+	},
+	[ALC888_3ST_HP] = {
+		.mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
+		.dac_nids = alc883_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
+		.channel_mode = alc888_3st_hp_modes,
+		.need_dac_fix = 1,
+		.input_mux = &alc883_capture_source,
+	},
+	[ALC888_6ST_DELL] = {
+		.mixers = { alc883_base_mixer, alc883_chmode_mixer },
+		.init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
 		.dig_out_nid = ALC883_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
 		.dig_in_nid = ALC883_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
 		.channel_mode = alc883_sixstack_modes,
 		.input_mux = &alc883_capture_source,
+		.unsol_event = alc888_6st_dell_unsol_event,
+		.init_hook = alc888_6st_dell_front_automute,
 	},
-	[ALC888_3ST_HP] = {
-		.mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
-		.init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+	[ALC883_MITAC] = {
+		.mixers = { alc883_mitac_mixer },
+		.init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
 		.num_dacs = ARRAY_SIZE(alc883_dac_nids),
 		.dac_nids = alc883_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-		.adc_nids = alc883_adc_nids,
-		.num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
-		.channel_mode = alc888_3st_hp_modes,
-		.need_dac_fix = 1,
+		.num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+		.channel_mode = alc883_3ST_2ch_modes,
 		.input_mux = &alc883_capture_source,
+		.unsol_event = alc883_mitac_unsol_event,
+		.init_hook = alc883_mitac_automute,
 	},
 };
 
@@ -7449,15 +7846,11 @@
 	struct alc_spec *spec = codec->spec;
 	int idx;
 
+	alc_set_pin_output(codec, nid, pin_type);
 	if (spec->multiout.dac_nids[dac_idx] == 0x25)
 		idx = 4;
 	else
 		idx = spec->multiout.dac_nids[dac_idx] - 2;
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
 	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
 
 }
@@ -7486,6 +7879,9 @@
 	if (pin) /* connect to front */
 		/* use dac 0 */
 		alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc883_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -7537,9 +7933,12 @@
 /* additional initialization for auto-configuration model */
 static void alc883_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc883_auto_init_multi_out(codec);
 	alc883_auto_init_hp_out(codec);
 	alc883_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc883(struct hda_codec *codec)
@@ -7582,15 +7981,17 @@
 	spec->stream_name_analog = "ALC883 Analog";
 	spec->stream_analog_playback = &alc883_pcm_analog_playback;
 	spec->stream_analog_capture = &alc883_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
 
 	spec->stream_name_digital = "ALC883 Digital";
 	spec->stream_digital_playback = &alc883_pcm_digital_playback;
 	spec->stream_digital_capture = &alc883_pcm_digital_capture;
 
-	if (!spec->adc_nids && spec->input_mux) {
-		spec->adc_nids = alc883_adc_nids;
-		spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
-	}
+	spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
+	spec->adc_nids = alc883_adc_nids;
+	spec->capsrc_nids = alc883_capsrc_nids;
+
+	spec->vmaster_nid = 0x0c;
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC883_AUTO)
@@ -7613,6 +8014,8 @@
 #define alc262_dac_nids		alc260_dac_nids
 #define alc262_adc_nids		alc882_adc_nids
 #define alc262_adc_nids_alt	alc882_adc_nids_alt
+#define alc262_capsrc_nids	alc882_capsrc_nids
+#define alc262_capsrc_nids_alt	alc882_capsrc_nids_alt
 
 #define alc262_modes		alc260_modes
 #define alc262_capture_source	alc882_capture_source
@@ -7631,7 +8034,7 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	/* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	   HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
+	   HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
@@ -7653,19 +8056,105 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
 	/* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
-	   HDA_CODEC_MUTE("PC Beelp Playback Switch", 0x0b, 0x05, HDA_INPUT), */
+	   HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
 	/*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	{ } /* end */
 };
 
+/* update HP, line and mono-out pins according to the master switch */
+static void alc262_hp_master_update(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int val = spec->master_sw;
+
+	/* HP & line-out */
+	snd_hda_codec_write_cache(codec, 0x1b, 0,
+				  AC_VERB_SET_PIN_WIDGET_CONTROL,
+				  val ? PIN_HP : 0);
+	snd_hda_codec_write_cache(codec, 0x15, 0,
+				  AC_VERB_SET_PIN_WIDGET_CONTROL,
+				  val ? PIN_HP : 0);
+	/* mono (speaker) depending on the HP jack sense */
+	val = val && !spec->jack_present;
+	snd_hda_codec_write_cache(codec, 0x16, 0,
+				  AC_VERB_SET_PIN_WIDGET_CONTROL,
+				  val ? PIN_OUT : 0);
+}
+
+static void alc262_hp_bpc_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int presence;
+	presence = snd_hda_codec_read(codec, 0x1b, 0,
+				      AC_VERB_GET_PIN_SENSE, 0);
+	spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+	alc262_hp_master_update(codec);
+}
+
+static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_hp_bpc_automute(codec);
+}
+
+static void alc262_hp_wildwest_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int presence;
+	presence = snd_hda_codec_read(codec, 0x15, 0,
+				      AC_VERB_GET_PIN_SENSE, 0);
+	spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+	alc262_hp_master_update(codec);
+}
+
+static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_hp_wildwest_automute(codec);
+}
+
+static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	*ucontrol->value.integer.value = spec->master_sw;
+	return 0;
+}
+
+static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct alc_spec *spec = codec->spec;
+	int val = !!*ucontrol->value.integer.value;
+
+	if (val == spec->master_sw)
+		return 0;
+	spec->master_sw = val;
+	alc262_hp_master_update(codec);
+	return 1;
+}
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc262_hp_master_sw_get,
+		.put = alc262_hp_master_sw_put,
+	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
-
+	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
+			      HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
+			    HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -7684,12 +8173,21 @@
 };
 
 static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_ctl_boolean_mono_info,
+		.get = alc262_hp_master_sw_get,
+		.put = alc262_hp_master_sw_put,
+	},
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
+			      HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
+			    HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
@@ -7709,6 +8207,85 @@
 	{ } /* end */
 };
 
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (force || !spec->sense_updated) {
+		unsigned int present;
+		present = snd_hda_codec_read(codec, 0x15, 0,
+					     AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+		spec->sense_updated = 1;
+	}
+	snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+				 spec->jack_present ? HDA_AMP_MUTE : 0);
+}
+
+static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
+					unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_hp_t5735_automute(codec, 1);
+}
+
+static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
+{
+	alc262_hp_t5735_automute(codec, 1);
+}
+
+static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_verb alc262_hp_t5735_verbs[] = {
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{ }
+};
+
+static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct hda_verb alc262_hp_rp5700_verbs[] = {
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
+	{}
+};
+
+static struct hda_input_mux alc262_hp_rp5700_capture_source = {
+	.num_items = 1,
+	.items = {
+		{ "Line", 0x1 },
+	},
+};
+
 /* bind hp and internal speaker mute (with plug check) */
 static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_value *ucontrol)
@@ -8082,16 +8659,82 @@
 	{}
 };
 
-/* add playback controls from the parsed DAC table */
-static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
-					     const struct auto_pin_cfg *cfg)
-{
-	hda_nid_t nid;
-	int err;
+/* Samsung Q1 Ultra Vista model setup */
+static struct snd_kcontrol_new alc262_ultra_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+	{ } /* end */
+};
 
-	spec->multiout.num_dacs = 1;	/* only use one dac */
-	spec->multiout.dac_nids = spec->private_dac_nids;
-	spec->multiout.dac_nids[0] = 2;
+static struct hda_verb alc262_ultra_verbs[] = {
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* Mic is on Node 0x19 */
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+	{0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+	{}
+};
+
+static struct hda_input_mux alc262_ultra_capture_source = {
+	.num_items = 1,
+	.items = {
+		{ "Mic", 0x1 },
+	},
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_ultra_automute(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute;
+	unsigned int present;
+
+	/* need to execute and sync at first */
+	snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
+	present = snd_hda_codec_read(codec, 0x15, 0,
+				     AC_VERB_GET_PIN_SENSE, 0);
+	spec->jack_present = (present & 0x80000000) != 0;
+	if (spec->jack_present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+	}
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_ultra_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc262_ultra_automute(codec);
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	hda_nid_t nid;
+	int err;
+
+	spec->multiout.num_dacs = 1;	/* only use one dac */
+	spec->multiout.dac_nids = spec->private_dac_nids;
+	spec->multiout.dac_nids[0] = 2;
 
 	nid = cfg->line_out_pins[0];
 	if (nid) {
@@ -8269,7 +8912,7 @@
 	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 
@@ -8311,6 +8954,8 @@
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
 
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+
 	{ }
 };
 
@@ -8405,6 +9050,8 @@
         /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
 	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
 
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+
 	{ }
 };
 
@@ -8469,9 +9116,12 @@
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc262_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc262_auto_init_multi_out(codec);
 	alc262_auto_init_hp_out(codec);
 	alc262_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
@@ -8484,39 +9134,50 @@
 	[ALC262_FUJITSU]	= "fujitsu",
 	[ALC262_HP_BPC]		= "hp-bpc",
 	[ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
+	[ALC262_HP_TC_T5735]	= "hp-tc-t5735",
+	[ALC262_HP_RP5700]	= "hp-rp5700",
 	[ALC262_BENQ_ED8]	= "benq",
 	[ALC262_BENQ_T31]	= "benq-t31",
 	[ALC262_SONY_ASSAMD]	= "sony-assamd",
+	[ALC262_ULTRA]		= "ultra",
 	[ALC262_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc262_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
 	SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
-	SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
-	SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
-	SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
-	SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
-	SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
 	SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
-	SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
-	SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
-	SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
 	SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
 	SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
 	SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
 	SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
+	SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+	SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
+		      ALC262_HP_TC_T5735),
+	SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
+	SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
+	SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+	SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+	SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
 	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
-	SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
+	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
+	SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
 	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
 	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
-	SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-	SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
-	SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-	SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+	SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
 	{}
 };
 
@@ -8579,6 +9240,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_capture_source,
+		.unsol_event = alc262_hp_bpc_unsol_event,
+		.init_hook = alc262_hp_bpc_automute,
 	},
 	[ALC262_HP_BPC_D7000_WF] = {
 		.mixers = { alc262_HP_BPC_WildWest_mixer },
@@ -8589,6 +9252,8 @@
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_D7000_capture_source,
+		.unsol_event = alc262_hp_wildwest_unsol_event,
+		.init_hook = alc262_hp_wildwest_automute,
 	},
 	[ALC262_HP_BPC_D7000_WL] = {
 		.mixers = { alc262_HP_BPC_WildWest_mixer,
@@ -8600,7 +9265,30 @@
 		.num_channel_mode = ARRAY_SIZE(alc262_modes),
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_HP_D7000_capture_source,
+		.unsol_event = alc262_hp_wildwest_unsol_event,
+		.init_hook = alc262_hp_wildwest_automute,
 	},
+	[ALC262_HP_TC_T5735] = {
+		.mixers = { alc262_hp_t5735_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_capture_source,
+		.unsol_event = alc262_hp_t5735_unsol_event,
+		.init_hook = alc262_hp_t5735_init_hook,
+	},
+	[ALC262_HP_RP5700] = {
+		.mixers = { alc262_hp_rp5700_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_hp_rp5700_capture_source,
+        },
 	[ALC262_BENQ_ED8] = {
 		.mixers = { alc262_base_mixer },
 		.init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
@@ -8635,6 +9323,19 @@
 		.unsol_event = alc262_hippo_unsol_event,
 		.init_hook = alc262_hippo_automute,
 	},	
+	[ALC262_ULTRA] = {
+		.mixers = { alc262_ultra_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC262_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_ultra_capture_source,
+		.unsol_event = alc262_ultra_unsol_event,
+		.init_hook = alc262_ultra_automute,
+	},
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -8705,17 +9406,21 @@
 		if (wcap != AC_WID_AUD_IN) {
 			spec->adc_nids = alc262_adc_nids_alt;
 			spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
+			spec->capsrc_nids = alc262_capsrc_nids_alt;
 			spec->mixers[spec->num_mixers] =
 				alc262_capture_alt_mixer;
 			spec->num_mixers++;
 		} else {
 			spec->adc_nids = alc262_adc_nids;
 			spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
+			spec->capsrc_nids = alc262_capsrc_nids;
 			spec->mixers[spec->num_mixers] = alc262_capture_mixer;
 			spec->num_mixers++;
 		}
 	}
 
+	spec->vmaster_nid = 0x0c;
+
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC262_AUTO)
 		spec->init_hook = alc262_auto_init;
@@ -8748,6 +9453,8 @@
 	0x08
 };
 
+static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
+
 static struct snd_kcontrol_new alc268_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
@@ -8873,6 +9580,107 @@
 	alc268_acer_automute(codec, 1);
 }
 
+static struct snd_kcontrol_new alc268_dell_mixer[] = {
+	/* output mixer control */
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+	{ }
+};
+
+static struct hda_verb alc268_dell_verbs[] = {
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{ }
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc268_dell_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+	unsigned int mute;
+
+	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
+	if (present & 0x80000000)
+		mute = HDA_AMP_MUTE;
+	else
+		mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+	snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+				 HDA_AMP_MUTE, mute);
+}
+
+static void alc268_dell_unsol_event(struct hda_codec *codec,
+				    unsigned int res)
+{
+	if ((res >> 26) != ALC880_HP_EVENT)
+		return;
+	alc268_dell_automute(codec);
+}
+
+#define alc268_dell_init_hook	alc268_dell_automute
+
+static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+	{ }
+};
+
+static struct hda_verb alc267_quanta_il1_verbs[] = {
+	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+	{ }
+};
+
+static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
+		& AC_PINSENSE_PRESENCE;
+	snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    present ? 0 : PIN_OUT);
+}
+
+static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x18, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_write(codec, 0x23, 0,
+			    AC_VERB_SET_CONNECT_SEL,
+			    present ? 0x00 : 0x01);
+}
+
+static void alc267_quanta_il1_automute(struct hda_codec *codec)
+{
+	alc267_quanta_il1_hp_automute(codec);
+	alc267_quanta_il1_mic_automute(codec);
+}
+
+static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
+					   unsigned int res)
+{
+	switch (res >> 26) {
+	case ALC880_HP_EVENT:
+		alc267_quanta_il1_hp_automute(codec);
+		break;
+	case ALC880_MIC_EVENT:
+		alc267_quanta_il1_mic_automute(codec);
+		break;
+	}
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -8915,19 +9723,13 @@
 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
 
-	/* FIXME: use matrix-type input source selection */
-	/* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */
-	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-	/* Input mixer2 */
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+	/* Unmute Selector 23h,24h and set the default input to mic-in */
+	
+	{0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
 	{ }
 };
 
@@ -8966,36 +9768,7 @@
 
 #define alc268_mux_enum_info alc_mux_enum_info
 #define alc268_mux_enum_get alc_mux_enum_get
-
-static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-                snd_hda_codec_write_cache(codec, nid, 0,
-					  AC_VERB_SET_CONNECT_SEL,
-					  idx );
-	}
-	*cur_val = idx;
-	return 1;
-}
+#define alc268_mux_enum_put alc_mux_enum_put
 
 static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
@@ -9004,7 +9777,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -9025,7 +9797,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -9047,6 +9818,56 @@
 	},
 };
 
+#ifdef CONFIG_SND_DEBUG
+static struct snd_kcontrol_new alc268_test_mixer[] = {
+	/* Volume widgets */
+	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
+	HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
+	HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
+	HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
+	HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
+	HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
+	/* The below appears problematic on some hardwares */
+	/*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
+	HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
+
+	/* Modes for retasking pin widgets */
+	ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
+
+	/* Controls for GPIO pins, assuming they are configured as outputs */
+	ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+	ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+	ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+	ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+
+	/* Switches to allow the digital SPDIF output pin to be enabled.
+	 * The ALC268 does not have an SPDIF input.
+	 */
+	ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
+
+	/* A switch allowing EAPD to be enabled.  Some laptops seem to use
+	 * this output to turn on an external amplifier.
+	 */
+	ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
+	ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
+
+	{ } /* end */
+};
+#endif
+
 /* create input playback/capture controls for the given pin */
 static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
 				    const char *ctlname, int idx)
@@ -9194,6 +10015,7 @@
 /* pcm configuration: identiacal with ALC880 */
 #define alc268_pcm_analog_playback	alc880_pcm_analog_playback
 #define alc268_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc268_pcm_analog_alt_capture	alc880_pcm_analog_alt_capture
 #define alc268_pcm_digital_playback	alc880_pcm_digital_playback
 
 /*
@@ -9246,34 +10068,65 @@
 /* init callback for auto-configuration model -- overriding the default init */
 static void alc268_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc268_auto_init_multi_out(codec);
 	alc268_auto_init_hp_out(codec);
 	alc268_auto_init_mono_speaker_out(codec);
 	alc268_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 /*
  * configuration and preset
  */
 static const char *alc268_models[ALC268_MODEL_LAST] = {
+	[ALC267_QUANTA_IL1]	= "quanta-il1",
 	[ALC268_3ST]		= "3stack",
 	[ALC268_TOSHIBA]	= "toshiba",
 	[ALC268_ACER]		= "acer",
+	[ALC268_DELL]		= "dell",
+	[ALC268_ZEPTO]		= "zepto",
+#ifdef CONFIG_SND_DEBUG
+	[ALC268_TEST]		= "test",
+#endif
 	[ALC268_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc268_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
+	SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
+	SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
+	SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
+	SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
+	SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+	SND_PCI_QUIRK(0x1179, 0xff00, "TOSHIBA Satellite Pro A200", ALC268_TOSHIBA),
+	SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA Satellite Pro A210", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
-	SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
-	SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
-	SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
 	SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
+	SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
+	SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
 	{}
 };
 
 static struct alc_config_preset alc268_presets[] = {
+	[ALC267_QUANTA_IL1] = {
+		.mixers = { alc267_quanta_il1_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc267_quanta_il1_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_capture_source,
+		.unsol_event = alc267_quanta_il1_unsol_event,
+		.init_hook = alc267_quanta_il1_automute,
+	},
 	[ALC268_3ST] = {
 		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
 		.init_verbs = { alc268_base_init_verbs },
@@ -9281,6 +10134,7 @@
 		.dac_nids = alc268_dac_nids,
                 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
                 .adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x03,
 		.dig_out_nid = ALC268_DIGOUT_NID,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
@@ -9295,6 +10149,7 @@
 		.dac_nids = alc268_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
 		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x03,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
@@ -9310,6 +10165,7 @@
 		.dac_nids = alc268_dac_nids,
 		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
 		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
 		.hp_nid = 0x02,
 		.num_channel_mode = ARRAY_SIZE(alc268_modes),
 		.channel_mode = alc268_modes,
@@ -9317,33 +10173,458 @@
 		.unsol_event = alc268_acer_unsol_event,
 		.init_hook = alc268_acer_init_hook,
 	},
+	[ALC268_DELL] = {
+		.mixers = { alc268_dell_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc268_dell_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.hp_nid = 0x02,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.unsol_event = alc268_dell_unsol_event,
+		.init_hook = alc268_dell_init_hook,
+		.input_mux = &alc268_capture_source,
+	},
+	[ALC268_ZEPTO] = {
+		.mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc268_toshiba_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC268_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_capture_source,
+		.unsol_event = alc268_toshiba_unsol_event,
+		.init_hook = alc268_toshiba_automute
+	},
+#ifdef CONFIG_SND_DEBUG
+	[ALC268_TEST] = {
+		.mixers = { alc268_test_mixer, alc268_capture_mixer },
+		.init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+				alc268_volume_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc268_dac_nids),
+		.dac_nids = alc268_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+		.adc_nids = alc268_adc_nids_alt,
+		.capsrc_nids = alc268_capsrc_nids,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC268_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc268_modes),
+		.channel_mode = alc268_modes,
+		.input_mux = &alc268_capture_source,
+	},
+#endif
+};
+
+static int patch_alc268(struct hda_codec *codec)
+{
+	struct alc_spec *spec;
+	int board_config;
+	int err;
+
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
+						  alc268_models,
+						  alc268_cfg_tbl);
+
+	if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
+		printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+		       "trying auto-probe from BIOS...\n");
+		board_config = ALC268_AUTO;
+	}
+
+	if (board_config == ALC268_AUTO) {
+		/* automatic parse from the BIOS config */
+		err = alc268_parse_auto_config(codec);
+		if (err < 0) {
+			alc_free(codec);
+			return err;
+		} else if (!err) {
+			printk(KERN_INFO
+			       "hda_codec: Cannot set up configuration "
+			       "from BIOS.  Using base mode...\n");
+			board_config = ALC268_3ST;
+		}
+	}
+
+	if (board_config != ALC268_AUTO)
+		setup_preset(spec, &alc268_presets[board_config]);
+
+	spec->stream_name_analog = "ALC268 Analog";
+	spec->stream_analog_playback = &alc268_pcm_analog_playback;
+	spec->stream_analog_capture = &alc268_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
+
+	spec->stream_name_digital = "ALC268 Digital";
+	spec->stream_digital_playback = &alc268_pcm_digital_playback;
+
+	if (!spec->adc_nids && spec->input_mux) {
+		/* check whether NID 0x07 is valid */
+		unsigned int wcap = get_wcaps(codec, 0x07);
+		int i;
+
+		/* get type */
+		wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+		if (wcap != AC_WID_AUD_IN) {
+			spec->adc_nids = alc268_adc_nids_alt;
+			spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
+			spec->mixers[spec->num_mixers] =
+					alc268_capture_alt_mixer;
+			spec->num_mixers++;
+		} else {
+			spec->adc_nids = alc268_adc_nids;
+			spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
+			spec->mixers[spec->num_mixers] =
+				alc268_capture_mixer;
+			spec->num_mixers++;
+		}
+		spec->capsrc_nids = alc268_capsrc_nids;
+		/* set default input source */
+		for (i = 0; i < spec->num_adc_nids; i++)
+			snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
+				0, AC_VERB_SET_CONNECT_SEL,
+				spec->input_mux->items[0].index);
+	}
+
+	spec->vmaster_nid = 0x02;
+
+	codec->patch_ops = alc_patch_ops;
+	if (board_config == ALC268_AUTO)
+		spec->init_hook = alc268_auto_init;
+		
+	return 0;
+}
+
+/*
+ *  ALC269 channel source setting (2 channel)
+ */
+#define ALC269_DIGOUT_NID	ALC880_DIGOUT_NID
+
+#define alc269_dac_nids		alc260_dac_nids
+
+static hda_nid_t alc269_adc_nids[1] = {
+	/* ADC1 */
+	0x07,
+};
+
+#define alc269_modes		alc260_modes
+#define alc269_capture_source	alc880_lg_lw_capture_source
+
+static struct snd_kcontrol_new alc269_base_mixer[] = {
+	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
+/* capture mixer elements */
+static struct snd_kcontrol_new alc269_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = alc_mux_enum_info,
+		.get = alc_mux_enum_get,
+		.put = alc_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc269_init_verbs[] = {
+	/*
+	 * Unmute ADC0 and set the default input to mic-in
+	 */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	/* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
+	 * analog-loopback mixer widget
+	 * Note: PASD motherboards uses the Line In 2 as the input for
+	 * front panel mic (mic 2)
+	 */
+	/* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+	/*
+	 * Set up output mixers (0x0c - 0x0e)
+	 */
+	/* set vol=0 to output mixers */
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* set up input amps for analog loopback */
+	/* Amp Indices: DAC = 0, mixer = 1 */
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+	{0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* FIXME: use matrix-type input source selection */
+	/* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
+	/* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+	/* set EAPD */
+	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+	{ }
+};
+
+/* add playback controls from the parsed DAC table */
+static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	hda_nid_t nid;
+	int err;
+
+	spec->multiout.num_dacs = 1;	/* only use one dac */
+	spec->multiout.dac_nids = spec->private_dac_nids;
+	spec->multiout.dac_nids[0] = 2;
+
+	nid = cfg->line_out_pins[0];
+	if (nid) {
+		err = add_control(spec, ALC_CTL_WIDGET_VOL,
+				  "Front Playback Volume",
+				  HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
+		if (err < 0)
+			return err;
+		err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+				  "Front Playback Switch",
+				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+		if (err < 0)
+			return err;
+	}
+
+	nid = cfg->speaker_pins[0];
+	if (nid) {
+		if (!cfg->line_out_pins[0]) {
+			err = add_control(spec, ALC_CTL_WIDGET_VOL,
+					  "Speaker Playback Volume",
+					  HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
+							      HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+		if (nid == 0x16) {
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+					  "Speaker Playback Switch",
+					  HDA_COMPOSE_AMP_VAL(nid, 2, 0,
+							      HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else {
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+					  "Speaker Playback Switch",
+					  HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+							      HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+	nid = cfg->hp_pins[0];
+	if (nid) {
+		/* spec->multiout.hp_nid = 2; */
+		if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
+			err = add_control(spec, ALC_CTL_WIDGET_VOL,
+					  "Headphone Playback Volume",
+					  HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
+							      HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+		if (nid == 0x16) {
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+					  "Headphone Playback Switch",
+					  HDA_COMPOSE_AMP_VAL(nid, 2, 0,
+							      HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else {
+			err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+					  "Headphone Playback Switch",
+					  HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+							      HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+	return 0;
+}
+
+#define alc269_auto_create_analog_input_ctls \
+	alc880_auto_create_analog_input_ctls
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc269_loopbacks	alc880_loopbacks
+#endif
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc269_pcm_analog_playback	alc880_pcm_analog_playback
+#define alc269_pcm_analog_capture	alc880_pcm_analog_capture
+#define alc269_pcm_digital_playback	alc880_pcm_digital_playback
+#define alc269_pcm_digital_capture	alc880_pcm_digital_capture
+
+/*
+ * BIOS auto configuration
+ */
+static int alc269_parse_auto_config(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	int err;
+	static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+					   alc269_ignore);
+	if (err < 0)
+		return err;
+
+	err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
+	spec->num_mux_defs = 1;
+	spec->input_mux = &spec->private_imux;
+
+	err = alc_auto_add_mic_boost(codec);
+	if (err < 0)
+		return err;
+
+	return 1;
+}
+
+#define alc269_auto_init_multi_out	alc882_auto_init_multi_out
+#define alc269_auto_init_hp_out		alc882_auto_init_hp_out
+#define alc269_auto_init_analog_input	alc882_auto_init_analog_input
+
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc269_auto_init(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	alc269_auto_init_multi_out(codec);
+	alc269_auto_init_hp_out(codec);
+	alc269_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc269_models[ALC269_MODEL_LAST] = {
+	[ALC269_BASIC]		= "basic",
+};
+
+static struct snd_pci_quirk alc269_cfg_tbl[] = {
+	{}
+};
+
+static struct alc_config_preset alc269_presets[] = {
+	[ALC269_BASIC] = {
+		.mixers = { alc269_base_mixer },
+		.init_verbs = { alc269_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
+		.dac_nids = alc269_dac_nids,
+		.hp_nid = 0x03,
+		.num_channel_mode = ARRAY_SIZE(alc269_modes),
+		.channel_mode = alc269_modes,
+		.input_mux = &alc269_capture_source,
+	},
 };
 
-static int patch_alc268(struct hda_codec *codec)
+static int patch_alc269(struct hda_codec *codec)
 {
 	struct alc_spec *spec;
 	int board_config;
 	int err;
 
-	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
 	codec->spec = spec;
 
-	board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
-						  alc268_models,
-						  alc268_cfg_tbl);
+	board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
+						  alc269_models,
+						  alc269_cfg_tbl);
 
-	if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
-		printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+	if (board_config < 0) {
+		printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
 		       "trying auto-probe from BIOS...\n");
-		board_config = ALC268_AUTO;
+		board_config = ALC269_AUTO;
 	}
 
-	if (board_config == ALC268_AUTO) {
+	if (board_config == ALC269_AUTO) {
 		/* automatic parse from the BIOS config */
-		err = alc268_parse_auto_config(codec);
+		err = alc269_parse_auto_config(codec);
 		if (err < 0) {
 			alc_free(codec);
 			return err;
@@ -9351,48 +10632,34 @@
 			printk(KERN_INFO
 			       "hda_codec: Cannot set up configuration "
 			       "from BIOS.  Using base mode...\n");
-			board_config = ALC268_3ST;
+			board_config = ALC269_BASIC;
 		}
 	}
 
-	if (board_config != ALC268_AUTO)
-		setup_preset(spec, &alc268_presets[board_config]);
+	if (board_config != ALC269_AUTO)
+		setup_preset(spec, &alc269_presets[board_config]);
 
-	spec->stream_name_analog = "ALC268 Analog";
-	spec->stream_analog_playback = &alc268_pcm_analog_playback;
-	spec->stream_analog_capture = &alc268_pcm_analog_capture;
+	spec->stream_name_analog = "ALC269 Analog";
+	spec->stream_analog_playback = &alc269_pcm_analog_playback;
+	spec->stream_analog_capture = &alc269_pcm_analog_capture;
 
-	spec->stream_name_digital = "ALC268 Digital";
-	spec->stream_digital_playback = &alc268_pcm_digital_playback;
+	spec->stream_name_digital = "ALC269 Digital";
+	spec->stream_digital_playback = &alc269_pcm_digital_playback;
+	spec->stream_digital_capture = &alc269_pcm_digital_capture;
+
+	spec->adc_nids = alc269_adc_nids;
+	spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
+	spec->mixers[spec->num_mixers] = alc269_capture_mixer;
+	spec->num_mixers++;
 
-	if (board_config == ALC268_AUTO) {
-		if (!spec->adc_nids && spec->input_mux) {
-			/* check whether NID 0x07 is valid */
-			unsigned int wcap = get_wcaps(codec, 0x07);
-
-			/* get type */
-			wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-			if (wcap != AC_WID_AUD_IN) {
-				spec->adc_nids = alc268_adc_nids_alt;
-				spec->num_adc_nids =
-					ARRAY_SIZE(alc268_adc_nids_alt);
-				spec->mixers[spec->num_mixers] =
-					alc268_capture_alt_mixer;
-				spec->num_mixers++;
-			} else {
-				spec->adc_nids = alc268_adc_nids;
-				spec->num_adc_nids =
-					ARRAY_SIZE(alc268_adc_nids);
-				spec->mixers[spec->num_mixers] =
-					alc268_capture_mixer;
-				spec->num_mixers++;
-			}
-		}
-	}
 	codec->patch_ops = alc_patch_ops;
-	if (board_config == ALC268_AUTO)
-		spec->init_hook = alc268_auto_init;
-		
+	if (board_config == ALC269_AUTO)
+		spec->init_hook = alc269_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	if (!spec->loopback.amplist)
+		spec->loopback.amplist = alc269_loopbacks;
+#endif
+
 	return 0;
 }
 
@@ -10213,7 +11480,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 *FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -10229,13 +11495,7 @@
 					      hda_nid_t nid,
 					      int pin_type, int dac_idx)
 {
-	/* set as output */
-
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_type);
-	snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-			    AMP_OUT_UNMUTE);
-
+	alc_set_pin_output(codec, nid, pin_type);
 }
 
 static void alc861_auto_init_multi_out(struct hda_codec *codec)
@@ -10262,6 +11522,9 @@
 	if (pin) /* connect to front */
 		alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
 						  spec->multiout.dac_nids[0]);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
@@ -10334,9 +11597,12 @@
 /* additional initialization for auto-configuration model */
 static void alc861_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc861_auto_init_multi_out(codec);
 	alc861_auto_init_hp_out(codec);
 	alc861_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -10369,22 +11635,23 @@
 	SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
-	SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
-	SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+	SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
 	SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
 	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
 	/* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
 	 *        Any other models that need this preset?
 	 */
 	/* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
-	SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
-	SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31),
+	SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+	SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
 	SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
+	SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+	SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
+	/* FIXME: the below seems conflict */
+	/* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
 	SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
 	SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
-	SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
-	SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
 	{}
 };
 
@@ -10543,6 +11810,8 @@
 	spec->stream_digital_playback = &alc861_pcm_digital_playback;
 	spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
+	spec->vmaster_nid = 0x03;
+
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC861_AUTO)
 		spec->init_hook = alc861_auto_init;
@@ -10585,6 +11854,8 @@
 	0x09,
 };
 
+static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
 static struct hda_input_mux alc861vd_capture_source = {
@@ -10616,33 +11887,8 @@
 
 #define alc861vd_mux_enum_info alc_mux_enum_info
 #define alc861vd_mux_enum_get alc_mux_enum_get
-
-static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[1] = { 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
+/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
+#define alc861vd_mux_enum_put alc882_mux_enum_put
 
 /*
  * 2ch mode
@@ -10697,7 +11943,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 *FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -11102,21 +12347,20 @@
 };
 
 static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
+	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
 	SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
 	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
 	SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
-	SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
-
+	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
 	/*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
 	SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
-	SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
-	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
-	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
 	SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
 	SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
+	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
+	SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
 	SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
-	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
 	{}
 };
 
@@ -11127,8 +12371,6 @@
 				 alc861vd_3stack_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
 		.dac_nids = alc660vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
@@ -11140,8 +12382,6 @@
 		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
 		.dac_nids = alc660vd_dac_nids,
 		.dig_out_nid = ALC861VD_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
@@ -11186,8 +12426,6 @@
 				alc861vd_lenovo_unsol_verbs },
 		.num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
 		.dac_nids = alc660vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_capture_source,
@@ -11199,8 +12437,6 @@
 		.init_verbs = { alc861vd_dallas_verbs },
 		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
 		.dac_nids = alc861vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_dallas_capture_source,
@@ -11212,9 +12448,7 @@
 		.init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
 		.num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
 		.dac_nids = alc861vd_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
 		.dig_out_nid = ALC861VD_DIGOUT_NID,
-		.adc_nids = alc861vd_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
 		.channel_mode = alc861vd_3stack_2ch_modes,
 		.input_mux = &alc861vd_hp_capture_source,
@@ -11229,11 +12463,7 @@
 static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
 				hda_nid_t nid, int pin_type, int dac_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0,
-				AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
-	snd_hda_codec_write(codec, nid, 0,
-				AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 }
 
 static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
@@ -11260,6 +12490,9 @@
 	pin = spec->autocfg.hp_pins[0];
 	if (pin) /* connect to front and  use dac 0 */
 		alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc861vd_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -11463,9 +12696,12 @@
 /* additional initialization for auto-configuration model */
 static void alc861vd_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc861vd_auto_init_multi_out(codec);
 	alc861vd_auto_init_hp_out(codec);
 	alc861vd_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc861vd(struct hda_codec *codec)
@@ -11516,10 +12752,13 @@
 
 	spec->adc_nids = alc861vd_adc_nids;
 	spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
+	spec->capsrc_nids = alc861vd_capsrc_nids;
 
 	spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
 	spec->num_mixers++;
 
+	spec->vmaster_nid = 0x02;
+
 	codec->patch_ops = alc_patch_ops;
 
 	if (board_config == ALC861VD_AUTO)
@@ -11555,9 +12794,11 @@
 	/* ADC1-2 */
 	0x09,
 };
+
+static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
+
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
-
 static struct hda_input_mux alc662_capture_source = {
 	.num_items = 4,
 	.items = {
@@ -11586,33 +12827,8 @@
 
 #define alc662_mux_enum_info alc_mux_enum_info
 #define alc662_mux_enum_get alc_mux_enum_get
+#define alc662_mux_enum_put alc882_mux_enum_put
 
-static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct alc_spec *spec = codec->spec;
-	const struct hda_input_mux *imux = spec->input_mux;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-	static hda_nid_t capture_mixers[2] = { 0x23, 0x22 };
-	hda_nid_t nid = capture_mixers[adc_idx];
-	unsigned int *cur_val = &spec->cur_mux[adc_idx];
-	unsigned int i, idx;
-
-	idx = ucontrol->value.enumerated.item[0];
-	if (idx >= imux->num_items)
-		idx = imux->num_items - 1;
-	if (*cur_val == idx)
-		return 0;
-	for (i = 0; i < imux->num_items; i++) {
-		unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-		snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-					 imux->items[i].index,
-					 HDA_AMP_MUTE, v);
-	}
-	*cur_val = idx;
-	return 1;
-}
 /*
  * 2ch mode
  */
@@ -11681,13 +12897,13 @@
 static struct snd_kcontrol_new alc662_base_mixer[] = {
 	/* output mixer control */
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Surround Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 
 	/*Input mixer control */
@@ -11699,24 +12915,12 @@
 	HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
-
-	/* Capture mixer control */
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc_mux_enum_info,
-		.get = alc_mux_enum_get,
-		.put = alc_mux_enum_put,
-	},
 	{ } /* end */
 };
 
 static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -11728,29 +12932,18 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc662_mux_enum_info,
-		.get = alc662_mux_enum_get,
-		.put = alc662_mux_enum_put,
-	},
 	{ } /* end */
 };
 
 static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
 	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -11762,49 +12955,27 @@
 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc662_mux_enum_info,
-		.get = alc662_mux_enum_get,
-		.put = alc662_mux_enum_put,
-	},
 	{ } /* end */
 };
 
 static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
-	HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 1,
-		.info = alc662_mux_enum_info,
-		.get = alc662_mux_enum_get,
-		.put = alc662_mux_enum_put,
-	},
 	{ } /* end */
 };
 
 static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
-	HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 
-	HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 
 	HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
 	HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -11816,6 +12987,24 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
+	HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
+	HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new alc662_chmode_mixer[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -11901,6 +13090,13 @@
 	{}
 };
 
+/* Set Unsolicited Event*/
+static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{}
+};
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -11957,14 +13153,13 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
 		.count = 1,
-		.info = alc882_mux_enum_info,
-		.get = alc882_mux_enum_get,
-		.put = alc882_mux_enum_put,
+		.info = alc662_mux_enum_info,
+		.get = alc662_mux_enum_get,
+		.put = alc662_mux_enum_put,
 	},
 	{ } /* end */
 };
@@ -12037,6 +13232,40 @@
 	alc662_eeepc_mic_automute(codec);
 }
 
+static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
+{
+	unsigned int mute;
+	unsigned int present;
+
+	snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
+	present = snd_hda_codec_read(codec, 0x14, 0,
+				     AC_VERB_GET_PIN_SENSE, 0);
+	present = (present & 0x80000000) != 0;
+	if (present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, HDA_AMP_MUTE);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+					 HDA_AMP_MUTE, mute);
+	}
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
+					  unsigned int res)
+{
+	if ((res >> 26) == ALC880_HP_EVENT)
+		alc662_eeepc_ep20_automute(codec);
+}
+
+static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
+{
+	alc662_eeepc_ep20_automute(codec);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks	alc880_loopbacks
 #endif
@@ -12057,12 +13286,16 @@
 	[ALC662_3ST_6ch]	= "3stack-6ch",
 	[ALC662_5ST_DIG]	= "6stack-dig",
 	[ALC662_LENOVO_101E]	= "lenovo-101e",
+	[ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
+	[ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
 	[ALC662_AUTO]		= "auto",
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
+	SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
 	SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
+	SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+	SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
 	{}
 };
 
@@ -12073,8 +13306,6 @@
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.dig_in_nid = ALC662_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
@@ -12087,8 +13318,6 @@
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.dig_in_nid = ALC662_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
@@ -12101,8 +13330,6 @@
 		.init_verbs = { alc662_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
 		.channel_mode = alc662_3ST_6ch_modes,
 		.need_dac_fix = 1,
@@ -12115,8 +13342,6 @@
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
 		.dig_out_nid = ALC662_DIGOUT_NID,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.dig_in_nid = ALC662_DIGIN_NID,
 		.num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
 		.channel_mode = alc662_5stack_modes,
@@ -12127,8 +13352,6 @@
 		.init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.input_mux = &alc662_lenovo_101e_capture_source,
@@ -12141,14 +13364,25 @@
 				alc662_eeepc_sue_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
 		.dac_nids = alc662_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
-		.adc_nids = alc662_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
 		.channel_mode = alc662_3ST_2ch_modes,
 		.input_mux = &alc662_eeepc_capture_source,
 		.unsol_event = alc662_eeepc_unsol_event,
 		.init_hook = alc662_eeepc_inithook,
 	},
+	[ALC662_ASUS_EEEPC_EP20] = {
+		.mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
+			    alc662_chmode_mixer },
+		.init_verbs = { alc662_init_verbs,
+				alc662_eeepc_ep20_sue_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc662_dac_nids),
+		.dac_nids = alc662_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+		.channel_mode = alc662_3ST_6ch_modes,
+		.input_mux = &alc662_lenovo_101e_capture_source,
+		.unsol_event = alc662_eeepc_ep20_unsol_event,
+		.init_hook = alc662_eeepc_ep20_inithook,
+	},
 
 };
 
@@ -12288,11 +13522,7 @@
 					      hda_nid_t nid, int pin_type,
 					      int dac_idx)
 {
-	/* set as output */
-	snd_hda_codec_write(codec, nid, 0,
-			    AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
-	snd_hda_codec_write(codec, nid, 0,
-			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+	alc_set_pin_output(codec, nid, pin_type);
 	/* need the manual connection? */
 	if (alc880_is_multi_pin(nid)) {
 		struct alc_spec *spec = codec->spec;
@@ -12308,6 +13538,7 @@
 	struct alc_spec *spec = codec->spec;
 	int i;
 
+	alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
 	for (i = 0; i <= HDA_SIDE; i++) {
 		hda_nid_t nid = spec->autocfg.line_out_pins[i];
 		int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -12326,6 +13557,9 @@
 	if (pin) /* connect to front */
 		/* use dac 0 */
 		alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
+	pin = spec->autocfg.speaker_pins[0];
+	if (pin)
+		alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 }
 
 #define alc662_is_input_pin(nid)	alc880_is_input_pin(nid)
@@ -12403,9 +13637,12 @@
 /* additional initialization for auto-configuration model */
 static void alc662_auto_init(struct hda_codec *codec)
 {
+	struct alc_spec *spec = codec->spec;
 	alc662_auto_init_multi_out(codec);
 	alc662_auto_init_hp_out(codec);
 	alc662_auto_init_analog_input(codec);
+	if (spec->unsol_event)
+		alc_sku_automute(codec);
 }
 
 static int patch_alc662(struct hda_codec *codec)
@@ -12453,10 +13690,11 @@
 	spec->stream_digital_playback = &alc662_pcm_digital_playback;
 	spec->stream_digital_capture = &alc662_pcm_digital_capture;
 
-	if (!spec->adc_nids && spec->input_mux) {
-		spec->adc_nids = alc662_adc_nids;
-		spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
-	}
+	spec->adc_nids = alc662_adc_nids;
+	spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
+	spec->capsrc_nids = alc662_capsrc_nids;
+
+	spec->vmaster_nid = 0x02;
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC662_AUTO)
@@ -12475,7 +13713,9 @@
 struct hda_codec_preset snd_hda_preset_realtek[] = {
 	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
 	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
+	{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
 	{ .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
+	{ .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
 	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
 	  .patch = patch_alc861 },
 	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
@@ -12490,5 +13730,6 @@
 	{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
 	{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
 	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
+	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
 	{} /* terminator */
 };
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_si3054.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_si3054.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_si3054.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_si3054.c	2008-09-28 23:33:40.000000000 +0200
@@ -22,7 +22,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -207,7 +206,7 @@
 	info->name = "Si3054 Modem";
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
-	info->is_modem = 1;
+	info->pcm_type = HDA_PCM_TYPE_MODEM;
 	return 0;
 }
 
@@ -287,7 +286,6 @@
 struct hda_codec_preset snd_hda_preset_si3054[] = {
  	{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
- 	{ .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 },
  	{ .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 },
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_sigmatel.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_sigmatel.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_sigmatel.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_sigmatel.c	2008-09-28 23:33:41.000000000 +0200
@@ -24,7 +24,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -35,10 +34,12 @@
 #include "hda_local.h"
 
 #define NUM_CONTROL_ALLOC	32
-#define STAC_HP_EVENT		0x37
+#define STAC_PWR_EVENT		0x20
+#define STAC_HP_EVENT		0x30
 
 enum {
 	STAC_REF,
+	STAC_9200_OQO,
 	STAC_9200_DELL_D21,
 	STAC_9200_DELL_D22,
 	STAC_9200_DELL_D23,
@@ -62,6 +63,19 @@
 };
 
 enum {
+	STAC_92HD73XX_REF,
+	STAC_DELL_M6,
+	STAC_92HD73XX_MODELS
+};
+
+enum {
+	STAC_92HD71BXX_REF,
+	STAC_DELL_M4_1,
+	STAC_DELL_M4_2,
+	STAC_92HD71BXX_MODELS
+};
+
+enum {
 	STAC_925x_REF,
 	STAC_M2_2,
 	STAC_MA6,
@@ -97,6 +111,7 @@
 	STAC_D965_3ST,
 	STAC_D965_5ST,
 	STAC_DELL_3ST,
+	STAC_DELL_BIOS,
 	STAC_927X_MODELS
 };
 
@@ -110,11 +125,25 @@
 	unsigned int mic_switch: 1;
 	unsigned int alt_switch: 1;
 	unsigned int hp_detect: 1;
-	unsigned int gpio_mute: 1;
 
-	unsigned int gpio_mask, gpio_data;
+	/* gpio lines */
+	unsigned int gpio_mask;
+	unsigned int gpio_dir;
+	unsigned int gpio_data;
+	unsigned int gpio_mute;
+
+	/* analog loopback */
+	unsigned char aloopback_mask;
+	unsigned char aloopback_shift;
+
+	/* power management */
+	unsigned int num_pwrs;
+	hda_nid_t *pwr_nids;
+	hda_nid_t *dac_list;
 
 	/* playback */
+	struct hda_input_mux *mono_mux;
+	unsigned int cur_mmux;
 	struct hda_multi_out multiout;
 	hda_nid_t dac_nids[5];
 
@@ -125,8 +154,10 @@
 	unsigned int num_muxes;
 	hda_nid_t *dmic_nids;
 	unsigned int num_dmics;
-	hda_nid_t dmux_nid;
+	hda_nid_t *dmux_nids;
+	unsigned int num_dmuxes;
 	hda_nid_t dig_in_nid;
+	hda_nid_t mono_nid;
 
 	/* pin widgets */
 	hda_nid_t *pin_nids;
@@ -140,7 +171,7 @@
 
 	/* capture source */
 	struct hda_input_mux *dinput_mux;
-	unsigned int cur_dmux;
+	unsigned int cur_dmux[2];
 	struct hda_input_mux *input_mux;
 	unsigned int cur_mux[3];
 
@@ -157,6 +188,10 @@
 	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_dimux;
 	struct hda_input_mux private_imux;
+	struct hda_input_mux private_mono_mux;
+
+	/* virtual master */
+	unsigned int vmaster_tlv[4];
 };
 
 static hda_nid_t stac9200_adc_nids[1] = {
@@ -171,6 +206,58 @@
         0x02,
 };
 
+static hda_nid_t stac92hd73xx_pwr_nids[8] = {
+	0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+	0x0f, 0x10, 0x11
+};
+
+static hda_nid_t stac92hd73xx_adc_nids[2] = {
+	0x1a, 0x1b
+};
+
+#define STAC92HD73XX_NUM_DMICS	2
+static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
+	0x13, 0x14, 0
+};
+
+#define STAC92HD73_DAC_COUNT 5
+static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
+	0x15, 0x16, 0x17, 0x18, 0x19,
+};
+
+static hda_nid_t stac92hd73xx_mux_nids[4] = {
+	0x28, 0x29, 0x2a, 0x2b,
+};
+
+static hda_nid_t stac92hd73xx_dmux_nids[2] = {
+	0x20, 0x21,
+};
+
+static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
+	0x0a, 0x0d, 0x0f
+};
+
+static hda_nid_t stac92hd71bxx_adc_nids[2] = {
+	0x12, 0x13,
+};
+
+static hda_nid_t stac92hd71bxx_mux_nids[2] = {
+	0x1a, 0x1b
+};
+
+static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
+	0x1c,
+};
+
+static hda_nid_t stac92hd71bxx_dac_nids[1] = {
+	0x10, /*0x11, */
+};
+
+#define STAC92HD71BXX_NUM_DMICS	2
+static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
+	0x18, 0x19, 0
+};
+
 static hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
@@ -188,6 +275,10 @@
 	0x15, 0
 };
 
+static hda_nid_t stac925x_dmux_nids[1] = {
+	0x14,
+};
+
 static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
@@ -204,6 +295,19 @@
         0x15, 0x16, 0x17
 };
 
+static hda_nid_t stac927x_dac_nids[6] = {
+	0x02, 0x03, 0x04, 0x05, 0x06, 0
+};
+
+static hda_nid_t stac927x_dmux_nids[1] = {
+	0x1b,
+};
+
+#define STAC927X_NUM_DMICS 2
+static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
+	0x13, 0x14, 0
+};
+
 static hda_nid_t stac9205_adc_nids[2] = {
         0x12, 0x13
 };
@@ -212,6 +316,10 @@
         0x19, 0x1a
 };
 
+static hda_nid_t stac9205_dmux_nids[1] = {
+	0x1d,
+};
+
 #define STAC9205_NUM_DMICS	2
 static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
@@ -232,6 +340,17 @@
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
 
+static hda_nid_t stac92hd73xx_pin_nids[13] = {
+	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x0f, 0x10, 0x11, 0x12, 0x13,
+	0x14, 0x1e, 0x22
+};
+
+static hda_nid_t stac92hd71bxx_pin_nids[10] = {
+	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+	0x0f, 0x14, 0x18, 0x19, 0x1e,
+};
+
 static hda_nid_t stac927x_pin_nids[14] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x12, 0x13,
@@ -257,8 +376,9 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
+	unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
-	ucontrol->value.enumerated.item[0] = spec->cur_dmux;
+	ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
 	return 0;
 }
 
@@ -267,9 +387,10 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
+	unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
 	return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
-				     spec->dmux_nid, &spec->cur_dmux);
+			spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
 }
 
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -299,15 +420,45 @@
 				     spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
 }
 
+static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+	return snd_hda_input_mux_info(spec->mono_mux, uinfo);
+}
+
+static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_mmux;
+	return 0;
+}
+
+static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
+				     spec->mono_nid, &spec->cur_mmux);
+}
+
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
 
 static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	struct sigmatel_spec *spec = codec->spec;
 
-	ucontrol->value.integer.value[0] = spec->aloopback;
+	ucontrol->value.integer.value[0] = !!(spec->aloopback &
+					      (spec->aloopback_mask << idx));
 	return 0;
 }
 
@@ -316,23 +467,33 @@
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
+	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 	unsigned int dac_mode;
+	unsigned int val, idx_val;
 
-	if (spec->aloopback == ucontrol->value.integer.value[0])
+	idx_val = spec->aloopback_mask << idx;
+	if (ucontrol->value.integer.value[0])
+		val = spec->aloopback | idx_val;
+	else
+		val = spec->aloopback & ~idx_val;
+	if (spec->aloopback == val)
 		return 0;
 
-	spec->aloopback = ucontrol->value.integer.value[0];
-
+	spec->aloopback = val;
 
+	/* Only return the bits defined by the shift value of the
+	 * first two bytes of the mask
+	 */
 	dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
-		kcontrol->private_value & 0xFFFF, 0x0);
+				      kcontrol->private_value & 0xFFFF, 0x0);
+	dac_mode >>= spec->aloopback_shift;
 
-	if (spec->aloopback) {
+	if (spec->aloopback & idx_val) {
 		snd_hda_power_up(codec);
-		dac_mode |= 0x40;
+		dac_mode |= idx_val;
 	} else {
 		snd_hda_power_down(codec);
-		dac_mode &= ~0x40;
+		dac_mode &= ~idx_val;
 	}
 
 	snd_hda_codec_write_cache(codec, codec->afg, 0,
@@ -354,6 +515,125 @@
 	{}
 };
 
+static struct hda_verb stac92hd73xx_6ch_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* setup audio connections */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* setup adcs to point to mixer */
+	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	/* setup import muxs */
+	{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{}
+};
+
+static struct hda_verb dell_m6_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* setup audio connections */
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* setup adcs to point to mixer */
+	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	/* setup import muxs */
+	{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{}
+};
+
+static struct hda_verb stac92hd73xx_8ch_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* setup audio connections */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
+	/* connect hp ports to dac3 */
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
+	/* setup adcs to point to mixer */
+	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	/* setup import muxs */
+	{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
+	{}
+};
+
+static struct hda_verb stac92hd73xx_10ch_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* setup audio connections */
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
+	{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
+	/* dac3 is connected to import3 mux */
+	{ 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
+	/* connect hp ports to dac4 */
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
+	/* setup adcs to point to mixer */
+	{ 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{ 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{ 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	/* setup import muxs */
+	{ 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
+	{}
+};
+
+static struct hda_verb stac92hd71bxx_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* connect headphone jack to dac1 */
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
+	/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+};
+
+static struct hda_verb stac92hd71bxx_analog_core_init[] = {
+	/* set master volume and direct control */
+	{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+	/* connect headphone jack to dac1 */
+	{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	/* connect ports 0d and 0f to audio mixer */
+	{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
+	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
+	{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
+	/* unmute dac0 input in audio mixer */
+	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
+	/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+	{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{}
+};
+
 static struct hda_verb stac925x_core_init[] = {
 	/* set dac0mux for dac converter */
 	{ 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -388,6 +668,16 @@
 	{}
 };
 
+#define STAC_MONO_MUX \
+	{ \
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+		.name = "Mono Mux", \
+		.count = 1, \
+		.info = stac92xx_mono_mux_enum_info, \
+		.get = stac92xx_mono_mux_enum_get, \
+		.put = stac92xx_mono_mux_enum_put, \
+	}
+
 #define STAC_INPUT_SOURCE(cnt) \
 	{ \
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -398,11 +688,11 @@
 		.put = stac92xx_mux_enum_put, \
 	}
 
-#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \
+#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
 	{ \
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
 		.name  = "Analog Loopback", \
-		.count = 1, \
+		.count = cnt, \
 		.info  = stac92xx_aloopback_info, \
 		.get   = stac92xx_aloopback_get, \
 		.put   = stac92xx_aloopback_put, \
@@ -419,6 +709,114 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
+	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
+	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
+	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+	HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
+	HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
+	STAC_INPUT_SOURCE(2),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
+	HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+	{ } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
+	STAC_INPUT_SOURCE(2),
+	STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
+
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+	{ } /* end */
+};
+
 static struct snd_kcontrol_new stac925x_mixer[] = {
 	STAC_INPUT_SOURCE(1),
 	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
@@ -428,16 +826,8 @@
 };
 
 static struct snd_kcontrol_new stac9205_mixer[] = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Digital Input Source",
-		.count = 1,
-		.info = stac92xx_dmux_enum_info,
-		.get = stac92xx_dmux_enum_get,
-		.put = stac92xx_dmux_enum_put,
-	},
 	STAC_INPUT_SOURCE(2),
-	STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0),
+	STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
@@ -466,7 +856,7 @@
 
 static struct snd_kcontrol_new stac927x_mixer[] = {
 	STAC_INPUT_SOURCE(3),
-	STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB),
+	STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
 
 	HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
@@ -482,6 +872,44 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new stac_dmux_mixer = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Digital Input Source",
+	/* count set later */
+	.info = stac92xx_dmux_enum_info,
+	.get = stac92xx_dmux_enum_get,
+	.put = stac92xx_dmux_enum_put,
+};
+
+static const char *slave_vols[] = {
+	"Front Playback Volume",
+	"Surround Playback Volume",
+	"Center Playback Volume",
+	"LFE Playback Volume",
+	"Side Playback Volume",
+	"Headphone Playback Volume",
+	"Headphone Playback Volume",
+	"Speaker Playback Volume",
+	"External Speaker Playback Volume",
+	"Speaker2 Playback Volume",
+	NULL
+};
+
+static const char *slave_sws[] = {
+	"Front Playback Switch",
+	"Surround Playback Switch",
+	"Center Playback Switch",
+	"LFE Playback Switch",
+	"Side Playback Switch",
+	"Headphone Playback Switch",
+	"Headphone Playback Switch",
+	"Speaker Playback Switch",
+	"External Speaker Playback Switch",
+	"Speaker2 Playback Switch",
+	"IEC958 Playback Switch",
+	NULL
+};
+
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -497,17 +925,46 @@
 		if (err < 0)
 			return err;
 	}
+	if (spec->num_dmuxes > 0) {
+		stac_dmux_mixer.count = spec->num_dmuxes;
+		err = snd_ctl_add(codec->bus->card,
+				  snd_ctl_new1(&stac_dmux_mixer, codec));
+		if (err < 0)
+			return err;
+	}
 
 	if (spec->multiout.dig_out_nid) {
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
 		if (err < 0)
 			return err;
 	}
+
+	/* if we have no master control, let's create it */
+	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+		snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
+					HDA_OUTPUT, spec->vmaster_tlv);
+		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+					  spec->vmaster_tlv, slave_vols);
+		if (err < 0)
+			return err;
+	}
+	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+					  NULL, slave_sws);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;	
 }
 
@@ -627,9 +1084,15 @@
 	0x90170310, 0x04a11020, 0x90170310, 0x40f003fc,
 };
 
+static unsigned int oqo9200_pin_configs[8] = {
+	0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210,
+	0x90170111, 0x90a70120, 0x400000f2, 0x400000f3,
+};
+
 
 static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
 	[STAC_REF] = ref9200_pin_configs,
+	[STAC_9200_OQO] = oqo9200_pin_configs,
 	[STAC_9200_DELL_D21] = dell9200_d21_pin_configs,
 	[STAC_9200_DELL_D22] = dell9200_d22_pin_configs,
 	[STAC_9200_DELL_D23] = dell9200_d23_pin_configs,
@@ -644,6 +1107,7 @@
 
 static const char *stac9200_models[STAC_9200_MODELS] = {
 	[STAC_REF] = "ref",
+	[STAC_9200_OQO] = "oqo",
 	[STAC_9200_DELL_D21] = "dell-d21",
 	[STAC_9200_DELL_D22] = "dell-d22",
 	[STAC_9200_DELL_D23] = "dell-d23",
@@ -661,6 +1125,8 @@
 	/* SigmaTel reference board */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
 		      "DFI LanParty", STAC_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+		      "SigmaTel",STAC_9205_REF),
 	/* Dell laptops have BIOS problem */
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
 		      "unknown Dell", STAC_9200_DELL_D21),
@@ -728,12 +1194,14 @@
 		      STAC_9200_GATEWAY),
 	SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707",
 		      STAC_9200_GATEWAY),
+	/* OQO Mobile */
+	SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
 	{} /* terminator */
 };
 
 static unsigned int ref925x_pin_configs[8] = {
 	0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
-	0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
+	0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
 };
 
 static unsigned int stac925x_MA6_pin_configs[8] = {
@@ -777,6 +1245,110 @@
 	{} /* terminator */
 };
 
+static unsigned int ref92hd73xx_pin_configs[13] = {
+	0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
+	0x0181302e, 0x01014010, 0x01014020, 0x01014030,
+	0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
+	0x01452050,
+};
+
+static unsigned int dell_m6_pin_configs[13] = {
+	0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110,
+	0x03a11020, 0x03011050, 0x4f0000f0, 0x4f0000f0,
+	0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0,
+	0x4f0000f0,
+};
+
+static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
+	[STAC_92HD73XX_REF]	= ref92hd73xx_pin_configs,
+	[STAC_DELL_M6]	= dell_m6_pin_configs,
+};
+
+static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+	[STAC_92HD73XX_REF] = "ref",
+	[STAC_DELL_M6] = "dell-m6",
+};
+
+static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+				"DFI LanParty", STAC_92HD73XX_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
+				"unknown Dell", STAC_DELL_M6),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
+				"unknown Dell", STAC_DELL_M6),
+	{} /* terminator */
+};
+
+static unsigned int ref92hd71bxx_pin_configs[10] = {
+	0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
+	0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
+	0x90a000f0, 0x01452050,
+};
+
+static unsigned int dell_m4_1_pin_configs[13] = {
+	0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110,
+	0x23a1902e, 0x23014250, 0x40f000f0, 0x4f0000f0,
+	0x40f000f0, 0x4f0000f0,
+};
+
+static unsigned int dell_m4_2_pin_configs[13] = {
+	0x0421101f, 0x04a11221, 0x90a70330, 0x90170110,
+	0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0,
+	0x40f000f0, 0x044413b0,
+};
+
+static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
+	[STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
+	[STAC_DELL_M4_1]	= dell_m4_1_pin_configs,
+	[STAC_DELL_M4_2]	= dell_m4_2_pin_configs,
+};
+
+static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+	[STAC_92HD71BXX_REF] = "ref",
+	[STAC_DELL_M4_1] = "dell-m4-1",
+	[STAC_DELL_M4_2] = "dell-m4-2",
+};
+
+static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
+	/* SigmaTel reference board */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+		      "DFI LanParty", STAC_92HD71BXX_REF),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
+				"unknown Dell", STAC_DELL_M4_1),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
+				"unknown Dell", STAC_DELL_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
+				"unknown Dell", STAC_DELL_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
+				"unknown Dell", STAC_DELL_M4_2),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
+				"unknown Dell", STAC_DELL_M4_2),
+	{} /* terminator */
+};
+
 static unsigned int ref922x_pin_configs[10] = {
 	0x01014010, 0x01016011, 0x01012012, 0x0221401f,
 	0x01813122, 0x01011014, 0x01441030, 0x01c41030,
@@ -823,8 +1395,8 @@
     102801D7 (Dell XPS M1210)
 */
 static unsigned int dell_922x_m82_pin_configs[10] = {
-	0x0221121f, 0x408103ff, 0x02111212, 0x90100310, 
-	0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, 
+	0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 
+	0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 
 	0x508003f3, 0x405003f4, 
 };
 
@@ -1022,22 +1594,24 @@
 static unsigned int dell_3st_pin_configs[14] = {
 	0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
 	0x01111212, 0x01116211, 0x01813050, 0x01112214,
-	0x403003fa, 0x40000100, 0x40000100, 0x404003fb,
+	0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
 	0x40c003fc, 0x40000100
 };
 
 static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
-	[STAC_D965_REF] = ref927x_pin_configs,
-	[STAC_D965_3ST] = d965_3st_pin_configs,
-	[STAC_D965_5ST] = d965_5st_pin_configs,
-	[STAC_DELL_3ST] = dell_3st_pin_configs,
+	[STAC_D965_REF]  = ref927x_pin_configs,
+	[STAC_D965_3ST]  = d965_3st_pin_configs,
+	[STAC_D965_5ST]  = d965_5st_pin_configs,
+	[STAC_DELL_3ST]  = dell_3st_pin_configs,
+	[STAC_DELL_BIOS] = NULL,
 };
 
 static const char *stac927x_models[STAC_927X_MODELS] = {
-	[STAC_D965_REF]	= "ref",
-	[STAC_D965_3ST]	= "3stack",
-	[STAC_D965_5ST] = "5stack",
-	[STAC_DELL_3ST]	= "dell-3stack",
+	[STAC_D965_REF]		= "ref",
+	[STAC_D965_3ST]		= "3stack",
+	[STAC_D965_5ST]		= "5stack",
+	[STAC_DELL_3ST]		= "dell-3stack",
+	[STAC_DELL_BIOS]	= "dell-bios",
 };
 
 static struct snd_pci_quirk stac927x_cfg_tbl[] = {
@@ -1064,13 +1638,21 @@
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
-	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_D965_3ST),
 	/* Dell 3 stack systems */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
+	/* Dell 3 stack systems with verb table in BIOS */
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell     ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0242, "Dell     ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0243, "Dell     ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
 	/* 965 based 5 stack systems */
-	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_D965_5ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
@@ -1085,7 +1667,7 @@
 
 static unsigned int ref9205_pin_configs[12] = {
 	0x40000100, 0x40000100, 0x01016011, 0x01014010,
-	0x01813122, 0x01a19021, 0x40000100, 0x40000100,
+	0x01813122, 0x01a19021, 0x01019020, 0x40000100,
 	0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
 };
 
@@ -1097,6 +1679,7 @@
     102801FD
     10280204
     1028021F
+    10280228 (Dell Vostro 1500)
 */
 static unsigned int dell_9205_m42_pin_configs[12] = {
 	0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
@@ -1176,10 +1759,14 @@
 		      "Dell Inspiron", STAC_9205_DELL_M44),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
 		      "Dell Inspiron", STAC_9205_DELL_M44),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0200,
+		      "Dell D530", STAC_9205_DELL_M42),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
 		      "unknown Dell", STAC_9205_DELL_M42),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
 		      "Dell Inspiron", STAC_9205_DELL_M44),
+	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
+		      "Dell Vostro 1500", STAC_9205_DELL_M42),
 	{} /* terminator */
 };
 
@@ -1245,22 +1832,6 @@
 					spec->pin_configs[i]);
 }
 
-static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	/* Configure GPIOx as output */
-	snd_hda_codec_write_cache(codec, codec->afg, 0,
-				  AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
-	/* Configure GPIOx as CMOS */
-	snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
-	/* Assert GPIOx */
-	snd_hda_codec_write_cache(codec, codec->afg, 0,
-				  AC_VERB_SET_GPIO_DATA, spec->gpio_data);
-	/* Enable GPIOx */
-	snd_hda_codec_write_cache(codec, codec->afg, 0,
-				  AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
-}
-
 /*
  * Analog playback callbacks
  */
@@ -1269,7 +1840,8 @@
 				      struct snd_pcm_substream *substream)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -1425,6 +1997,7 @@
 		codec->num_pcms++;
 		info++;
 		info->name = "STAC92xx Digital";
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback;
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
@@ -1479,7 +2052,7 @@
 	struct sigmatel_spec *spec = codec->spec;
         hda_nid_t nid = kcontrol->private_value >> 8;
 	int io_idx = kcontrol-> private_value & 0xff;
-        unsigned short val = ucontrol->value.integer.value[0];
+	unsigned short val = !!ucontrol->value.integer.value[0];
 
 	spec->io_switch[io_idx] = val;
 
@@ -1491,6 +2064,13 @@
 			pinctl |= stac92xx_get_vref(codec, nid);
 		stac92xx_auto_set_pinctl(codec, nid, pinctl);
 	}
+
+	/* check the auto-mute again: we need to mute/unmute the speaker
+	 * appropriately according to the pin direction
+	 */
+	if (spec->hp_detect)
+		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+
         return 1;
 }
 
@@ -1512,11 +2092,12 @@
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
 	hda_nid_t nid = kcontrol->private_value & 0xff;
+	unsigned int val = !!ucontrol->value.integer.value[0];
 
-	if (spec->clfe_swap == ucontrol->value.integer.value[0])
+	if (spec->clfe_swap == val)
 		return 0;
 
-	spec->clfe_swap = ucontrol->value.integer.value[0];
+	spec->clfe_swap = val;
 
 	snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
 		spec->clfe_swap ? 0x4 : 0x0);
@@ -1547,6 +2128,7 @@
 enum {
 	STAC_CTL_WIDGET_VOL,
 	STAC_CTL_WIDGET_MUTE,
+	STAC_CTL_WIDGET_MONO_MUX,
 	STAC_CTL_WIDGET_IO_SWITCH,
 	STAC_CTL_WIDGET_CLFE_SWITCH
 };
@@ -1554,6 +2136,7 @@
 static struct snd_kcontrol_new stac92xx_control_templates[] = {
 	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
 	HDA_CODEC_MUTE(NULL, 0, 0, 0),
+	STAC_MONO_MUX,
 	STAC_CODEC_IO_SWITCH(NULL, 0),
 	STAC_CODEC_CLFE_SWITCH(NULL, 0),
 };
@@ -1598,6 +2181,7 @@
 	for (i = 0; i < codec->num_nodes; i++) {
 		wcaps = codec->wcaps[i];
 		wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+
 		if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
 			num_dacs++;
 	}
@@ -1685,7 +2269,6 @@
 			wcaps = snd_hda_param_read(codec, conn[j],
 						   AC_PAR_AUDIO_WIDGET_CAP);
 			wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-
 			if (wtype != AC_WID_AUD_OUT ||
 			    (wcaps & AC_WCAP_DIGITAL))
 				continue;
@@ -1759,10 +2342,10 @@
 	int i, err;
 
 	struct sigmatel_spec *spec = codec->spec;
-	unsigned int wid_caps;
+	unsigned int wid_caps, pincap;
 
 
-	for (i = 0; i < cfg->line_outs; i++) {
+	for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) {
 		if (!spec->multiout.dac_nids[i])
 			continue;
 
@@ -1795,13 +2378,39 @@
 		}
 	}
 
-	if (spec->line_switch)
-		if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
-			return err;
+	if (spec->line_switch) {
+		nid = cfg->input_pins[AUTO_PIN_LINE];
+		pincap = snd_hda_param_read(codec, nid,
+						AC_PAR_PIN_CAP);
+		if (pincap & AC_PINCAP_OUT) {
+			err = stac92xx_add_control(spec,
+				STAC_CTL_WIDGET_IO_SWITCH,
+				"Line In as Output Switch", nid << 8);
+			if (err < 0)
+				return err;
+		}
+	}
 
-	if (spec->mic_switch)
-		if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
-			return err;
+	if (spec->mic_switch) {
+		unsigned int def_conf;
+		nid = cfg->input_pins[AUTO_PIN_MIC];
+		def_conf = snd_hda_codec_read(codec, nid, 0,
+						AC_VERB_GET_CONFIG_DEFAULT, 0);
+
+		/* some laptops have an internal analog microphone
+		 * which can't be used as a output */
+		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+			pincap = snd_hda_param_read(codec, nid,
+							AC_PAR_PIN_CAP);
+			if (pincap & AC_PINCAP_OUT) {
+				err = stac92xx_add_control(spec,
+					STAC_CTL_WIDGET_IO_SWITCH,
+					"Mic as Output Switch", (nid << 8) | 1);
+				if (err < 0)
+					return err;
+			}
+		}
+	}
 
 	return 0;
 }
@@ -1891,6 +2500,37 @@
 	return 0;
 }
 
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+	"DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+	int i, num_cons;
+	hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
+
+	num_cons = snd_hda_get_connections(codec,
+				spec->mono_nid,
+				con_lst,
+				HDA_MAX_NUM_INPUTS);
+	if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
+		return -EINVAL;
+
+	for (i = 0; i < num_cons; i++) {
+		mono_mux->items[mono_mux->num_items].label =
+					stac92xx_mono_labels[i];
+		mono_mux->items[mono_mux->num_items].index = i;
+		mono_mux->num_items++;
+	}
+
+	return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
+				"Mono Mux", spec->mono_nid);
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
 	"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -1904,15 +2544,18 @@
 	struct sigmatel_spec *spec = codec->spec;
 	struct hda_input_mux *dimux = &spec->private_dimux;
 	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
-	int i, j;
+	int err, i, j;
+	char name[32];
 
 	dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
 	dimux->items[dimux->num_items].index = 0;
 	dimux->num_items++;
 
 	for (i = 0; i < spec->num_dmics; i++) {
+		hda_nid_t nid;
 		int index;
 		int num_cons;
+		unsigned int wcaps;
 		unsigned int def_conf;
 
 		def_conf = snd_hda_codec_read(codec,
@@ -1923,17 +2566,32 @@
 		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
 			continue;
 
+		nid = spec->dmic_nids[i];
 		num_cons = snd_hda_get_connections(codec,
-				spec->dmux_nid,
+				spec->dmux_nids[0],
 				con_lst,
 				HDA_MAX_NUM_INPUTS);
 		for (j = 0; j < num_cons; j++)
-			if (con_lst[j] == spec->dmic_nids[i]) {
+			if (con_lst[j] == nid) {
 				index = j;
 				goto found;
 			}
 		continue;
 found:
+		wcaps = get_wcaps(codec, nid);
+
+		if (wcaps & AC_WCAP_OUT_AMP) {
+			sprintf(name, "%s Capture Volume",
+				stac92xx_dmic_labels[dimux->num_items]);
+
+			err = stac92xx_add_control(spec,
+				STAC_CTL_WIDGET_VOL,
+				name,
+				HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+
 		dimux->items[dimux->num_items].label =
 			stac92xx_dmic_labels[dimux->num_items];
 		dimux->items[dimux->num_items].index = index;
@@ -2026,6 +2684,7 @@
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int err;
+	int hp_speaker_swap = 0;
 
 	if ((err = snd_hda_parse_pin_def_config(codec,
 						&spec->autocfg,
@@ -2034,6 +2693,68 @@
 	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid pin config */
 
+	/* If we have no real line-out pin and multiple hp-outs, HPs should
+	 * be set up as multi-channel outputs.
+	 */
+	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
+	    spec->autocfg.hp_outs > 1) {
+		/* Copy hp_outs to line_outs, backup line_outs in
+		 * speaker_outs so that the following routines can handle
+		 * HP pins as primary outputs.
+		 */
+		memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
+		       sizeof(spec->autocfg.line_out_pins));
+		spec->autocfg.speaker_outs = spec->autocfg.line_outs;
+		memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
+		       sizeof(spec->autocfg.hp_pins));
+		spec->autocfg.line_outs = spec->autocfg.hp_outs;
+		hp_speaker_swap = 1;
+	}
+	if (spec->autocfg.mono_out_pin) {
+		int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
+				& AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
+		u32 caps = query_amp_caps(codec,
+				spec->autocfg.mono_out_pin, dir);
+		hda_nid_t conn_list[1];
+
+		/* get the mixer node and then the mono mux if it exists */
+		if (snd_hda_get_connections(codec,
+				spec->autocfg.mono_out_pin, conn_list, 1) &&
+				snd_hda_get_connections(codec, conn_list[0],
+				conn_list, 1)) {
+
+				int wcaps = get_wcaps(codec, conn_list[0]);
+				int wid_type = (wcaps & AC_WCAP_TYPE)
+					>> AC_WCAP_TYPE_SHIFT;
+				/* LR swap check, some stac925x have a mux that
+ 				 * changes the DACs output path instead of the
+ 				 * mono-mux path.
+ 				 */
+				if (wid_type == AC_WID_AUD_SEL &&
+						!(wcaps & AC_WCAP_LR_SWAP))
+					spec->mono_nid = conn_list[0];
+		}
+		/* all mono outs have a least a mute/unmute switch */
+		err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
+			"Mono Playback Switch",
+			HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
+					1, 0, dir));
+		if (err < 0)
+			return err;
+		/* check to see if there is volume support for the amp */
+		if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+			err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
+				"Mono Playback Volume",
+				HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
+					1, 0, dir));
+			if (err < 0)
+				return err;
+		}
+
+		stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
+					 AC_PINCTL_OUT_EN);
+	}
+
 	if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
 		return err;
 	if (spec->multiout.num_dacs == 0)
@@ -2045,6 +2766,19 @@
 	if (err < 0)
 		return err;
 
+	if (hp_speaker_swap == 1) {
+		/* Restore the hp_outs and line_outs */
+		memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
+		       sizeof(spec->autocfg.line_out_pins));
+		spec->autocfg.hp_outs = spec->autocfg.line_outs;
+		memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
+		       sizeof(spec->autocfg.speaker_pins));
+		spec->autocfg.line_outs = spec->autocfg.speaker_outs;
+		memset(spec->autocfg.speaker_pins, 0,
+		       sizeof(spec->autocfg.speaker_pins));
+		spec->autocfg.speaker_outs = 0;
+	}
+
 	err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
 
 	if (err < 0)
@@ -2055,6 +2789,12 @@
 	if (err < 0)
 		return err;
 
+	if (spec->mono_nid > 0) {
+		err = stac92xx_auto_create_mono_output_ctls(codec);
+		if (err < 0)
+			return err;
+	}
+
 	if (spec->num_dmics > 0)
 		if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
 						&spec->autocfg)) < 0)
@@ -2073,7 +2813,9 @@
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
 	spec->input_mux = &spec->private_imux;
-	spec->dinput_mux = &spec->private_dimux;
+	if (!spec->dinput_mux)
+		spec->dinput_mux = &spec->private_dimux;
+	spec->mono_mux = &spec->private_mono_mux;
 
 	return 1;
 }
@@ -2183,38 +2925,35 @@
  * funky external mute control using GPIO pins.
  */
 
-static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+			  unsigned int dir_mask, unsigned int data)
 {
 	unsigned int gpiostate, gpiomask, gpiodir;
 
 	gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
 				       AC_VERB_GET_GPIO_DATA, 0);
-
-	if (!muted)
-		gpiostate |= (1 << pin);
-	else
-		gpiostate &= ~(1 << pin);
+	gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
 
 	gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
 				      AC_VERB_GET_GPIO_MASK, 0);
-	gpiomask |= (1 << pin);
+	gpiomask |= mask;
 
 	gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
 				     AC_VERB_GET_GPIO_DIRECTION, 0);
-	gpiodir |= (1 << pin);
+	gpiodir |= dir_mask;
 
-	/* AppleHDA seems to do this -- WTF is this verb?? */
+	/* Configure GPIOx as CMOS */
 	snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
 
 	snd_hda_codec_write(codec, codec->afg, 0,
 			    AC_VERB_SET_GPIO_MASK, gpiomask);
-	snd_hda_codec_write(codec, codec->afg, 0,
-			    AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+	snd_hda_codec_read(codec, codec->afg, 0,
+			   AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
 
 	msleep(1);
 
-	snd_hda_codec_write(codec, codec->afg, 0,
-			    AC_VERB_SET_GPIO_DATA, gpiostate);
+	snd_hda_codec_read(codec, codec->afg, 0,
+			   AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
 static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
@@ -2226,6 +2965,29 @@
 					  (AC_USRSP_EN | event));
 }
 
+static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
+{
+	int i;
+	for (i = 0; i < cfg->hp_outs; i++)
+		if (cfg->hp_pins[i] == nid)
+			return 1; /* nid is a HP-Out */
+
+	return 0; /* nid is not a HP-Out */
+};
+
+static void stac92xx_power_down(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	/* power down inactive DACs */
+	hda_nid_t *dac;
+	for (dac = spec->dac_list; *dac; dac++)
+		if (!is_in_dac_nids(spec, *dac) &&
+			spec->multiout.hp_nid != *dac)
+			snd_hda_codec_write_cache(codec, *dac, 0,
+					AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -2261,11 +3023,29 @@
 			stac92xx_auto_set_pinctl(codec, nid, pinctl);
 		}
 	}
-	if (spec->num_dmics > 0)
-		for (i = 0; i < spec->num_dmics; i++)
-			stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
-						 AC_PINCTL_IN_EN);
-
+	for (i = 0; i < spec->num_dmics; i++)
+		stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
+					AC_PINCTL_IN_EN);
+	for (i = 0; i < spec->num_pwrs; i++)  {
+		int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
+					? STAC_HP_EVENT : STAC_PWR_EVENT;
+		int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
+					0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i],
+					0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+		/* outputs are only ports capable of power management
+		 * any attempts on powering down a input port cause the
+		 * referenced VREF to act quirky.
+		 */
+		if (pinctl & AC_PINCTL_IN_EN)
+			continue;
+		if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED)
+			continue;
+		enable_pin_detect(codec, spec->pwr_nids[i], event | i);
+		codec->patch_ops.unsol_event(codec, (event | i) << 26);
+	}
+	if (spec->dac_list)
+		stac92xx_power_down(codec);
 	if (cfg->dig_out_pin)
 		stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
 					 AC_PINCTL_OUT_EN);
@@ -2273,10 +3053,8 @@
 		stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
 					 AC_PINCTL_IN_EN);
 
-	if (spec->gpio_mute) {
-		stac922x_gpio_mute(codec, 0, 0);
-		stac922x_gpio_mute(codec, 1, 0);
-	}
+	stac_gpio_set(codec, spec->gpio_mask,
+					spec->gpio_dir, spec->gpio_data);
 
 	return 0;
 }
@@ -2342,13 +3120,20 @@
 			pin_ctl & ~flag);
 }
 
-static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
+static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
 {
 	if (!nid)
 		return 0;
 	if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
-	    & (1 << 31))
-		return 1;
+	    & (1 << 31)) {
+		unsigned int pinctl;
+		pinctl = snd_hda_codec_read(codec, nid, 0,
+					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+		if (pinctl & AC_PINCTL_IN_EN)
+			return 0; /* mic- or line-input */
+		else
+			return 1; /* HP-output */
+	}
 	return 0;
 }
 
@@ -2359,10 +3144,14 @@
 	int i, presence;
 
 	presence = 0;
+	if (spec->gpio_mute)
+		presence = !(snd_hda_codec_read(codec, codec->afg, 0,
+			AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
+
 	for (i = 0; i < cfg->hp_outs; i++) {
-		presence = get_pin_presence(codec, cfg->hp_pins[i]);
 		if (presence)
 			break;
+		presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
 	}
 
 	if (presence) {
@@ -2384,12 +3173,37 @@
 	}
 } 
 
+static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid = spec->pwr_nids[idx];
+	int presence, val;
+	val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
+							& 0x000000ff;
+	presence = get_hp_pin_presence(codec, nid);
+	idx = 1 << idx;
+
+	if (presence)
+		val &= ~idx;
+	else
+		val |= idx;
+
+	/* power down unused output ports */
+	snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
+};
+
 static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-	switch (res >> 26) {
+	struct sigmatel_spec *spec = codec->spec;
+	int idx = res >> 26 & 0x0f;
+
+	switch ((res >> 26) & 0x30) {
 	case STAC_HP_EVENT:
 		stac92xx_hp_detect(codec, res);
-		break;
+		/* fallthru */
+	case STAC_PWR_EVENT:
+		if (spec->num_pwrs > 0)
+			stac92xx_pin_sense(codec, idx);
 	}
 }
 
@@ -2400,12 +3214,13 @@
 
 	stac92xx_set_config_regs(codec);
 	snd_hda_sequence_write(codec, spec->init);
-	if (spec->gpio_mute) {
-		stac922x_gpio_mute(codec, 0, 0);
-		stac922x_gpio_mute(codec, 1, 0);
-	}
+	stac_gpio_set(codec, spec->gpio_mask,
+		spec->gpio_dir, spec->gpio_data);
 	snd_hda_codec_resume_amp(codec);
 	snd_hda_codec_resume_cache(codec);
+	/* power down inactive DACs */
+	if (spec->dac_list)
+		stac92xx_power_down(codec);
 	/* invoke unsolicited event to reset the HP state */
 	if (spec->hp_detect)
 		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
@@ -2460,8 +3275,10 @@
 	spec->num_muxes = 1;
 	spec->num_dmics = 0;
 	spec->num_adcs = 1;
+	spec->num_pwrs = 0;
 
-	if (spec->board_config == STAC_9200_GATEWAY)
+	if (spec->board_config == STAC_9200_GATEWAY ||
+	    spec->board_config == STAC_9200_OQO)
 		spec->init = stac9200_eapd_init;
 	else
 		spec->init = stac9200_core_init;
@@ -2515,6 +3332,7 @@
 	spec->mux_nids = stac925x_mux_nids;
 	spec->num_muxes = 1;
 	spec->num_adcs = 1;
+	spec->num_pwrs = 0;
 	switch (codec->vendor_id) {
 	case 0x83847632: /* STAC9202  */
 	case 0x83847633: /* STAC9202D */
@@ -2522,6 +3340,8 @@
 	case 0x83847637: /* STAC9251D */
 		spec->num_dmics = STAC925X_NUM_DMICS;
 		spec->dmic_nids = stac925x_dmic_nids;
+		spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
+		spec->dmux_nids = stac925x_dmux_nids;
 		break;
 	default:
 		spec->num_dmics = 0;
@@ -2551,6 +3371,231 @@
 	return 0;
 }
 
+static struct hda_input_mux stac92hd73xx_dmux = {
+	.num_items = 4,
+	.items = {
+		{ "Analog Inputs", 0x0b },
+		{ "CD", 0x08 },
+		{ "Digital Mic 1", 0x09 },
+		{ "Digital Mic 2", 0x0a },
+	}
+};
+
+static int patch_stac92hd73xx(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
+	int err = 0;
+
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
+	spec->pin_nids = stac92hd73xx_pin_nids;
+	spec->board_config = snd_hda_check_board_config(codec,
+							STAC_92HD73XX_MODELS,
+							stac92hd73xx_models,
+							stac92hd73xx_cfg_tbl);
+again:
+	if (spec->board_config < 0) {
+		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+			" STAC92HD73XX, using BIOS defaults\n");
+		err = stac92xx_save_bios_config_regs(codec);
+		if (err < 0) {
+			stac92xx_free(codec);
+			return err;
+		}
+		spec->pin_configs = spec->bios_pin_configs;
+	} else {
+		spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
+		stac92xx_set_config_regs(codec);
+	}
+
+	spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
+			conn, STAC92HD73_DAC_COUNT + 2) - 1;
+
+	if (spec->multiout.num_dacs < 0) {
+		printk(KERN_WARNING "hda_codec: Could not determine "
+		       "number of channels defaulting to DAC count\n");
+		spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
+	}
+
+	switch (spec->multiout.num_dacs) {
+	case 0x3: /* 6 Channel */
+		spec->mixer = stac92hd73xx_6ch_mixer;
+		spec->init = stac92hd73xx_6ch_core_init;
+		break;
+	case 0x4: /* 8 Channel */
+		spec->multiout.hp_nid = 0x18;
+		spec->mixer = stac92hd73xx_8ch_mixer;
+		spec->init = stac92hd73xx_8ch_core_init;
+		break;
+	case 0x5: /* 10 Channel */
+		spec->multiout.hp_nid = 0x19;
+		spec->mixer = stac92hd73xx_10ch_mixer;
+		spec->init = stac92hd73xx_10ch_core_init;
+	};
+
+	spec->multiout.dac_nids = stac92hd73xx_dac_nids;
+	spec->aloopback_mask = 0x01;
+	spec->aloopback_shift = 8;
+
+	spec->mux_nids = stac92hd73xx_mux_nids;
+	spec->adc_nids = stac92hd73xx_adc_nids;
+	spec->dmic_nids = stac92hd73xx_dmic_nids;
+	spec->dmux_nids = stac92hd73xx_dmux_nids;
+
+	spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
+	spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
+	spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
+	spec->dinput_mux = &stac92hd73xx_dmux;
+	/* GPIO0 High = Enable EAPD */
+	spec->gpio_mask = spec->gpio_dir = 0x1;
+	spec->gpio_data = 0x01;
+
+	switch (spec->board_config) {
+	case STAC_DELL_M6:
+		spec->init = dell_m6_core_init;
+		switch (codec->subsystem_id) {
+		case 0x1028025e: /* Analog Mics */
+		case 0x1028025f:
+			stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
+			spec->num_dmics = 0;
+			break;
+		case 0x10280254: /* Digital Mics */
+		case 0x10280255:
+		case 0x10280271:
+		case 0x10280272:
+			stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+			spec->num_dmics = 1;
+			break;
+		case 0x10280256: /* Both */
+		case 0x10280057:
+			stac92xx_set_config_reg(codec, 0x0b, 0x90A70170);
+			stac92xx_set_config_reg(codec, 0x13, 0x90A60160);
+			spec->num_dmics = 1;
+			break;
+		}
+		break;
+	default:
+		spec->num_dmics = STAC92HD73XX_NUM_DMICS;
+	}
+
+	spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
+	spec->pwr_nids = stac92hd73xx_pwr_nids;
+
+	err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
+
+	if (!err) {
+		if (spec->board_config < 0) {
+			printk(KERN_WARNING "hda_codec: No auto-config is "
+			       "available, default to model=ref\n");
+			spec->board_config = STAC_92HD73XX_REF;
+			goto again;
+		}
+		err = -EINVAL;
+	}
+
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
+
+	codec->patch_ops = stac92xx_patch_ops;
+
+	return 0;
+}
+
+static int patch_stac92hd71bxx(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	int err = 0;
+
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
+	spec->pin_nids = stac92hd71bxx_pin_nids;
+	spec->board_config = snd_hda_check_board_config(codec,
+							STAC_92HD71BXX_MODELS,
+							stac92hd71bxx_models,
+							stac92hd71bxx_cfg_tbl);
+again:
+	if (spec->board_config < 0) {
+		snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+			" STAC92HD71BXX, using BIOS defaults\n");
+		err = stac92xx_save_bios_config_regs(codec);
+		if (err < 0) {
+			stac92xx_free(codec);
+			return err;
+		}
+		spec->pin_configs = spec->bios_pin_configs;
+	} else {
+		spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
+		stac92xx_set_config_regs(codec);
+	}
+
+	switch (codec->vendor_id) {
+	case 0x111d76b6: /* 4 Port without Analog Mixer */
+	case 0x111d76b7:
+	case 0x111d76b4: /* 6 Port without Analog Mixer */
+	case 0x111d76b5:
+		spec->mixer = stac92hd71bxx_mixer;
+		spec->init = stac92hd71bxx_core_init;
+		break;
+	default:
+		spec->mixer = stac92hd71bxx_analog_mixer;
+		spec->init = stac92hd71bxx_analog_core_init;
+	}
+
+	spec->aloopback_mask = 0x20;
+	spec->aloopback_shift = 0;
+
+	/* GPIO0 High = EAPD */
+	spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
+
+	spec->mux_nids = stac92hd71bxx_mux_nids;
+	spec->adc_nids = stac92hd71bxx_adc_nids;
+	spec->dmic_nids = stac92hd71bxx_dmic_nids;
+	spec->dmux_nids = stac92hd71bxx_dmux_nids;
+
+	spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
+	spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+	spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
+	spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+
+	spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
+	spec->pwr_nids = stac92hd71bxx_pwr_nids;
+
+	spec->multiout.num_dacs = 1;
+	spec->multiout.hp_nid = 0x11;
+	spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+
+	err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
+	if (!err) {
+		if (spec->board_config < 0) {
+			printk(KERN_WARNING "hda_codec: No auto-config is "
+			       "available, default to model=ref\n");
+			spec->board_config = STAC_92HD71BXX_REF;
+			goto again;
+		}
+		err = -EINVAL;
+	}
+
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
+
+	codec->patch_ops = stac92xx_patch_ops;
+
+	return 0;
+};
+
 static int patch_stac922x(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
@@ -2567,7 +3612,8 @@
 							stac922x_models,
 							stac922x_cfg_tbl);
 	if (spec->board_config == STAC_INTEL_MAC_V3) {
-		spec->gpio_mute = 1;
+		spec->gpio_mask = spec->gpio_dir = 0x03;
+		spec->gpio_data = 0x03;
 		/* Intel Macs have all same PCI SSID, so we need to check
 		 * codec SSID to distinguish the exact models
 		 */
@@ -2587,10 +3633,12 @@
 		case 0x106b1700:
 		case 0x106b0200:
 		case 0x106b1e00:
+		case 0x100: /* Invalid subsystem ID, happens randomly on
+			     * MacBook Pro 1st generation
+			     */
 			spec->board_config = STAC_INTEL_MAC_V3;
 			break;
 		case 0x106b1a00:
-		case 0x00000100:
 			spec->board_config = STAC_INTEL_MAC_V4;
 			break;
 		case 0x106b0a00:
@@ -2620,6 +3668,7 @@
 	spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
 	spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
 	spec->num_dmics = 0;
+	spec->num_pwrs = 0;
 
 	spec->init = stac922x_core_init;
 	spec->mixer = stac922x_mixer;
@@ -2669,53 +3718,73 @@
 							stac927x_models,
 							stac927x_cfg_tbl);
  again:
-	if (spec->board_config < 0) {
-                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
+	if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
+		if (spec->board_config < 0)
+			snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+				    "STAC927x, using BIOS defaults\n");
 		err = stac92xx_save_bios_config_regs(codec);
 		if (err < 0) {
 			stac92xx_free(codec);
 			return err;
 		}
 		spec->pin_configs = spec->bios_pin_configs;
-	} else if (stac927x_brd_tbl[spec->board_config] != NULL) {
+	} else {
 		spec->pin_configs = stac927x_brd_tbl[spec->board_config];
 		stac92xx_set_config_regs(codec);
 	}
 
+	spec->adc_nids = stac927x_adc_nids;
+	spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
+	spec->mux_nids = stac927x_mux_nids;
+	spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
+	spec->dac_list = stac927x_dac_nids;
+	spec->multiout.dac_nids = spec->dac_nids;
+
 	switch (spec->board_config) {
 	case STAC_D965_3ST:
-		spec->adc_nids = stac927x_adc_nids;
-		spec->mux_nids = stac927x_mux_nids;
-		spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
-		spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
+	case STAC_D965_5ST:
+		/* GPIO0 High = Enable EAPD */
+		spec->gpio_mask = spec->gpio_dir = 0x01;
+		spec->gpio_data = 0x01;
 		spec->num_dmics = 0;
+
 		spec->init = d965_core_init;
 		spec->mixer = stac927x_mixer;
 		break;
-	case STAC_D965_5ST:
-		spec->adc_nids = stac927x_adc_nids;
-		spec->mux_nids = stac927x_mux_nids;
-		spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
-		spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
-		spec->num_dmics = 0;
+	case STAC_DELL_BIOS:
+		/* configure the analog microphone on some laptops */
+		stac92xx_set_config_reg(codec, 0x0c, 0x90a79130);
+		/* correct the front output jack as a hp out */
+		stac92xx_set_config_reg(codec, 0x0f, 0x0227011f);
+		/* correct the front input jack as a mic */
+		stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
+		/* fallthru */
+	case STAC_DELL_3ST:
+		/* GPIO2 High = Enable EAPD */
+		spec->gpio_mask = spec->gpio_dir = 0x04;
+		spec->gpio_data = 0x04;
+		spec->dmic_nids = stac927x_dmic_nids;
+		spec->num_dmics = STAC927X_NUM_DMICS;
+
 		spec->init = d965_core_init;
 		spec->mixer = stac927x_mixer;
+		spec->dmux_nids = stac927x_dmux_nids;
+		spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
 		break;
 	default:
-		spec->adc_nids = stac927x_adc_nids;
-		spec->mux_nids = stac927x_mux_nids;
-		spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
-		spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
+		/* GPIO0 High = Enable EAPD */
+		spec->gpio_mask = spec->gpio_dir = 0x1;
+		spec->gpio_data = 0x01;
 		spec->num_dmics = 0;
+
 		spec->init = stac927x_core_init;
 		spec->mixer = stac927x_mixer;
 	}
 
-	spec->multiout.dac_nids = spec->dac_nids;
-	/* GPIO0 High = Enable EAPD */
-	spec->gpio_mask = spec->gpio_data = 0x00000001;
-	stac92xx_enable_gpio_mask(codec); 
-	
+	spec->num_pwrs = 0;
+	spec->aloopback_mask = 0x40;
+	spec->aloopback_shift = 0;
+
 	err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
 	if (!err) {
 		if (spec->board_config < 0) {
@@ -2733,6 +3802,18 @@
 
 	codec->patch_ops = stac92xx_patch_ops;
 
+	/*
+	 * !!FIXME!!
+	 * The STAC927x seem to require fairly long delays for certain
+	 * command sequences.  With too short delays (even if the answer
+	 * is set to RIRB properly), it results in the silence output
+	 * on some hardwares like Dell.
+	 *
+	 * The below flag enables the longer delay (see get_response
+	 * in hda_intel.c).
+	 */
+	codec->bus->needs_damn_long_delay = 1;
+
 	return 0;
 }
 
@@ -2771,11 +3852,15 @@
 	spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
 	spec->dmic_nids = stac9205_dmic_nids;
 	spec->num_dmics = STAC9205_NUM_DMICS;
-	spec->dmux_nid = 0x1d;
+	spec->dmux_nids = stac9205_dmux_nids;
+	spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
+	spec->num_pwrs = 0;
 
 	spec->init = stac9205_core_init;
 	spec->mixer = stac9205_mixer;
 
+	spec->aloopback_mask = 0x40;
+	spec->aloopback_shift = 0;
 	spec->multiout.dac_nids = spec->dac_nids;
 	
 	switch (spec->board_config){
@@ -2784,19 +3869,28 @@
 		stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
 		stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
 
-		spec->gpio_mask = 0x00000007; /* GPIO0-2 */
-		/* GPIO0 High = EAPD, GPIO1 Low = DRM,
-		 * GPIO2 High = Headphone Mute
+		/* Enable unsol response for GPIO4/Dock HP connection */
+		snd_hda_codec_write(codec, codec->afg, 0,
+			AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
+		snd_hda_codec_write_cache(codec, codec->afg, 0,
+					  AC_VERB_SET_UNSOLICITED_ENABLE,
+					  (AC_USRSP_EN | STAC_HP_EVENT));
+
+		spec->gpio_dir = 0x0b;
+		spec->gpio_mask = 0x1b;
+		spec->gpio_mute = 0x10;
+		/* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
+		 * GPIO3 Low = DRM
 		 */
-		spec->gpio_data = 0x00000005;
+		spec->gpio_data = 0x01;
 		break;
 	default:
 		/* GPIO0 High = EAPD */
-		spec->gpio_mask = spec->gpio_data = 0x00000001;
+		spec->gpio_mask = spec->gpio_dir = 0x1;
+		spec->gpio_data = 0x01;
 		break;
 	}
 
-	stac92xx_enable_gpio_mask(codec);
 	err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
 	if (!err) {
 		if (spec->board_config < 0) {
@@ -2950,7 +4044,7 @@
 
 static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
 {
-	if (get_pin_presence(codec, 0x0a)) {
+	if (get_hp_pin_presence(codec, 0x0a)) {
 		stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
 		stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
 	} else {
@@ -3000,6 +4094,7 @@
 	SND_PCI_QUIRK(0x104d, 0x81ef, "Sony VAIO F/S", CXD9872RD_VAIO),
 	SND_PCI_QUIRK(0x104d, 0x81fd, "Sony VAIO AR", CXD9872AKD_VAIO),
 	SND_PCI_QUIRK(0x104d, 0x8205, "Sony VAIO AR", CXD9872AKD_VAIO),
+	SND_PCI_QUIRK(0x104d, 0x9005, "Sony VAIO VGN-FZ18M", CXD9872RD_VAIO),
 	{}
 };
 
@@ -3032,6 +4127,7 @@
 		spec->multiout.hp_nid = VAIO_HP_DAC;
 		spec->num_adcs = ARRAY_SIZE(vaio_adcs);
 		spec->adc_nids = vaio_adcs;
+		spec->num_pwrs = 0;
 		spec->input_mux = &vaio_mux;
 		spec->mux_nids = vaio_mux_nids;
 		codec->patch_ops = stac9872_vaio_patch_ops;
@@ -3045,6 +4141,7 @@
 		spec->multiout.dac_nids = vaio_dacs;
 		spec->multiout.hp_nid = VAIO_HP_DAC;
 		spec->num_adcs = ARRAY_SIZE(vaio_adcs);
+		spec->num_pwrs = 0;
 		spec->adc_nids = vaio_adcs;
 		spec->input_mux = &vaio_mux;
 		spec->mux_nids = vaio_mux_nids;
@@ -3097,6 +4194,7 @@
  	{ .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 },
  	{ .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 },
  	{ .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 },
+	{ .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 },
  	{ .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 },
  	{ .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 },
  	{ .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 },
@@ -3104,5 +4202,17 @@
  	{ .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
  	{ .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
  	{ .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
+	{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
+	{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
+	{ .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
+	{ .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
+	{ .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
 	{} /* terminator */
 };
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/patch_via.c linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_via.c
--- linux-2.6.24.7-rt20/sound/pci/hda/patch_via.c	2008-10-06 08:30:35.000000000 +0200
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/patch_via.c	2008-09-28 23:33:40.000000000 +0200
@@ -27,11 +27,12 @@
 /* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid          */
 /* 2006-08-02  Lydia Wang  Add support to VT1709 codec                       */
 /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
+/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization      */
+/* 2007-09-17  Lydia Wang  Add VT1708B codec support                        */
 /*                                                                           */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -51,14 +52,23 @@
 #define VT1708_HP_NID		0x13
 #define VT1708_DIGOUT_NID	0x14
 #define VT1708_DIGIN_NID	0x16
+#define VT1708_DIGIN_PIN	0x26
 
 #define VT1709_HP_DAC_NID	0x28
 #define VT1709_DIGOUT_NID	0x13
 #define VT1709_DIGIN_NID	0x17
+#define VT1709_DIGIN_PIN	0x25
+
+#define VT1708B_HP_NID		0x25
+#define VT1708B_DIGOUT_NID	0x12
+#define VT1708B_DIGIN_NID	0x15
+#define VT1708B_DIGIN_PIN	0x21
 
 #define IS_VT1708_VENDORID(x)		((x) >= 0x11061708 && (x) <= 0x1106170b)
 #define IS_VT1709_10CH_VENDORID(x)	((x) >= 0x1106e710 && (x) <= 0x1106e713)
 #define IS_VT1709_6CH_VENDORID(x)	((x) >= 0x1106e714 && (x) <= 0x1106e717)
+#define IS_VT1708B_8CH_VENDORID(x)	((x) >= 0x1106e720 && (x) <= 0x1106e723)
+#define IS_VT1708B_4CH_VENDORID(x)	((x) >= 0x1106e724 && (x) <= 0x1106e727)
 
 
 enum {
@@ -131,6 +141,11 @@
 	0x14, 0x15, 0x16
 };
 
+static hda_nid_t vt1708B_adc_nids[2] = {
+	/* ADC1-2 */
+	0x13, 0x14
+};
+
 /* add dynamic controls */
 static int via_add_control(struct via_spec *spec, int type, const char *name,
 			   unsigned long val)
@@ -268,9 +283,13 @@
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     0x18, &spec->cur_mux[adc_idx]);
 	else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-		  IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
+		  IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0)
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     0x19, &spec->cur_mux[adc_idx]);
+	else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
+		  IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0)
+		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+					     0x17, &spec->cur_mux[adc_idx]);
 	else
 		return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 					     spec->adc_nids[adc_idx],
@@ -287,7 +306,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -309,15 +327,15 @@
 	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 	 * mixer widget
 	 */
 	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
 	/*
 	 * Set up output mixers (0x19 - 0x1b)
@@ -329,10 +347,9 @@
 	
 	/* Setup default input to PW4 */
 	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Set mic as default input of sw0 */
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
 	/* PW9 Output enable */
 	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	{ }
 };
 
 static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -340,7 +357,8 @@
 				 struct snd_pcm_substream *substream)
 {
 	struct via_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
+	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
+					     hinfo);
 }
 
 static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -476,6 +494,11 @@
 						    spec->multiout.dig_out_nid);
 		if (err < 0)
 			return err;
+		err = snd_hda_create_spdif_share_sw(codec,
+						    &spec->multiout);
+		if (err < 0)
+			return err;
+		spec->multiout.share_spdif = 1;
 	}
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -506,6 +529,7 @@
 		codec->num_pcms++;
 		info++;
 		info->name = spec->stream_name_digital;
+		info->pcm_type = HDA_PCM_TYPE_SPDIF;
 		if (spec->multiout.dig_out_nid) {
 			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
 				*(spec->stream_digital_playback);
@@ -544,6 +568,33 @@
 {
 	struct via_spec *spec = codec->spec;
 	snd_hda_sequence_write(codec, spec->init_verbs);
+	/* Lydia Add for EAPD enable */
+	if (!spec->dig_in_nid) { /* No Digital In connection */
+		if (IS_VT1708_VENDORID(codec->vendor_id)) {
+			snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    PIN_OUT);
+			snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
+					    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+		} else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
+			   IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
+			snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    PIN_OUT);
+			snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+					    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+		} else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
+			   IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
+			snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+					    AC_VERB_SET_PIN_WIDGET_CONTROL,
+					    PIN_OUT);
+			snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+					    AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+		}
+	} else /* enable SPDIF-input pin */
+		snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
+				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+
  	return 0;
 }
 
@@ -623,58 +674,68 @@
 		if (i == AUTO_SEQ_CENLFE) {
 			/* Center/LFE */
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-					      "Center Playback Volume",
-					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+					"Center Playback Volume",
+					HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+							    HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
 					      "LFE Playback Volume",
-					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
 					      "Center Playback Switch",
-					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
 					      "LFE Playback Switch",
-					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		} else if (i == AUTO_SEQ_FRONT){
 			/* add control to mixer index 0 */
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
 					      "Master Front Playback Volume",
-					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+								  HDA_INPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
 					      "Master Front Playback Switch",
-					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+					      HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+								  HDA_INPUT));
 			if (err < 0)
 				return err;
 			
 			/* add control to PW3 */
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		} else {
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		}
@@ -875,7 +936,6 @@
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		/* The multiple "Capture Source" controls confuse alsamixer
 		 * So call somewhat different..
-		 * FIXME: the controls appear in the "playback" view!
 		 */
 		/* .name = "Capture Source", */
 		.name = "Input Source",
@@ -899,15 +959,15 @@
 	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-	/* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 	 * mixer widget
 	 */
 	/* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
 	/*
 	 * Set up output selector (0x1a, 0x1b, 0x29)
@@ -925,8 +985,6 @@
 
 	/* Set input of PW4 as AOW4 */
 	{0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Set mic as default input of sw0 */
-	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
 	/* PW9 Output enable */
 	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 	{ }
@@ -1073,68 +1131,80 @@
 			/* Center/LFE */
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
 					      "Center Playback Volume",
-					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
 					      "LFE Playback Volume",
-					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
 					      "Center Playback Switch",
-					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
 					      "LFE Playback Switch",
-					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		} else if (i == AUTO_SEQ_FRONT){
 			/* add control to mixer index 0 */
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
 					      "Master Front Playback Volume",
-					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+								  HDA_INPUT));
 			if (err < 0)
 				return err;
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
 					      "Master Front Playback Switch",
-					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+					      HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+								  HDA_INPUT));
 			if (err < 0)
 				return err;
 			
 			/* add control to PW3 */
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		} else if (i == AUTO_SEQ_SURROUND) {
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		} else if (i == AUTO_SEQ_SIDE) {
 			sprintf(name, "%s Playback Volume", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 			sprintf(name, "%s Playback Switch", chname[i]);
 			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+					      HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+								  HDA_OUTPUT));
 			if (err < 0)
 				return err;
 		}
@@ -1351,8 +1421,6 @@
 
 	/* Set input of PW4 as MW0 */
 	{0x20, AC_VERB_SET_CONNECT_SEL, 0},
-	/* Set mic as default input of sw0 */
-	{0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
 	/* PW9 Output enable */
 	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 	{ }
@@ -1403,6 +1471,494 @@
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 	spec->loopback.amplist = vt1709_loopbacks;
 #endif
+	return 0;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		/* The multiple "Capture Source" controls confuse alsamixer
+		 * So call somewhat different..
+		 */
+		/* .name = "Capture Source", */
+		.name = "Input Source",
+		.count = 1,
+		.info = via_mux_enum_info,
+		.get = via_mux_enum_get,
+		.put = via_mux_enum_put,
+	},
+	{ } /* end */
+};
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-1 and set the default input to mic-in
+	 */
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/*
+	 * Set up output mixers
+	 */
+	/* set vol=0 to output mixers */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* Setup default input to PW4 */
+	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
+	/* PW9 Output enable */
+	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* PW10 Input enable */
+	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	{ }
+};
+
+static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
+	/*
+	 * Unmute ADC0-1 and set the default input to mic-in
+	 */
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+	/* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+	 * mixer widget
+	 */
+	/* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+	/*
+	 * Set up output mixers
+	 */
+	/* set vol=0 to output mixers */
+	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* Setup default input of PW4 to MW0 */
+	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
+	/* PW9 Output enable */
+	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+	/* PW10 Input enable */
+	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+	{ }
+};
+
+static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 8,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_pcm_prepare,
+		.cleanup = via_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 4,
+	.nid = 0x10, /* NID to query formats and rates */
+	.ops = {
+		.open = via_playback_pcm_open,
+		.prepare = via_playback_pcm_prepare,
+		.cleanup = via_playback_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
+	.substreams = 2,
+	.channels_min = 2,
+	.channels_max = 2,
+	.nid = 0x13, /* NID to query formats and rates */
+	.ops = {
+		.prepare = via_capture_pcm_prepare,
+		.cleanup = via_capture_pcm_cleanup
+	},
+};
+
+static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.open = via_dig_playback_pcm_open,
+		.close = via_dig_playback_pcm_close,
+		.prepare = via_dig_playback_pcm_prepare
+	},
+};
+
+static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
+				     const struct auto_pin_cfg *cfg)
+{
+	int i;
+	hda_nid_t nid;
+
+	spec->multiout.num_dacs = cfg->line_outs;
+
+	spec->multiout.dac_nids = spec->private_dac_nids;
+
+	for (i = 0; i < 4; i++) {
+		nid = cfg->line_out_pins[i];
+		if (nid) {
+			/* config dac list */
+			switch (i) {
+			case AUTO_SEQ_FRONT:
+				spec->multiout.dac_nids[i] = 0x10;
+				break;
+			case AUTO_SEQ_CENLFE:
+				spec->multiout.dac_nids[i] = 0x24;
+				break;
+			case AUTO_SEQ_SURROUND:
+				spec->multiout.dac_nids[i] = 0x25;
+				break;
+			case AUTO_SEQ_SIDE:
+				spec->multiout.dac_nids[i] = 0x11;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
+					     const struct auto_pin_cfg *cfg)
+{
+	char name[32];
+	static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+	hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
+	hda_nid_t nid, nid_vol = 0;
+	int i, err;
+
+	for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+		nid = cfg->line_out_pins[i];
+
+		if (!nid)
+			continue;
+
+		nid_vol = nid_vols[i];
+
+		if (i == AUTO_SEQ_CENLFE) {
+			/* Center/LFE */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Center Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "LFE Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Center Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "LFE Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else if (i == AUTO_SEQ_FRONT) {
+			/* add control to mixer index 0 */
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+					      "Master Front Playback Volume",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_INPUT));
+			if (err < 0)
+				return err;
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+					      "Master Front Playback Switch",
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_INPUT));
+			if (err < 0)
+				return err;
+
+			/* add control to PW3 */
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		} else {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+					      HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+								  HDA_OUTPUT));
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+	int err;
+
+	if (!pin)
+		return 0;
+
+	spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
+
+	err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+			      "Headphone Playback Volume",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+	err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+			      "Headphone Playback Switch",
+			      HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
+						const struct auto_pin_cfg *cfg)
+{
+	static char *labels[] = {
+		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+	};
+	struct hda_input_mux *imux = &spec->private_imux;
+	int i, err, idx = 0;
+
+	/* for internal loopback recording select */
+	imux->items[imux->num_items].label = "Stereo Mixer";
+	imux->items[imux->num_items].index = idx;
+	imux->num_items++;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		if (!cfg->input_pins[i])
+			continue;
+
+		switch (cfg->input_pins[i]) {
+		case 0x1a: /* Mic */
+			idx = 2;
+			break;
+
+		case 0x1b: /* Line In */
+			idx = 3;
+			break;
+
+		case 0x1e: /* Front Mic */
+			idx = 4;
+			break;
+
+		case 0x1f: /* CD */
+			idx = 1;
+			break;
+		}
+		err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+					   idx, 0x16);
+		if (err < 0)
+			return err;
+		imux->items[imux->num_items].label = labels[i];
+		imux->items[imux->num_items].index = idx;
+		imux->num_items++;
+	}
+	return 0;
+}
+
+static int vt1708B_parse_auto_config(struct hda_codec *codec)
+{
+	struct via_spec *spec = codec->spec;
+	int err;
+
+	err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+	if (err < 0)
+		return err;
+	err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+		return 0; /* can't find valid BIOS pin config */
+
+	err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+	err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+	if (err < 0)
+		return err;
+	err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
+	if (err < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+	if (spec->autocfg.dig_out_pin)
+		spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
+	if (spec->autocfg.dig_in_pin)
+		spec->dig_in_nid = VT1708B_DIGIN_NID;
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1708B_loopbacks[] = {
+	{ 0x16, HDA_INPUT, 1 },
+	{ 0x16, HDA_INPUT, 2 },
+	{ 0x16, HDA_INPUT, 3 },
+	{ 0x16, HDA_INPUT, 4 },
+	{ } /* end */
+};
+#endif
+
+static int patch_vt1708B_8ch(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	/* automatic parse from the BIOS config */
+	err = vt1708B_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration "
+		       "from BIOS.  Using genenic mode...\n");
+	}
+
+	spec->init_verbs = vt1708B_8ch_volume_init_verbs;
+
+	spec->stream_name_analog = "VT1708B Analog";
+	spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1708B Digital";
+	spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
+	spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
+
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1708B_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	spec->loopback.amplist = vt1708B_loopbacks;
+#endif
+
+	return 0;
+}
+
+static int patch_vt1708B_4ch(struct hda_codec *codec)
+{
+	struct via_spec *spec;
+	int err;
+
+	/* create a codec specific record */
+	spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+
+	/* automatic parse from the BIOS config */
+	err = vt1708B_parse_auto_config(codec);
+	if (err < 0) {
+		via_free(codec);
+		return err;
+	} else if (!err) {
+		printk(KERN_INFO "hda_codec: Cannot set up configuration "
+		       "from BIOS.  Using genenic mode...\n");
+	}
+
+	spec->init_verbs = vt1708B_4ch_volume_init_verbs;
+
+	spec->stream_name_analog = "VT1708B Analog";
+	spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
+	spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
+
+	spec->stream_name_digital = "VT1708B Digital";
+	spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
+	spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
+
+	if (!spec->adc_nids && spec->input_mux) {
+		spec->adc_nids = vt1708B_adc_nids;
+		spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+		spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
+		spec->num_mixers++;
+	}
+
+	codec->patch_ops = via_patch_ops;
+
+	codec->patch_ops.init = via_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+	spec->loopback.amplist = vt1708B_loopbacks;
+#endif
 
 	return 0;
 }
@@ -1415,13 +1971,37 @@
 	{ .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
 	{ .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
 	{ .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
-	{ .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-	{ .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
-	{ .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
+	  .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
+	  .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
+	  .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
+	  .patch = patch_vt1709_10ch},
+	{ .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
+	  .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
+	  .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
+	  .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
+	  .patch = patch_vt1709_6ch},
+	{ .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
+	  .patch = patch_vt1708B_8ch},
+	{ .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
+	  .patch = patch_vt1708B_8ch},
+	{ .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
+	  .patch = patch_vt1708B_8ch},
+	{ .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
+	  .patch = patch_vt1708B_8ch},
+	{ .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
+	  .patch = patch_vt1708B_4ch},
+	{ .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
+	  .patch = patch_vt1708B_4ch},
+	{ .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
+	  .patch = patch_vt1708B_4ch},
+	{ .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
+	  .patch = patch_vt1708B_4ch},
 	{} /* terminator */
 };
diff -urN linux-2.6.24.7-rt20/sound/pci/hda/vmaster.c linux-2.6.24.7-rt20-atom/sound/pci/hda/vmaster.c
--- linux-2.6.24.7-rt20/sound/pci/hda/vmaster.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.7-rt20-atom/sound/pci/hda/vmaster.c	2008-09-28 23:33:39.000000000 +0200
@@ -0,0 +1,364 @@
+/*
+ * Virtual master and slave controls
+ *
+ *  Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+/*
+ * a subset of information returned via ctl info callback
+ */
+struct link_ctl_info {
+	int type;		/* value type */
+	int count;		/* item count */
+	int min_val, max_val;	/* min, max values */
+};
+
+/*
+ * link master - this contains a list of slave controls that are
+ * identical types, i.e. info returns the same value type and value
+ * ranges, but may have different number of counts.
+ *
+ * The master control is so far only mono volume/switch for simplicity.
+ * The same value will be applied to all slaves.
+ */
+struct link_master {
+	struct list_head slaves;
+	struct link_ctl_info info;
+	int val;		/* the master value */
+};
+
+/*
+ * link slave - this contains a slave control element
+ *
+ * It fakes the control callbacsk with additional attenuation by the
+ * master control.  A slave may have either one or two channels.
+ */
+
+struct link_slave {
+	struct list_head list;
+	struct link_master *master;
+	struct link_ctl_info info;
+	int vals[2];		/* current values */
+	struct snd_kcontrol slave; /* the copy of original control entry */
+};
+
+/* get the slave ctl info and save the initial values */
+static int slave_init(struct link_slave *slave)
+{
+	struct snd_ctl_elem_info *uinfo;
+	struct snd_ctl_elem_value *uctl;
+	int err, ch;
+
+	if (slave->info.count)
+		return 0; /* already initialized */
+
+	uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
+	if (!uinfo)
+		return -ENOMEM;
+	uinfo->id = slave->slave.id;
+	err = slave->slave.info(&slave->slave, uinfo);
+	if (err < 0) {
+		kfree(uinfo);
+		return err;
+	}
+	slave->info.type = uinfo->type;
+	slave->info.count = uinfo->count;
+	if (slave->info.count > 2  ||
+	    (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
+	     slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
+		snd_printk(KERN_ERR "invalid slave element\n");
+		kfree(uinfo);
+		return -EINVAL;
+	}
+	slave->info.min_val = uinfo->value.integer.min;
+	slave->info.max_val = uinfo->value.integer.max;
+	kfree(uinfo);
+
+	uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
+	if (!uctl)
+		return -ENOMEM;
+	uctl->id = slave->slave.id;
+	err = slave->slave.get(&slave->slave, uctl);
+	for (ch = 0; ch < slave->info.count; ch++)
+		slave->vals[ch] = uctl->value.integer.value[ch];
+	kfree(uctl);
+	return 0;
+}
+
+/* initialize master volume */
+static int master_init(struct link_master *master)
+{
+	struct link_slave *slave;
+
+	if (master->info.count)
+		return 0; /* already initialized */
+
+	list_for_each_entry(slave, &master->slaves, list) {
+		int err = slave_init(slave);
+		if (err < 0)
+			return err;
+		master->info = slave->info;
+		master->info.count = 1; /* always mono */
+		/* set full volume as default (= no attenuation) */
+		master->val = master->info.max_val;
+		return 0;
+	}
+	return -ENOENT;
+}
+
+static int slave_get_val(struct link_slave *slave,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	int err, ch;
+
+	err = slave_init(slave);
+	if (err < 0)
+		return err;
+	for (ch = 0; ch < slave->info.count; ch++)
+		ucontrol->value.integer.value[ch] = slave->vals[ch];
+	return 0;
+}
+
+static int slave_put_val(struct link_slave *slave,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	int err, ch, vol;
+
+	err = master_init(slave->master);
+	if (err < 0)
+		return err;
+
+	switch (slave->info.type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+		for (ch = 0; ch < slave->info.count; ch++)
+			ucontrol->value.integer.value[ch] &=
+				!!slave->master->val;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		for (ch = 0; ch < slave->info.count; ch++) {
+			/* max master volume is supposed to be 0 dB */
+			vol = ucontrol->value.integer.value[ch];
+			vol += slave->master->val - slave->master->info.max_val;
+			if (vol < slave->info.min_val)
+				vol = slave->info.min_val;
+			else if (vol > slave->info.max_val)
+				vol = slave->info.max_val;
+			ucontrol->value.integer.value[ch] = vol;
+		}
+		break;
+	}
+	return slave->slave.put(&slave->slave, ucontrol);
+}
+
+/*
+ * ctl callbacks for slaves
+ */
+static int slave_info(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_info *uinfo)
+{
+	struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+	return slave->slave.info(&slave->slave, uinfo);
+}
+
+static int slave_get(struct snd_kcontrol *kcontrol,
+		     struct snd_ctl_elem_value *ucontrol)
+{
+	struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+	return slave_get_val(slave, ucontrol);
+}
+
+static int slave_put(struct snd_kcontrol *kcontrol,
+		     struct snd_ctl_elem_value *ucontrol)
+{
+	struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+	int err, ch, changed = 0;
+
+	err = slave_init(slave);
+	if (err < 0)
+		return err;
+	for (ch = 0; ch < slave->info.count; ch++) {
+		if (slave->vals[ch] != ucontrol->value.integer.value[ch]) {
+			changed = 1;
+			slave->vals[ch] = ucontrol->value.integer.value[ch];
+		}
+	}
+	if (!changed)
+		return 0;
+	return slave_put_val(slave, ucontrol);
+}
+
+static int slave_tlv_cmd(struct snd_kcontrol *kcontrol,
+			 int op_flag, unsigned int size,
+			 unsigned int __user *tlv)
+{
+	struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+	/* FIXME: this assumes that the max volume is 0 dB */
+	return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv);
+}
+
+static void slave_free(struct snd_kcontrol *kcontrol)
+{
+	struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+	if (slave->slave.private_free)
+		slave->slave.private_free(&slave->slave);
+	if (slave->master)
+		list_del(&slave->list);
+	kfree(slave);
+}
+
+/*
+ * Add a slave control to the group with the given master control
+ *
+ * All slaves must be the same type (returning the same information
+ * via info callback).  The fucntion doesn't check it, so it's your
+ * responsibility.
+ *
+ * Also, some additional limitations:
+ * - at most two channels
+ * - logarithmic volume control (dB level), no linear volume
+ * - master can only attenuate the volume, no gain
+ */
+int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
+{
+	struct link_master *master_link = snd_kcontrol_chip(master);
+	struct link_slave *srec;
+
+	srec = kzalloc(sizeof(*srec) +
+		       slave->count * sizeof(*slave->vd), GFP_KERNEL);
+	if (!srec)
+		return -ENOMEM;
+	srec->slave = *slave;
+	memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
+	srec->master = master_link;
+
+	/* override callbacks */
+	slave->info = slave_info;
+	slave->get = slave_get;
+	slave->put = slave_put;
+	if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
+		slave->tlv.c = slave_tlv_cmd;
+	slave->private_data = srec;
+	slave->private_free = slave_free;
+
+	list_add_tail(&srec->list, &master_link->slaves);
+	return 0;
+}
+
+/*
+ * ctl callbacks for master controls
+ */
+static int master_info(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_info *uinfo)
+{
+	struct link_master *master = snd_kcontrol_chip(kcontrol);
+	int ret;
+
+	ret = master_init(master);
+	if (ret < 0)
+		return ret;
+	uinfo->type = master->info.type;
+	uinfo->count = master->info.count;
+	uinfo->value.integer.min = master->info.min_val;
+	uinfo->value.integer.max = master->info.max_val;
+	return 0;
+}
+
+static int master_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct link_master *master = snd_kcontrol_chip(kcontrol);
+	int err = master_init(master);
+	if (err < 0)
+		return err;
+	ucontrol->value.integer.value[0] = master->val;
+	return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct link_master *master = snd_kcontrol_chip(kcontrol);
+	struct link_slave *slave;
+	struct snd_ctl_elem_value *uval;
+	int err, old_val;
+
+	err = master_init(master);
+	if (err < 0)
+		return err;
+	old_val = master->val;
+	if (ucontrol->value.integer.value[0] == old_val)
+		return 0;
+
+	uval = kmalloc(sizeof(*uval), GFP_KERNEL);
+	if (!uval)
+		return -ENOMEM;
+	list_for_each_entry(slave, &master->slaves, list) {
+		master->val = old_val;
+		uval->id = slave->slave.id;
+		slave_get_val(slave, uval);
+		master->val = ucontrol->value.integer.value[0];
+		slave_put_val(slave, uval);
+	}
+	kfree(uval);
+	return 1;
+}
+
+static void master_free(struct snd_kcontrol *kcontrol)
+{
+	struct link_master *master = snd_kcontrol_chip(kcontrol);
+	struct link_slave *slave;
+
+	list_for_each_entry(slave, &master->slaves, list)
+		slave->master = NULL;
+	kfree(master);
+}
+
+
+/*
+ * Create a virtual master control with the given name
+ */
+struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+						 const unsigned int *tlv)
+{
+	struct link_master *master;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_new knew;
+
+	memset(&knew, 0, sizeof(knew));
+	knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	knew.name = name;
+	knew.info = master_info;
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return NULL;
+	INIT_LIST_HEAD(&master->slaves);
+
+	kctl = snd_ctl_new1(&knew, master);
+	if (!kctl) {
+		kfree(master);
+		return NULL;
+	}
+	/* override some callbacks */
+	kctl->info = master_info;
+	kctl->get = master_get;
+	kctl->put = master_put;
+	kctl->private_free = master_free;
+
+	/* additional (constant) TLV read */
+	if (tlv) {
+		/* FIXME: this assumes that the max volume is 0 dB */
+		kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+		kctl->tlv.p = tlv;
+	}
+	return kctl;
+}
