Index: wireless-testing/drivers/net/wireless/b43/Makefile
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/Makefile	2008-06-12 11:42:15.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/Makefile	2008-06-15 15:25:06.000000000 +0200
@@ -9,9 +9,11 @@ b43-y				+= lo.o
 b43-y				+= wa.o
 b43-y				+= dma.o
 b43-$(CONFIG_B43_PIO)		+= pio.o
 b43-$(CONFIG_B43_RFKILL)	+= rfkill.o
 b43-$(CONFIG_B43_LEDS)		+= leds.o
 b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
+b43-$(CONFIG_B43_DEBUG)		+= vm.o
+b43-$(CONFIG_B43_DEBUG)		+= dasm.o
 b43-$(CONFIG_B43_DEBUG)		+= debugfs.o
 
 obj-$(CONFIG_B43)		+= b43.o
Index: wireless-testing/drivers/net/wireless/b43/b43.h
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/b43.h	2008-06-15 15:24:53.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/b43.h	2008-06-15 15:25:06.000000000 +0200
@@ -698,12 +698,13 @@ struct b43_qos_params {
 	struct ieee80211_tx_queue_params p;
 	/* Does this need to get uploaded to hardware? */
 	bool need_hw_update;
 };
 
 struct b43_wldev;
+struct b43_vm;
 
 /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
 struct b43_wl {
 	/* Pointer to the active wireless device on this chip */
 	struct b43_wldev *current_dev;
 	/* Pointer to the ieee80211 hardware data structure */
@@ -767,12 +768,13 @@ struct b43_wl {
 };
 
 /* The type of the firmware file. */
 enum b43_firmware_file_type {
 	B43_FWTYPE_PROPRIETARY,
 	B43_FWTYPE_OPENSOURCE,
+	B43_FWTYPE_VM,
 	B43_NR_FWTYPES,
 };
 
 /* Context data for fetching firmware. */
 struct b43_request_fw_context {
 	/* The device we are requesting the fw for. */
@@ -902,12 +904,15 @@ struct b43_wldev {
 	u8 max_nr_keys;
 	struct b43_key key[58];
 
 	/* Firmware data */
 	struct b43_firmware fw;
 
+	/* The virtual firmware machine (if used) */
+	struct b43_vm *vm;
+
 	/* Devicelist in struct b43_wl (all 802.11 cores) */
 	struct list_head list;
 
 	/* Debugging stuff follows. */
 #ifdef CONFIG_B43_DEBUG
 	struct b43_dfsentry *dfsentry;
Index: wireless-testing/drivers/net/wireless/b43/vm.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/drivers/net/wireless/b43/vm.c	2008-06-15 15:25:06.000000000 +0200
@@ -0,0 +1,1363 @@
+/*
+
+  Broadcom B43 wireless driver
+  Virtual firmware machine
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.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; 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "vm.h"
+#include "dasm.h"
+#include "b43.h"
+#include "main.h"
+
+#include <linux/bitops.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/firmware.h>
+#include <linux/gfp.h>
+#include <linux/debugfs.h>
+
+
+static int modparam_vm_enable;
+module_param_named(vm_enable, modparam_vm_enable, int, 0444);
+MODULE_PARM_DESC(vm_enable, "Run the firmware on the host in a virtual machine");
+
+
+#define INSN_FMT	"%08X%08X"
+#define INSN_ARG(insn)	(unsigned int)(u32)((insn) >> 32), \
+			(unsigned int)(u32)(insn)
+
+
+static inline u64 insn_at_pc(struct b43_vm *vm, u16 pc)
+{
+	const __be64 *code;
+	u64 insn;
+
+	code = (const __be64 *)&(vm->code[pc * 8]);
+	insn = be64_to_cpup(code);
+	insn = (insn >> 32) | (insn << 32);
+
+	return insn;
+}
+
+static void b43_vm_free_coredump(const char *dump)
+{
+	free_page((unsigned long)dump);
+}
+
+static ssize_t b43_vm_dump_regs(struct b43_vm *vm, char *buf, ssize_t c,
+				const char *pfx,
+				const u16 *regs, size_t nr_regs)
+{
+	size_t i;
+	const char *template;
+	u16 val;
+
+	if (nr_regs >= 10)
+		template = "%s%02u: %04X  ";
+	else
+		template = "%s%01u: %04X  ";
+
+	for (i = 0; i < nr_regs; i++) {
+		if ((i != 0) && (i % 4 == 0))
+			c += snprintf(buf + c, PAGE_SIZE - c, "\n");
+		val = regs[i];
+		c += snprintf(buf + c, PAGE_SIZE - c,
+			      template,
+			      pfx, (unsigned int)i, val);
+	}
+	c += snprintf(buf + c, PAGE_SIZE - c, "\n");
+
+	return c;
+}
+
+static const char * b43_vm_dump_core(struct b43_vm *vm)
+{
+	ssize_t c = 0;
+	char *buf;
+	size_t nr_insns;
+
+	buf = (char *)get_zeroed_page(GFP_ATOMIC);
+	if (!buf) {
+		b43err(vm->dev->wl, "VM: Coredump: Out of memory\n");
+		return NULL;
+	}
+
+	c += snprintf(buf + c, PAGE_SIZE - c,
+		      "--- B43-%s microcode VM coredump ---\n",
+		      wiphy_name(vm->dev->wl->hw->wiphy));
+	c += snprintf(buf + c, PAGE_SIZE - c,
+		      "PC: %04X  Speed: %llu insn/sec\n",
+		      vm->pc, (unsigned long long)vm->insn_per_sec);
+	c += snprintf(buf + c, PAGE_SIZE - c,
+		      "Flags:  add_carry=%u  sub_carry=%u  crashed=%u\n",
+		      vm->add_carry, vm->sub_carry, vm->crashed);
+	c += snprintf(buf + c, PAGE_SIZE - c, "Link registers:\n");
+	c = b43_vm_dump_regs(vm, buf, c, "lr", vm->lr, ARRAY_SIZE(vm->lr));
+	c += snprintf(buf + c, PAGE_SIZE - c, "Offset registers:\n");
+	c = b43_vm_dump_regs(vm, buf, c, "off", vm->off, ARRAY_SIZE(vm->off));
+	c += snprintf(buf + c, PAGE_SIZE - c, "General purpose registers:\n");
+	c = b43_vm_dump_regs(vm, buf, c, "r", vm->gpr, ARRAY_SIZE(vm->gpr));
+
+	c += snprintf(buf + c, PAGE_SIZE - c, "Code:\n");
+	nr_insns = vm->code_size / 8;
+	if (vm->pc < nr_insns) {
+		ssize_t start, end, i;
+		u64 insn;
+		const char *dasm;
+
+		start = max_t(ssize_t, (ssize_t)vm->pc - 6, 0);
+		end = min_t(ssize_t, vm->pc + 6, nr_insns - 1);
+
+		for (i = start; i <= end; i++) {
+			insn = insn_at_pc(vm, i);
+			dasm = b43_dasm_instruction(insn);
+			if (i == vm->pc) {
+				c += snprintf(buf + c, PAGE_SIZE - c,
+					      "%04X: <%08X%08X>  %s\n",
+					      (unsigned int)i,
+					      (unsigned int)(u32)(insn >> 32),
+					      (unsigned int)(u32)(insn),
+					      dasm);
+			} else {
+				c += snprintf(buf + c, PAGE_SIZE - c,
+					      "%04X:  %08X%08X   %s\n",
+					      (unsigned int)i,
+					      (unsigned int)(u32)(insn >> 32),
+					      (unsigned int)(u32)(insn),
+					      dasm);
+			}
+			kfree(dasm);
+		}
+	} else
+		snprintf(buf + c, PAGE_SIZE - c, ">> Invalid PC <<\n");
+
+	return buf;
+}
+
+static void b43_vm_print_dump(struct b43_vm *vm)
+{
+	const char *dump;
+	size_t len, i;
+	char buf[64];
+
+	dump = b43_vm_dump_core(vm);
+	if (dump) {
+		len = strlen(dump);
+		for (i = 0; i < len; i += sizeof(buf) - 1) {
+			memset(buf, 0, sizeof(buf));
+			memcpy(buf, dump + i, min(sizeof(buf) - 1,
+						  len - i));
+			printk(buf);
+		}
+		b43_vm_free_coredump(dump);
+	}
+}
+
+static inline u16 get_mask(u16 opcode)
+{
+	u8 m;
+
+	m = (opcode >> 4) & 0xF;
+	return ((1u << (m + 1)) - 1);
+}
+
+static inline u8 get_shift(u16 opcode)
+{
+	return (opcode & 0xF);
+}
+
+static inline void put_oper_memory(struct b43_vm *vm, u16 z, u16 value)
+{
+	u16 mem;
+
+	mem = z * 2;
+	b43_shm_write16(vm->dev, B43_SHM_SHARED, mem, value);
+}
+
+static inline void put_oper_memory_indirect(struct b43_vm *vm, u16 z, u16 value)
+{
+	u16 mem, offset;
+
+	offset = (z & 0x3F) * 2;
+	mem = vm->off[(z >> 6) & 0x7] * 2;
+	b43_shm_write16(vm->dev, B43_SHM_SHARED, mem + offset, value);
+}
+
+static inline void put_oper_gpr(struct b43_vm *vm, u16 z, u16 value)
+{
+	u16 reg;
+
+	reg = z & 0x3F;
+	vm->gpr[reg] = value;
+}
+
+static inline void put_oper_spr(struct b43_vm *vm, u16 z, u16 value)
+{
+	u16 reg;
+
+	reg = z & 0x1FF;
+	reg = (reg * 2) + 0x400; /* convert to driver MMIO */
+
+	switch (reg) {
+	case 0x4C0 ... 0x4CC: /* Offset register write */
+		reg = (reg - 0x4C0) / 2;
+		vm->off[reg] = value;
+		return;
+	case 0x4D0 ... 0x4D6: /* Link register write */
+		reg = (reg - 0x4D0) / 2;
+		vm->lr[reg] = value;
+		return;
+	}
+
+	b43_write16(vm->dev, reg, value);
+}
+
+static inline void put_result(struct b43_vm *vm, u16 z, u16 result)
+{
+	if (!(z & 0x800)) {
+		put_oper_memory(vm, z, result);
+		return;
+	}
+	if ((z & 0xC00) == 0xC00) {
+		/* Nothing is done. */
+		return;
+	}
+	if ((z & 0xFC0) == 0xBC0) {
+		put_oper_gpr(vm, z, result);
+		return;
+	}
+	if ((z & 0xE00) == 0x800) {
+		put_oper_spr(vm, z, result);
+		return;
+	}
+	if ((z & 0xE00) == 0xA00) {
+		put_oper_memory_indirect(vm, z, result);
+		return;
+	}
+
+	b43err(vm->dev->wl, "VM: put_oper: Unknown operand type: 0x%04X\n", z);
+	vm->crashed = 1;
+}
+
+static inline u16 get_oper_memory(struct b43_vm *vm, u16 operand)
+{
+	u16 mem;
+
+	mem = operand * 2;
+
+	return b43_shm_read16(vm->dev, B43_SHM_SHARED, mem);
+}
+
+static inline u16 get_oper_memory_indirect(struct b43_vm *vm, u16 operand)
+{
+	u16 mem, offset;
+
+	offset = (operand & 0x3F) * 2;
+	mem = vm->off[(operand >> 6) & 0x7] * 2;
+
+	return b43_shm_read16(vm->dev, B43_SHM_SHARED, mem + offset);
+}
+
+static inline u16 get_oper_immediate(struct b43_vm *vm, u16 operand)
+{
+	operand &= ~0xC00;
+	if (operand & (1 << 9))
+		operand |= 0xFC00; /* sign extend */
+	return operand;
+}
+
+static inline u16 get_oper_gpr(struct b43_vm *vm, u16 operand)
+{
+	u16 reg;
+
+	reg = operand & 0x3F;
+
+	return vm->gpr[reg];
+}
+
+static inline u16 get_oper_spr(struct b43_vm *vm, u16 operand)
+{
+	u16 reg, value;
+
+	reg = operand & 0x1FF;
+	reg = (reg * 2) + 0x400; /* convert to driver MMIO */
+
+	if (reg == 0x632) {
+		/* Workaround for reading the TSF timer. */
+		if (vm->prev_spr_read_offset == 0x638)
+			return vm->prev_tsf0_value;
+	}
+	vm->prev_spr_read_offset = reg;
+
+	switch (reg) {
+	case 0x4C0 ... 0x4CC: /* Offset register read */
+		reg = (reg - 0x4C0) / 2;
+		return vm->off[reg];
+	case 0x4D0 ... 0x4D6: /* Link register read */
+		reg = (reg - 0x4D0) / 2;
+		return vm->lr[reg];
+	}
+
+	value = b43_read16(vm->dev, reg);
+
+	if (reg == 0x632)
+		vm->prev_tsf0_value = value;
+
+	return value;
+}
+
+static inline u16 get_oper(struct b43_vm *vm, u16 operand)
+{
+	if (!(operand & 0x800))
+		return get_oper_memory(vm, operand);
+	if ((operand & 0xC00) == 0xC00)
+		return get_oper_immediate(vm, operand);
+	if ((operand & 0xFC0) == 0xBC0)
+		return get_oper_gpr(vm, operand);
+	if ((operand & 0xE00) == 0x800)
+		return get_oper_spr(vm, operand);
+	if ((operand & 0xE00) == 0xA00)
+		return get_oper_memory_indirect(vm, operand);
+
+	b43err(vm->dev->wl, "VM: get_oper: Unknown operand type: 0x%04X\n", operand);
+	vm->crashed = 1;
+	return 0;
+}
+
+static inline bool get_ext_condition(struct b43_vm *vm, u16 cond)
+{
+	struct b43_wldev *dev = vm->dev;
+	u8 request_reg, status_reg, bit;
+	u16 tmp, mask;
+	unsigned long start;
+
+	cond &= 0xFF;
+
+	if (cond == 0x7F)
+		return 1;	/* Always true */
+
+	if (unlikely(cond == 0xFF)) {
+		b43err(vm->dev->wl, "VM: Invalid external condition 0xFF\n");
+		vm->crashed = 1;
+		return 0;
+	}
+
+	request_reg = (cond / 16) + B43_VM_EXTCOND_REQ_START;
+	status_reg = (cond / 16) + B43_VM_EXTCOND_STATUS_START;
+	bit = (cond % 16);
+	mask = (1 << bit);
+
+	start = jiffies;
+
+	/* Request the condition */
+	b43_shm_write16_hardware(dev, B43_SHM_SCRATCH, request_reg, mask);
+	while (1) {
+		/* Wait for the dummy firmware on the device to clear
+		 * the bit. This notifies that it read and possibly EOI'd
+		 * the condition. */
+		tmp = b43_shm_read16_hardware(dev, B43_SHM_SCRATCH, request_reg);
+		if (!tmp)
+			break;
+		if (unlikely(time_after(jiffies, start + (2 * HZ)))) {
+			b43err(dev->wl, "VM: External condition timeout\n");
+			vm->crashed = 1;
+			return 0;
+		}
+		cpu_relax();
+	}
+	/* Now read the condition from the condition status register */
+	tmp = b43_shm_read16_hardware(dev, B43_SHM_SCRATCH, status_reg);
+
+	return !!(tmp & mask);
+}
+
+static void insn_srx(struct b43_vm *vm,
+		     u16 op, u16 x, u16 y, u16 z)
+{
+	u16 m, s, tmp, result;
+
+	m = get_mask(op);
+	s = get_shift(op);
+
+	tmp = (get_oper(vm, y) << 16) | get_oper(vm, x);
+	result = (tmp >> s) & m;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_orx(struct b43_vm *vm,
+		     u16 op, u16 x, u16 y, u16 z)
+{
+	u16 m, s, tmp, result;
+
+	m = get_mask(op);
+	s = get_shift(op);
+
+	m = rol16(m, s);
+	tmp = rol16(get_oper(vm, x), s);
+	result = (tmp & m) | (get_oper(vm, y) & ~m);
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_jzx(struct b43_vm *vm,
+		     u16 op, u16 x, u16 y, u16 z)
+{
+	u16 m, s;
+	u32 x_val, y_val;
+
+	m = get_mask(op);
+	s = get_shift(op);
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+
+	if (((((y_val << 16) | x_val) >> s) & m) == 0)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jnzx(struct b43_vm *vm,
+		      u16 op, u16 x, u16 y, u16 z)
+{
+	u16 m, s;
+	u32 x_val, y_val;
+
+	m = get_mask(op);
+	s = get_shift(op);
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+
+	if (((((y_val << 16) | x_val) >> s) & m) != 0)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jnext(struct b43_vm *vm,
+		       u16 op, u16 x, u16 y, u16 z)
+{
+	bool cond;
+
+	cond = get_ext_condition(vm, op);
+	if (!cond)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jext(struct b43_vm *vm,
+		      u16 op, u16 x, u16 y, u16 z)
+{
+	bool cond;
+
+	cond = get_ext_condition(vm, op);
+	if (cond)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_add(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val + y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_add_setc(struct b43_vm *vm,
+			  u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val + y_val;
+	put_result(vm, z, result);
+	if ((u32)x_val + (u32)y_val > 0xFFFF)
+		vm->add_carry = 1;
+	else
+		vm->add_carry = 0;
+
+	vm->pc++;
+}
+
+static void insn_addc(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, carry, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	carry = (u16)vm->add_carry;
+	result = x_val + y_val + carry;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_addc_setc(struct b43_vm *vm,
+			   u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, carry, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	carry = (u16)vm->add_carry;
+	result = x_val + y_val + carry;
+	put_result(vm, z, result);
+	if ((u32)x_val + (u32)y_val + (u32)carry > 0xFFFF)
+		vm->add_carry = 1;
+	else
+		vm->add_carry = 0;
+
+	vm->pc++;
+}
+
+static void insn_sub(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val - y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_sub_setc(struct b43_vm *vm,
+			  u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val - y_val;
+	put_result(vm, z, result);
+	if (x_val < y_val)
+		vm->sub_carry = 1;
+	else
+		vm->sub_carry = 0;
+
+	vm->pc++;
+}
+
+static void insn_subc(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, carry, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	carry = (u16)vm->sub_carry;
+	result = x_val - y_val - carry;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_subc_setc(struct b43_vm *vm,
+			   u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, carry, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	carry = (u16)vm->sub_carry;
+	result = x_val - y_val - carry;
+	put_result(vm, z, result);
+	if ((carry && y_val == 0xFFFF) ||
+	    ((u32)x_val < ((u32)y_val + (u32)carry)))
+		vm->sub_carry = 1;
+	else
+		vm->sub_carry = 0;
+
+	vm->pc++;
+}
+
+static void insn_sra(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val >> y_val;
+	if (x_val & 0x8000) {
+		/* signed */
+		if (y_val >= 16)
+			y_val = 16;
+		result |= (0xFFFF << (16 - y_val));
+	}
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_or(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val | y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_and(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val & y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_xor(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val ^ y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_sr(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val >> y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_sl(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val << y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_rl(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = rol16(x_val, y_val);
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_rr(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = ror16(x_val, y_val);
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_nand(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val, result;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	result = x_val & ~y_val;
+	put_result(vm, z, result);
+
+	vm->pc++;
+}
+
+static void insn_jand(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val & y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jnand(struct b43_vm *vm,
+		       u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (!(x_val & y_val))
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_js(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if ((x_val & y_val) == x_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jns(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if ((x_val & y_val) != x_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_je(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val == y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jne(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val != y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jls(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	s16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val < y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jges(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	s16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val >= y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jgs(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	s16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val > y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jles(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	s16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val <= y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jl(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val < y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jge(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val >= y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jg(struct b43_vm *vm,
+		    u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val > y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_jle(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 x_val, y_val;
+
+	x_val = get_oper(vm, x);
+	y_val = get_oper(vm, y);
+	if (x_val <= y_val)
+		vm->pc = z;
+	else
+		vm->pc++;
+}
+
+static void insn_call(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	if (unlikely(x >= ARRAY_SIZE(vm->lr))) {
+		b43err(vm->dev->wl,
+		       "VM: Invalid link register %u at CALL\n", x);
+		vm->crashed = 1;
+		return;
+	}
+	vm->lr[x] = vm->pc + 1;
+	vm->pc = z;
+}
+
+static void insn_ret(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+	u16 target;
+
+	if (unlikely(x >= ARRAY_SIZE(vm->lr))) {
+		b43err(vm->dev->wl,
+		       "VM: Invalid link register (a) %u at CALL\n", x);
+		vm->crashed = 1;
+		return;
+	}
+	if (unlikely(z >= ARRAY_SIZE(vm->lr))) {
+		b43err(vm->dev->wl,
+		       "VM: Invalid link register (b) %u at CALL\n", z);
+		vm->crashed = 1;
+		return;
+	}
+	target = vm->lr[z];
+	vm->lr[x] = vm->pc + 1;
+	vm->pc = target;
+}
+
+static void insn_tkip(struct b43_vm *vm,
+		      u16 x, u16 y, u16 z)
+{
+	//TODO
+	vm->pc++;
+}
+
+static void insn_nap(struct b43_vm *vm,
+		     u16 x, u16 y, u16 z)
+{
+#if 0
+	struct b43_wldev *dev = vm->dev;
+	u16 mask, tmp;
+	unsigned long start;
+
+	/* Tell the dummy firmware to NAP and spinwait
+	 * until it wakes up. */
+	start = jiffies;
+	mask = (1 << B43_VM_NAP_BIT);
+	b43_shm_write16_hardware(dev, B43_SHM_SCRATCH, B43_VM_NAP_REG, mask);
+	while (1) {
+		tmp = b43_shm_read16_hardware(dev, B43_SHM_SCRATCH, B43_VM_NAP_REG);
+		if (!tmp)
+			break;
+		if (unlikely(time_after(jiffies, start + (5 * HZ)))) {
+			b43err(dev->wl, "VM: NAP timeout\n");
+			vm->crashed = 1;
+			return;
+		}
+	}
+#endif
+	vm->pc++;
+}
+
+static int b43_vm_kthread(void *data)
+{
+	struct b43_vm *vm = data;
+	u64 code;
+	u16 opcode;	/* The current opcode */
+	u16 oper[3];	/* The current operands */
+
+	set_freezable();
+
+	spin_lock(&vm->lock);
+
+	vm->insn_per_sec = 0;
+	vm->speed_calc_time = jiffies - (HZ * 1);
+	while (1) {
+		spin_unlock(&vm->lock);
+
+		if (unlikely(kthread_should_stop()))
+			goto out;
+		try_to_freeze();
+		cond_resched();
+
+		spin_lock(&vm->lock);
+
+		if (unlikely(vm->crashed))
+			goto vm_crash_locked;
+
+		vm->insn_cnt++;
+		if (time_after(jiffies, vm->speed_calc_time + (HZ * 1))) {
+			vm->speed_calc_time = jiffies;
+			if (unlikely(vm->insn_per_sec == 0))
+				vm->insn_per_sec = vm->insn_cnt;
+			else
+				vm->insn_per_sec = (vm->insn_per_sec + vm->insn_cnt) / 2;
+			vm->insn_cnt = 0;
+		}
+
+		/* Fetch the next instruction */
+		if (unlikely(vm->pc * 8 >= vm->code_size)) {
+			b43err(vm->dev->wl, "VM: PC out of bounds (%u >= %u)\n",
+			       (unsigned int)(vm->pc * 8), (unsigned int)vm->code_size);
+			goto vm_crash_locked;
+		}
+		code = insn_at_pc(vm, vm->pc);
+
+		opcode = (code >> 36) & 0xFFF;
+		oper[0] = (code >> 24) & 0xFFF;
+		oper[1] = (code >> 12) & 0xFFF;
+		oper[2] = code & 0xFFF;
+
+		/* Handle M/S opcodes */
+		switch (opcode & 0xF00) {
+		case 0x200: /* SRX */
+			insn_srx(vm, opcode, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x300: /* ORX */
+			insn_orx(vm, opcode, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x400: /* JZX */
+			insn_jzx(vm, opcode, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x500: /* JNZX */
+			insn_jnzx(vm, opcode, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x600: /* JNEXT */
+			insn_jnext(vm, opcode, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x700: /* JEXT */
+			insn_jext(vm, opcode, oper[0], oper[1], oper[2]);
+			continue;
+		}
+
+		/* Handle constant opcodes */
+		switch (opcode) {
+		case 0x1C0: /* ADD */
+			insn_add(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1C2: /* ADD. */
+			insn_add_setc(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1C1: /* ADDC */
+			insn_addc(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1C3: /* ADDC. */
+			insn_addc_setc(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1D0: /* SUB */
+			insn_sub(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1D2: /* SUB. */
+			insn_sub_setc(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1D1: /* SUBC */
+			insn_subc(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1D3: /* SUBC. */
+			insn_subc_setc(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x130: /* SRA */
+			insn_sra(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x160: /* OR */
+			insn_or(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x140: /* AND */
+			insn_and(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x170: /* XOR */
+			insn_xor(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x120: /* SR */
+			insn_sr(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x110: /* SL */
+			insn_sl(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1A0: /* RL */
+			insn_rl(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1B0: /* RR */
+			insn_rr(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x150: /* NAND */
+			insn_nand(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x040: /* JAND */
+			insn_jand(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x040 | 0x1): /* JNAND */
+			insn_jnand(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x050: /* JS */
+			insn_js(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x050 | 0x1): /* JNS */
+			insn_jns(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x0D0: /* JE */
+			insn_je(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x0D0 | 0x1): /* JNE */
+			insn_jne(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x0D2: /* JLS */
+			insn_jls(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x0D2 | 0x1): /* JGES */
+			insn_jges(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x0D4: /* JGS */
+			insn_jgs(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x0D4 | 0x1): /* JLES */
+			insn_jles(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x0DA: /* JL */
+			insn_jl(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x0DA | 0x1): /* JGE */
+			insn_jge(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x0DC: /* JG */
+			insn_jg(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case (0x0DC | 0x1): /* JLE */
+			insn_jle(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x002: /* CALL */
+			insn_call(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x003: /* RET */
+			insn_ret(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x1E0: /* TKIP */
+			insn_tkip(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x001: /* NAP */
+			insn_nap(vm, oper[0], oper[1], oper[2]);
+			continue;
+		case 0x0D6: /* Instructions with unknown semantics. */
+		case 0x0D9:
+			b43warn(vm->dev->wl,
+				"VM: Executing unknown instruction 0x%03X\n",
+				opcode);
+			vm->pc++; /* no operation */
+			continue;
+		}
+
+		b43err(vm->dev->wl, "VM: Invalid opcode 0x%03X\n", opcode);
+		goto vm_crash_locked;
+	}
+
+out:
+b43_vm_print_dump(vm);
+	return 0;
+
+vm_crash_locked:
+	b43_vm_print_dump(vm);
+	spin_unlock(&vm->lock);
+	while (!kthread_should_stop())
+		schedule();
+
+	return -ECANCELED;
+}
+
+int b43_vm_init(struct b43_wldev *dev)
+{
+	struct b43_request_fw_context *fwctx;
+	struct b43_vm *vm;
+	int err;
+
+	if (!modparam_vm_enable)
+		return 0;
+
+	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+	if (!vm) {
+		err = -ENOMEM;
+		b43warn(dev->wl, "VM: Failed to allocate memory\n");
+		goto out;
+	}
+	fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
+	if (!fwctx) {
+		err = -ENOMEM;
+		b43warn(dev->wl, "VM: Failed to allocate memory\n");
+		goto err_free_vm;
+	}
+
+	fwctx->dev = dev;
+	fwctx->req_type = B43_FWTYPE_VM;
+	err = b43_do_request_fw(fwctx, "ucode5", &vm->fw);
+	if (err) {
+		b43warn(dev->wl, fwctx->errors[B43_FWTYPE_VM]);
+		b43warn(dev->wl, "VM: Failed to request the VM firmware\n");
+		goto err_free_fwctx;
+	}
+	kfree(fwctx);
+	fwctx = NULL;
+
+	spin_lock_init(&vm->lock);
+	vm->dev = dev;
+	dev->vm = vm;
+	vm->code = dev->fw.ucode.data->data + sizeof(struct b43_fw_header);
+	vm->code_size = dev->fw.ucode.data->size - sizeof(struct b43_fw_header);
+
+	err = 0;
+	b43info(dev->wl, "Running firmware inside of a virtual machine!\n");
+out:
+	return err;
+
+err_free_fwctx:
+	kfree(fwctx);
+err_free_vm:
+	kfree(vm);
+	dev->vm = NULL;
+
+	return err;
+}
+
+void b43_vm_exit(struct b43_wldev *dev)
+{
+	struct b43_vm *vm = dev->vm;
+
+	if (!b43_vm_enabled(dev))
+		return;
+
+	b43_vm_stop(dev);
+	b43_do_release_fw(&vm->fw);
+	kfree(vm);
+	dev->vm = NULL;
+}
+
+static ssize_t dfs_dump_read(struct b43_wldev *dev, char *buf, size_t bufsize)
+{
+	struct b43_vm *vm = dev->vm;
+	const char *dump;
+	size_t len;
+	int err = 0;
+
+	spin_lock(&vm->lock);
+	dump = b43_vm_dump_core(vm);
+	if (!dump) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+	len = min(strlen(dump), bufsize);
+	memcpy(buf, dump, len);
+	b43_vm_free_coredump(dump);
+out_unlock:
+	spin_unlock(&vm->lock);
+
+	return err ? err : len;
+}
+
+B43_DEBUGFS_FOPS(vm_dump, dfs_dump_read, NULL, 0);
+
+static int b43_vm_debugfs_init(struct b43_vm *vm)
+{
+	b43_dfs_create_file(vm->dev, vm_dump, 0400);
+
+	return 0;
+}
+
+static void b43_vm_debugfs_exit(struct b43_vm *vm)
+{
+	debugfs_remove(vm->dev->dfsentry->file_vm_dump.dentry);
+}
+
+int b43_vm_start(struct b43_wldev *dev)
+{
+	struct b43_vm *vm = dev->vm;
+	int err;
+
+	if (!b43_vm_enabled(dev))
+		return 0;
+
+	vm->kthread = kthread_run(b43_vm_kthread, vm,
+				  "b43-%s-vm",
+				  wiphy_name(dev->wl->hw->wiphy));
+	if (IS_ERR(vm->kthread)) {
+		err = PTR_ERR(vm->kthread);
+		b43warn(dev->wl, "VM: Failed to create kernel thread\n");
+		goto out;
+	}
+
+	b43_vm_debugfs_init(vm);
+	vm->started = 1;
+	err = 0;
+out:
+	return err;
+}
+
+void b43_vm_stop(struct b43_wldev *dev)
+{
+	struct b43_vm *vm = dev->vm;
+
+	if (!b43_vm_enabled(dev))
+		return;
+
+	if (vm->started) {
+		vm->started = 0;
+		b43_vm_debugfs_exit(vm);
+		kthread_stop(vm->kthread);
+	}
+}
+
+bool b43_vm_enabled(struct b43_wldev *dev)
+{
+	return (modparam_vm_enable && dev->vm);
+}
+
+struct b43_firmware_file * b43_vm_get_device_firmware(struct b43_wldev *dev)
+{
+	struct b43_vm *vm = dev->vm;
+
+	if (!b43_vm_enabled(dev))
+		return NULL;
+	return &vm->fw;
+}
+
+u16 b43_vm_gpr_read(struct b43_wldev *dev, u8 gpr)
+{
+	struct b43_vm *vm = dev->vm;
+	u16 val;
+
+	if (B43_WARN_ON(gpr >= ARRAY_SIZE(dev->vm->gpr)))
+		return 0;
+	spin_lock(&vm->lock);
+	val = dev->vm->gpr[gpr];
+	spin_unlock(&vm->lock);
+
+	return val;
+}
+
+void b43_vm_gpr_write(struct b43_wldev *dev, u8 gpr, u16 value)
+{
+	struct b43_vm *vm = dev->vm;
+
+	if (B43_WARN_ON(gpr >= ARRAY_SIZE(dev->vm->gpr)))
+		return;
+	spin_lock(&vm->lock);
+	dev->vm->gpr[gpr] = value;
+	spin_unlock(&vm->lock);
+}
Index: wireless-testing/drivers/net/wireless/b43/vm.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/drivers/net/wireless/b43/vm.h	2008-06-15 15:25:06.000000000 +0200
@@ -0,0 +1,138 @@
+#ifndef B43_VIRTUAL_FIRMWARE_MACHINE_H_
+#define B43_VIRTUAL_FIRMWARE_MACHINE_H_
+
+#include "b43.h"
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+
+struct dentry;
+struct task_struct;
+struct b43_wldev;
+
+/* A B43 microcode virtual machine. */
+struct b43_vm {
+	/* The device we belong to. */
+	struct b43_wldev *dev;
+	/* The kernel thread of the VM. */
+	struct task_struct *kthread;
+
+	/* Pointer to the VM-firmware that runs on the device.
+	 * The VM-firmware does only forward internal device state
+	 * to the VM. */
+	struct b43_firmware_file fw;
+
+	/* The firmware code. */
+	const u8 *code;
+	size_t code_size;
+
+	/* Instruction counter for calculating the insn/sec value. */
+	u64 insn_cnt;
+	/* Last jiffies when the insn/sec was calculated. */
+	unsigned long speed_calc_time;
+	/* Average instructions per second. */
+	u64 insn_per_sec;
+
+	/* The current program counter */
+	u16 pc;
+	/* The link registers */
+	u16 lr[4];
+	/* The offset registers */
+	u16 off[7];
+	/* The general purpose registers. */
+	u16 gpr[64];
+	/* The ADD carry bit */
+	bool add_carry;
+	/* The SUB carry bit */
+	bool sub_carry;
+	/* If "crashed" is set, a fatal crash occured. */
+	bool crashed;
+
+	/* TSF timer read workaround. */
+	u16 prev_spr_read_offset;
+	u16 prev_tsf0_value;
+
+	bool started;
+	spinlock_t lock;
+};
+
+/* Hardware GPR start for the external condition status */
+#define B43_VM_EXTCOND_STATUS_START	0
+/* Hardware GPR start for the external condition request */
+#define B43_VM_EXTCOND_REQ_START	16
+/* Hardware GPR that contains the NAP request bit */
+#define B43_VM_NAP_REG			31
+/* Bit in the hardware GPR that notifies a NAP request */
+#define B43_VM_NAP_BIT			15
+
+
+
+#ifdef CONFIG_B43_DEBUG
+
+int b43_vm_init(struct b43_wldev *dev);
+void b43_vm_exit(struct b43_wldev *dev);
+
+int b43_vm_start(struct b43_wldev *dev);
+void b43_vm_stop(struct b43_wldev *dev);
+
+bool b43_vm_enabled(struct b43_wldev *dev);
+struct b43_firmware_file * b43_vm_get_device_firmware(struct b43_wldev *dev);
+
+u16 b43_vm_gpr_read(struct b43_wldev *dev, u8 gpr);
+void b43_vm_gpr_write(struct b43_wldev *dev, u8 gpr, u16 value);
+
+
+#else /* CONFIG_B43_DEBUG */
+
+
+static inline
+int b43_vm_init(struct b43_wldev *dev)
+{
+	return 0;
+}
+
+static inline
+void b43_vm_exit(struct b43_wldev *dev)
+{
+}
+
+static inline
+int b43_vm_start(struct b43_wldev *dev)
+{
+	return 0;
+}
+
+static inline
+void b43_vm_stop(struct b43_wldev *dev)
+{
+}
+
+static inline
+bool b43_vm_enabled(struct b43_wldev *dev)
+{
+	return 0;
+}
+
+static inline
+struct b43_firmware_file * b43_vm_get_device_firmware(struct b43_wldev *dev)
+{
+	return NULL;
+}
+
+static inline
+u16 b43_vm_gpr_read(struct b43_wldev *dev, u8 gpr)
+{
+	B43_WARN_ON(1);
+	return 0;
+}
+
+static inline
+void b43_vm_gpr_write(struct b43_wldev *dev, u8 gpr, u16 value)
+{
+	B43_WARN_ON(1);
+}
+
+#endif /* CONFIG_B43_DEBUG */
+
+#endif /* B43_VIRTUAL_FIRMWARE_MACHINE_H_ */
Index: wireless-testing/drivers/net/wireless/b43/main.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/main.c	2008-06-15 15:24:53.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/main.c	2008-06-15 15:25:06.000000000 +0200
@@ -50,12 +50,13 @@
 #include "dma.h"
 #include "pio.h"
 #include "sysfs.h"
 #include "xmit.h"
 #include "lo.h"
 #include "pcmcia.h"
+#include "vm.h"
 
 MODULE_DESCRIPTION("Broadcom B43 wireless driver");
 MODULE_AUTHOR("Martin Langer");
 MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
@@ -376,12 +377,14 @@ static inline void b43_shm_control_word(
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 	u32 ret;
 
+	B43_WARN_ON(routing == B43_SHM_SCRATCH);
+
 	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
@@ -399,13 +402,13 @@ u32 b43_shm_read32(struct b43_wldev *dev
 out:
 	spin_unlock_irqrestore(&wl->shm_lock, flags);
 
 	return ret;
 }
 
-u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
+u16 b43_shm_read16_hardware(struct b43_wldev *dev, u16 routing, u16 offset)
 {
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 	u16 ret;
 
 	spin_lock_irqsave(&wl->shm_lock, flags);
@@ -425,17 +428,28 @@ u16 b43_shm_read16(struct b43_wldev * de
 out:
 	spin_unlock_irqrestore(&wl->shm_lock, flags);
 
 	return ret;
 }
 
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+	if (routing == B43_SHM_SCRATCH) {
+		if (b43_vm_enabled(dev))
+			return b43_vm_gpr_read(dev, offset);
+	}
+	return b43_shm_read16_hardware(dev, routing, offset);
+}
+
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 
+	B43_WARN_ON(routing == B43_SHM_SCRATCH);
+
 	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
@@ -450,13 +464,13 @@ void b43_shm_write32(struct b43_wldev *d
 	b43_shm_control_word(dev, routing, offset);
 	b43_write32(dev, B43_MMIO_SHM_DATA, value);
 out:
 	spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
-void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+void b43_shm_write16_hardware(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 {
 	struct b43_wl *wl = dev->wl;
 	unsigned long flags;
 
 	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
@@ -472,12 +486,23 @@ void b43_shm_write16(struct b43_wldev *d
 	b43_shm_control_word(dev, routing, offset);
 	b43_write16(dev, B43_MMIO_SHM_DATA, value);
 out:
 	spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+{
+	if (routing == B43_SHM_SCRATCH) {
+		if (b43_vm_enabled(dev)) {
+			b43_vm_gpr_write(dev, offset, value);
+			return;
+		}
+	}
+	b43_shm_write16_hardware(dev, routing, offset, value);
+}
+
 /* Read HostFlags */
 u64 b43_hf_read(struct b43_wldev * dev)
 {
 	u64 ret;
 
 	ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
@@ -2008,12 +2033,16 @@ int b43_do_request_fw(struct b43_request
 		break;
 	case B43_FWTYPE_OPENSOURCE:
 		snprintf(ctx->fwname, sizeof(ctx->fwname),
 			 "b43-open%s/%s.fw",
 			 modparam_fwpostfix, name);
 		break;
+	case B43_FWTYPE_VM:
+		snprintf(ctx->fwname, sizeof(ctx->fwname),
+			 "b43-vm/%s.fw", name);
+		break;
 	default:
 		B43_WARN_ON(1);
 		return -ENOSYS;
 	}
 	err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
 	if (err == -ENOENT) {
@@ -2244,34 +2273,41 @@ static int b43_upload_microcode(struct b
 	const size_t hdr_len = sizeof(struct b43_fw_header);
 	const __be32 *data;
 	unsigned int i, len;
 	u16 fwrev, fwpatch, fwdate, fwtime;
 	u32 tmp, macctl;
 	int err = 0;
+	struct b43_firmware_file *ucode_file;
 
 	/* Jump the microcode PSM to offset 0 */
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
 	B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
 	macctl |= B43_MACCTL_PSM_JMP0;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 	/* Zero out all microcode PSM registers and shared memory. */
 	for (i = 0; i < 64; i++)
 		b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
 	for (i = 0; i < 4096; i += 2)
 		b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
 
+	/* If we want to run the real firmware in a VM, we need
+	 * to upload the dummy wrapper firmware to the device. */
+	ucode_file = b43_vm_get_device_firmware(dev);
+	if (!ucode_file)
+		ucode_file = &dev->fw.ucode;
+
 	/* Upload Microcode. */
-	data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
-	len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
+	data = (__be32 *) (ucode_file->data->data + hdr_len);
+	len = (ucode_file->data->size - hdr_len) / sizeof(__be32);
 	b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
 	for (i = 0; i < len; i++) {
 		b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
 		udelay(10);
 	}
 
-	if (dev->fw.pcm.data) {
+	if (dev->fw.pcm.data && (ucode_file->type != B43_FWTYPE_VM)) {
 		/* Upload PCM data. */
 		data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
 		len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
 		b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
 		b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
 		/* No need for autoinc bit in SHM_HW */
@@ -2287,12 +2323,15 @@ static int b43_upload_microcode(struct b
 	/* Start the microcode PSM */
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
 	macctl &= ~B43_MACCTL_PSM_JMP0;
 	macctl |= B43_MACCTL_PSM_RUN;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
+	/* Now fire up the microcode in the VM, if we use one. */
+	b43_vm_start(dev);
+
 	/* Wait for the microcode to load and respond */
 	i = 0;
 	while (1) {
 		tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
 		if (tmp == B43_IRQ_MAC_SUSPENDED)
 			break;
@@ -2715,12 +2754,13 @@ static void b43_mgmtframe_txantenna(stru
 /* This is the opposite of b43_chip_init() */
 static void b43_chip_exit(struct b43_wldev *dev)
 {
 	b43_radio_turn_off(dev, 1);
 	b43_gpio_cleanup(dev);
 	b43_lo_g_cleanup(dev);
+	b43_vm_exit(dev);
 	/* firmware is released later */
 }
 
 /* Initialize the chip
  * http://bcm-specs.sipsolutions.net/ChipInit
  */
@@ -2737,20 +2777,21 @@ static int b43_chip_init(struct b43_wlde
 		macctl |= B43_MACCTL_GMODE;
 	macctl |= B43_MACCTL_INFRA;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
 	err = b43_request_firmware(dev);
 	if (err)
-		goto out;
+		goto error;
+	b43_vm_init(dev);
 	err = b43_upload_microcode(dev);
 	if (err)
-		goto out;	/* firmware is released later */
+		goto error;	/* firmware is released later */
 
 	err = b43_gpio_init(dev);
 	if (err)
-		goto out;	/* firmware is released later */
+		goto error;	/* firmware is released later */
 
 	err = b43_upload_initvals(dev);
 	if (err)
 		goto err_gpio_clean;
 	b43_radio_turn_on(dev);
 
@@ -2811,19 +2852,21 @@ static int b43_chip_init(struct b43_wlde
 
 	b43_write16(dev, B43_MMIO_POWERUP_DELAY,
 		    dev->dev->bus->chipco.fast_pwrup_delay);
 
 	err = 0;
 	b43dbg(dev->wl, "Chip initialized\n");
-out:
+
 	return err;
 
 err_radio_off:
 	b43_radio_turn_off(dev, 1);
 err_gpio_clean:
 	b43_gpio_cleanup(dev);
+error:
+	b43_vm_exit(dev);
 	return err;
 }
 
 static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
@@ -3539,12 +3582,18 @@ static int b43_op_set_key(struct ieee802
 
 	dev = wl->current_dev;
 	err = -ENODEV;
 	if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
 		goto out_unlock;
 
+	if (b43_vm_enabled(dev)) {
+		/* We are running the firmware in the VM, so
+		 * we can not support hwcrypto. */
+		err = -EOPNOTSUPP;
+		goto out_unlock;
+	}
 	if (dev->fw.pcm_request_failed) {
 		/* We don't have firmware for the crypto engine.
 		 * Must use software-crypto. */
 		err = -EOPNOTSUPP;
 		goto out_unlock;
 	}
Index: wireless-testing/drivers/net/wireless/b43/main.h
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/main.h	2008-06-15 15:24:50.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/main.h	2008-06-15 15:25:06.000000000 +0200
@@ -93,14 +93,16 @@ u8 b43_ieee80211_antenna_sanitize(struct
 
 void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
 void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
 
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
 u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
+u16 b43_shm_read16_hardware(struct b43_wldev *dev, u16 routing, u16 offset);
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
 void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
+void b43_shm_write16_hardware(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
 
 u64 b43_hf_read(struct b43_wldev *dev);
 void b43_hf_write(struct b43_wldev *dev, u64 value);
 
 void b43_dummy_transmission(struct b43_wldev *dev);
 
Index: wireless-testing/drivers/net/wireless/b43/dasm.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/drivers/net/wireless/b43/dasm.c	2008-06-15 15:25:06.000000000 +0200
@@ -0,0 +1,363 @@
+/*
+
+  Broadcom B43 wireless driver
+  Tiny instruction disassembler
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.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; 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "dasm.h"
+
+#include <linux/string.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+
+
+static void b43_dasm_oper(char *buf, u16 oper)
+{
+	if (!(oper & 0x800)) {
+		sprintf(buf, "[0x%03X]", oper);
+		return;
+	}
+	if ((oper & 0xC00) == 0xC00) {
+		oper &= ~0xC00;
+		if (oper & (1 << 9))
+			sprintf(buf, "0x%04X", (oper | 0xFC00));
+		else
+			sprintf(buf, "0x%03X", oper);
+		return;
+	}
+	if ((oper & 0xFC0) == 0xBC0) {
+		sprintf(buf, "r%u", (oper & 0x3F));
+		return;
+	}
+	if ((oper & 0xE00) == 0x800) {
+		sprintf(buf, "spr%03X", (oper & 0x1FF));
+		return;
+	}
+	if ((oper & 0xE00) == 0xA00) {
+		sprintf(buf, "[0x%02X,off%u]",
+			(oper & 0x3F), ((oper >> 6) & 0x7));
+		return;
+	}
+
+	strcpy(buf, "UNKNOWN");
+}
+
+char * b43_dasm_instruction(u64 insn)
+{
+	unsigned int i;
+	char *ret;
+	u16 opcode;
+	u16 oper[3];
+	const char *name;
+	char ops[5][16];
+
+	memset(ops, 0, sizeof(ops));
+
+	opcode = (insn >> 36) & 0xFFF;
+	oper[0] = (insn >> 24) & 0xFFF;
+	oper[1] = (insn >> 12) & 0xFFF;
+	oper[2] = insn & 0xFFF;
+
+	switch (opcode & 0xF00) {
+	case 0x200:
+		name = "srx";
+		sprintf(ops[0], "%u", (opcode & 0x0F0) >> 4);
+		sprintf(ops[1], "%u", (opcode & 0x00F));
+		b43_dasm_oper(ops[2], oper[0]);
+		b43_dasm_oper(ops[3], oper[1]);
+		b43_dasm_oper(ops[4], oper[2]);
+		goto out;
+	case 0x300:
+		name = "orx";
+		sprintf(ops[0], "%u", (opcode & 0x0F0) >> 4);
+		sprintf(ops[1], "%u", (opcode & 0x00F));
+		b43_dasm_oper(ops[2], oper[0]);
+		b43_dasm_oper(ops[3], oper[1]);
+		b43_dasm_oper(ops[4], oper[2]);
+		goto out;
+	case 0x400:
+		name = "jzx";
+		sprintf(ops[0], "%u", (opcode & 0x0F0) >> 4);
+		sprintf(ops[1], "%u", (opcode & 0x00F));
+		b43_dasm_oper(ops[2], oper[0]);
+		b43_dasm_oper(ops[3], oper[1]);
+		sprintf(ops[4], "%04X", oper[2]);
+		goto out;
+	case 0x500:
+		name = "jnzx";
+		sprintf(ops[0], "%u", (opcode & 0x0F0) >> 4);
+		sprintf(ops[1], "%u", (opcode & 0x00F));
+		b43_dasm_oper(ops[2], oper[0]);
+		b43_dasm_oper(ops[3], oper[1]);
+		sprintf(ops[4], "%04X", oper[2]);
+		goto out;
+	case 0x600:
+		name = "jnext";
+		sprintf(ops[0], "0x%02X", (opcode & 0x0FF));
+		sprintf(ops[1], "%04X", oper[2]);
+		goto out;
+	case 0x700:
+		name = "jext";
+		sprintf(ops[0], "0x%02X", (opcode & 0x0FF));
+		sprintf(ops[1], "%04X", oper[2]);
+		goto out;
+	}
+
+	switch (opcode) {
+	case 0x1C0:
+		name = "add";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1C2:
+		name = "add.";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1C1:
+		name = "addc";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1C3:
+		name = "addc.";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1D0:
+		name = "sub";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1D2:
+		name = "sub.";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1D1:
+		name = "subc";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1D3:
+		name = "subc.";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x130:
+		name = "sra";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x160:
+		name = "or";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x140:
+		name = "and";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x170:
+		name = "xor";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x120:
+		name = "sr";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x110:
+		name = "sl";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1A0:
+		name = "rl";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x1B0:
+		name = "rr";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x150:
+		name = "nand";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		b43_dasm_oper(ops[2], oper[2]);
+		goto out;
+	case 0x040:
+		name = "jand";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x040 | 0x1):
+		name = "jnand";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x050:
+		name = "js";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x050 | 0x1):
+		name = "jns";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x0D0:
+		name = "je";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x0D0 | 0x1):
+		name = "jne";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x0D2:
+		name = "jls";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x0D2 | 0x1):
+		name = "jges";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x0D4:
+		name = "jgs";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x0D4 | 0x1):
+		name = "jles";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x0DA:
+		name = "jl";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x0DA | 0x1):
+		name = "jge";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x0DC:
+		name = "jg";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case (0x0DC | 0x1):
+		name = "jle";
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[1]);
+		sprintf(ops[2], "%04X", oper[2]);
+		goto out;
+	case 0x002:
+		name = "call";
+		sprintf(ops[0], "lr%u", oper[0]);
+		sprintf(ops[1], "%04X", oper[2]);
+		goto out;
+	case 0x003:
+		name = "ret";
+		sprintf(ops[0], "lr%u", oper[0]);
+		sprintf(ops[1], "lr%u", oper[2]);
+		goto out;
+	case 0x1E0:
+		switch (oper[1] & ~0xC00) {
+		case 0x1:
+			name = "tkiph";
+			break;
+		case (0x1 | 0x2):
+			name = "tkiphs";
+			break;
+		case 0x0:
+			name = "tkipl";
+			break;
+		case (0x0 | 0x2):
+			name = "tkipls";
+			break;
+		default:
+			name = "TKIP UNKNOWN";
+		}
+		b43_dasm_oper(ops[0], oper[0]);
+		b43_dasm_oper(ops[1], oper[2]);
+		goto out;
+	case 0x001:
+		name = "nap";
+		goto out;
+	}
+
+	name = "Unknown instruction";
+
+out:
+	ret = kmalloc(256, GFP_ATOMIC);
+	if (!ret) {
+		printk(KERN_ERR "b43 dasm: out of memory\n");
+		return NULL;
+	}
+	strcpy(ret, name);
+	for (i = 0; i <= 4; i++) {
+		if (strlen(ops[i])) {
+			strcat(ret, (i == 0) ? " " : ", ");
+			strcat(ret, ops[i]);
+		}
+	}
+
+	return ret;
+}
Index: wireless-testing/drivers/net/wireless/b43/dasm.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/drivers/net/wireless/b43/dasm.h	2008-06-15 15:25:06.000000000 +0200
@@ -0,0 +1,8 @@
+#ifndef B43_DISASSEMBLER_H_
+#define B43_DISASSEMBLER_H_
+
+#include <linux/types.h>
+
+char * b43_dasm_instruction(u64 insn);
+
+#endif /* B43_DISASSEMBLER_H_ */
Index: wireless-testing/drivers/net/wireless/b43/debugfs.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/debugfs.c	2008-06-15 15:24:51.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/debugfs.c	2008-06-15 15:25:06.000000000 +0200
@@ -37,21 +37,12 @@
 #include "xmit.h"
 
 
 /* The root directory. */
 static struct dentry *rootdir;
 
-struct b43_debugfs_fops {
-	ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
-	int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
-	struct file_operations fops;
-	/* Offset of struct b43_dfs_file in struct b43_dfsentry */
-	size_t file_struct_offset;
-	/* Take wl->irq_lock before calling read/write? */
-	bool take_irqlock;
-};
 
 static inline
 struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
 				       const struct b43_debugfs_fops *dfops)
 {
 	void *p;
@@ -350,20 +341,20 @@ static ssize_t loctls_read_file(struct b
 out:
 	return err ? err : count;
 }
 
 #undef fappend
 
-static int b43_debugfs_open(struct inode *inode, struct file *file)
+int b43_debugfs_open(struct inode *inode, struct file *file)
 {
 	file->private_data = inode->i_private;
 	return 0;
 }
 
-static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
-				size_t count, loff_t *ppos)
+ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
+			 size_t count, loff_t *ppos)
 {
 	struct b43_wldev *dev;
 	struct b43_debugfs_fops *dfops;
 	struct b43_dfs_file *dfile;
 	ssize_t uninitialized_var(ret);
 	char *buf;
@@ -423,15 +414,15 @@ static ssize_t b43_debugfs_read(struct f
 out_unlock:
 	mutex_unlock(&dev->wl->mutex);
 
 	return err ? err : ret;
 }
 
-static ssize_t b43_debugfs_write(struct file *file,
-				 const char __user *userbuf,
-				 size_t count, loff_t *ppos)
+ssize_t b43_debugfs_write(struct file *file,
+			  const char __user *userbuf,
+			  size_t count, loff_t *ppos)
 {
 	struct b43_wldev *dev;
 	struct b43_debugfs_fops *dfops;
 	char *buf;
 	int err = 0;
 
@@ -479,26 +470,12 @@ out_unlock:
 	mutex_unlock(&dev->wl->mutex);
 
 	return err ? err : count;
 }
 
 
-#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
-	static struct b43_debugfs_fops fops_##name = {		\
-		.read	= _read,				\
-		.write	= _write,				\
-		.fops	= {					\
-			.open	= b43_debugfs_open,		\
-			.read	= b43_debugfs_read,		\
-			.write	= b43_debugfs_write,		\
-		},						\
-		.file_struct_offset = offsetof(struct b43_dfsentry, \
-					       file_##name),	\
-		.take_irqlock	= _take_irqlock,		\
-	}
-
 B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
 B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
 B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
 B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
@@ -582,33 +559,19 @@ void b43_debugfs_add_device(struct b43_w
 		dev->dfsentry = NULL;
 		kfree(log->log);
 		kfree(e);
 		return;
 	}
 
-#define ADD_FILE(name, mode)	\
-	do {							\
-		struct dentry *d;				\
-		d = debugfs_create_file(__stringify(name),	\
-					mode, e->subdir, dev,	\
-					&fops_##name.fops);	\
-		e->file_##name.dentry = NULL;			\
-		if (!IS_ERR(d))					\
-			e->file_##name.dentry = d;		\
-	} while (0)
-
-
-	ADD_FILE(tsf, 0600);
-	ADD_FILE(ucode_regs, 0400);
-	ADD_FILE(shm, 0400);
-	ADD_FILE(txstat, 0400);
-	ADD_FILE(txpower_g, 0600);
-	ADD_FILE(restart, 0200);
-	ADD_FILE(loctls, 0400);
-
-#undef ADD_FILE
+	b43_dfs_create_file(dev, tsf, 0600);
+	b43_dfs_create_file(dev, ucode_regs, 0400);
+	b43_dfs_create_file(dev, shm, 0400);
+	b43_dfs_create_file(dev, txstat, 0400);
+	b43_dfs_create_file(dev, txpower_g, 0600);
+	b43_dfs_create_file(dev, restart, 0200);
+	b43_dfs_create_file(dev, loctls, 0400);
 
 	b43_add_dynamic_debug(dev);
 }
 
 void b43_debugfs_remove_device(struct b43_wldev *dev)
 {
@@ -616,12 +579,13 @@ void b43_debugfs_remove_device(struct b4
 
 	if (!dev)
 		return;
 	e = dev->dfsentry;
 	if (!e)
 		return;
+
 	b43_remove_dynamic_debug(dev);
 
 	debugfs_remove(e->file_tsf.dentry);
 	debugfs_remove(e->file_ucode_regs.dentry);
 	debugfs_remove(e->file_shm.dentry);
 	debugfs_remove(e->file_txstat.dentry);
Index: wireless-testing/drivers/net/wireless/b43/debugfs.h
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/debugfs.h	2008-06-15 15:24:51.000000000 +0200
+++ wireless-testing/drivers/net/wireless/b43/debugfs.h	2008-06-15 15:25:06.000000000 +0200
@@ -42,20 +42,69 @@ struct b43_dfsentry {
 	struct b43_dfs_file file_shm;
 	struct b43_dfs_file file_txstat;
 	struct b43_dfs_file file_txpower_g;
 	struct b43_dfs_file file_restart;
 	struct b43_dfs_file file_loctls;
 
+	struct b43_dfs_file file_vm_dump;
+
 	struct b43_txstatus_log txstatlog;
 
 	/* Enabled/Disabled list for the dynamic debugging features. */
 	u32 dyn_debug[__B43_NR_DYNDBG];
 	/* Dentries for the dynamic debugging entries. */
 	struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG];
 };
 
+struct b43_debugfs_fops {
+	ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
+	int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
+	struct file_operations fops;
+	/* Offset of struct b43_dfs_file in struct b43_dfsentry */
+	size_t file_struct_offset;
+	/* Take wl->irq_lock before calling read/write? */
+	bool take_irqlock;
+};
+
+int b43_debugfs_open(struct inode *inode, struct file *file);
+ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
+			 size_t count, loff_t *ppos);
+ssize_t b43_debugfs_write(struct file *file,
+			  const char __user *userbuf,
+			  size_t count, loff_t *ppos);
+
+#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
+	static struct b43_debugfs_fops fops_##name = {		\
+		.read	= _read,				\
+		.write	= _write,				\
+		.fops	= {					\
+			.open	= b43_debugfs_open,		\
+			.read	= b43_debugfs_read,		\
+			.write	= b43_debugfs_write,		\
+		},						\
+		.file_struct_offset = offsetof(struct b43_dfsentry, \
+					       file_##name),	\
+		.take_irqlock	= _take_irqlock,		\
+	}
+
+#define b43_dfs_create_file(dev, name, mode)			\
+  do {								\
+  	if (dev->dfsentry) {					\
+		struct dentry *d;				\
+		d = debugfs_create_file(__stringify(name),	\
+					mode,			\
+					dev->dfsentry->subdir,	\
+					dev,			\
+					&fops_##name.fops);	\
+		dev->dfsentry->file_##name.dentry = NULL;	\
+		if (!IS_ERR(d))					\
+			dev->dfsentry->file_##name.dentry = d;	\
+	}							\
+  } while (0)
+
+
 int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature);
 
 void b43_debugfs_init(void);
 void b43_debugfs_exit(void);
 void b43_debugfs_add_device(struct b43_wldev *dev);
 void b43_debugfs_remove_device(struct b43_wldev *dev);
Index: wireless-testing/scripts/b43-vm-fw-generator.py
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/scripts/b43-vm-fw-generator.py	2008-06-15 15:25:06.000000000 +0200
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# Script for generating a b43 device Virtual Machine support firmware.
+# This dummy firmware runs on the device while the real firmware runs
+# inside of the VM in the kernel.
+# This dummy firmware is used to export internal device state to the
+# kernel only.
+#
+# Use b43-asm from
+# http://git.bu3sch.de/git/b43-tools.git
+# to build the firmware.
+#
+# Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+# Licensed under the GNU/GPL version 2
+#
+
+
+# Start register of external condition status bits.
+COND_STATUS_REG_START = 0
+# Start register of external condition request bits.
+COND_REQUEST_REG_START = 16
+# Register that contains the NAP request bit.
+NAP_REG = 31
+# NAP request bit
+NAP_REQUEST_BIT = 15
+
+
+
+print "/* THIS CODE IS GENERATED. DO NOT EDIT. ALL CHANGES WILL BE LOST. */"
+print "\n"
+print "%arch 5"
+print "%start mainloop"
+print "\n\n"
+print "mainloop:"
+print "\n"
+
+# External conditions
+for cond in range(0, 0xFF + 1):
+	if cond == 0x7F or cond == 0xFF:
+		continue # These are special and not exported
+
+	req_gpr = (cond / 16) + COND_REQUEST_REG_START	# Condition request register
+	stat_gpr = (cond / 16) + COND_STATUS_REG_START	# Condition status register
+	bit = cond % 16					# Bit number in either register
+
+	print "/* External condition 0x%02X */" % (cond)
+	print "jzx 0, %u, r%u, 0, no_request+	/* Check if requested */" % (bit, req_gpr)
+	print "jext 0x%02X, set_bit+		/* Test external condition */" % (cond)
+	print "orx 0, %u, 0, r%u, r%u		/* Clear status bit */" % (bit, stat_gpr, stat_gpr)
+	print "jmp do_not_set+"
+	print "set_bit:"
+	print "orx 0, %u, 1, r%u, r%u		/* Set status bit */" % (bit, stat_gpr, stat_gpr)
+	print "do_not_set:"
+	print "orx 0, %u, 0, r%u, r%u		/* Clear request bit */" % (bit, req_gpr, req_gpr)
+	print "no_request:"
+	print "\n"
+
+# NAP request
+bit = NAP_REQUEST_BIT
+gpr = NAP_REG
+print "/* Check if NAP was requested */"
+print "jzx 0, %u, r%u, 0, no_nap_request+" % (bit, gpr)
+print "nap				/* zzzZZZzzzzz */"
+print "orx 0, %u, 0, r%u, r%u		/* Clear for wakeup notification */" % (bit, gpr, gpr)
+print "no_nap_request:"
+print "\n"
+
+print "jmp mainloop"
+print "\n// vim" + ": syntax=b43 ts=8"
