qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: Re: Re: Atheros Wireless Device Emulation


From: Clemens Kolbitsch
Subject: [Qemu-devel] Re: Re: Re: Atheros Wireless Device Emulation
Date: Tue, 18 Mar 2008 09:08:27 +0100
User-agent: KMail/1.9.6 (enterprise 0.20070907.709405)

Patch #5:

The most important/difficult/ugly part: Hardware I/O. It is handled over a 
direclty
mapped memory regions that is written to/read from the device driver code. Based
on ath5k and plenty of reverse engineering.

NOTE: I did NOT reimplement the hardware!! I simply handled the events as they 
come
in and mess with the device memory to fake a real device. Thus the code is 
quite hard to
understand. Sorry *g*




diff -Naur qemu/hw/atheros_wlan_io.c qemu-altered/hw/atheros_wlan_io.c
--- qemu/hw/atheros_wlan_io.c   1970-01-01 01:00:00.000000000 +0100
+++ qemu-altered/hw/atheros_wlan_io.c   2008-03-01 12:33:11.000000000 +0100
@@ -0,0 +1,1188 @@
+/**
+ * QEMU WLAN device emulation
+ * 
+ * Copyright (c) 2008 Clemens Kolbitsch
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Modifications:
+ *  2008-February-24  Clemens Kolbitsch :
+ *                                  New implementation based on ne2000.c
+ *
+ */
+
+
+#include "hw.h"
+#include "pci.h"
+#include "pc.h"
+#include "net.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <signal.h>
+
+#include <time.h>
+#include <sys/time.h>
+
+#include "hw/atheros_wlan.h"
+#include "hw/atheros_wlan_ap.h"
+
+
+/*
+ * MadWifi OPENHAL atheros constants
+ */
+#include "hw/ath5k.h"
+#include "hw/ath5k_hw.h"
+#include "hw/ath5kreg.h"
+
+
+static const struct Atheros_WLAN_frequency Atheros_WLAN_frequency_data[] =
+       {
+               { 20689, 3077, 2412 },          // channel 1
+               { 20715, 3078, 2417 },          // channel 2
+               { 20689, 3079, 2422 },          // channel 3
+               { 20715, 3079, 2427 },          // channel 4
+               { 20529, 3076, 2432 },          // channel 5
+               { 20507, 3078, 2437 },          // channel 6
+               { 20529, 3078, 2442 },          // channel 7
+               { 20507, 3079, 2447 },          // channel 8
+               { 20529, 3077, 2452 },          // channel 9
+               { 20635, 3078, 2457 },          // channel 10
+               { 20529, 3079, 2462 },          // channel 11
+               { 20635, 3079, 2467 },          // channel 12
+               { 20657, 3076, 2472 },          // channel 13
+               { 20529, 1029, 2484 }           // channel 14
+       };
+
+/*
+ * NOTE: By using this function instead
+ * of accessing the array directly through
+ * an index, we can leave out parts of the
+ * EEPROM data!!
+ */
+static int get_eeprom_data(Atheros_WLANState *s, uint32_t addr, uint32_t *val)
+{
+       if (val == NULL)
+       {
+               return 1;
+       }
+
+       // why?? but seems necessary...
+       addr--;
+
+       if ((addr < 0) || (addr > s->eeprom_size))
+       {
+               return 2;
+       }
+
+       *val = s->eeprom_data[addr];
+       return 0;
+}
+
+
+
+
+
+
+void updateFrequency(Atheros_WLANState *s)
+{
+       int i;
+       u_int32_t new_frequency = 0;
+       for (i=0; i < sizeof(Atheros_WLAN_frequency_data) / 
sizeof(Atheros_WLAN_frequency_data[0]); i++)
+       {
+               if (Atheros_WLAN_frequency_data[i].value1 != 
s->current_frequency_partial_data[0])
+                       continue;
+               
+               if (Atheros_WLAN_frequency_data[i].value2 != 
s->current_frequency_partial_data[1])
+                       continue;
+
+               new_frequency = Atheros_WLAN_frequency_data[i].frequency;
+               break;
+       }
+
+       if (new_frequency)
+       {
+               s->current_frequency = new_frequency;
+       }
+}
+
+
+
+static uint32_t mm_readl(Atheros_WLANState *s, target_phys_addr_t addr);
+static void mm_writel(Atheros_WLANState *s, target_phys_addr_t addr, uint32_t 
val);
+
+static void Atheros_WLAN_mmio_writeb(void *opaque, target_phys_addr_t addr, 
uint32_t val)
+{
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+       DEBUG_PRINT(("mmio_writeb %x val %x\n", addr, val));
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+}
+
+static void Atheros_WLAN_mmio_writew(void *opaque, target_phys_addr_t addr, 
uint32_t val)
+{
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+       DEBUG_PRINT(("mmio_writew %x val %x\n", addr, val));
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+}
+
+static void Atheros_WLAN_mmio_writel(void *opaque, target_phys_addr_t addr, 
uint32_t val)
+{
+       mm_writel((Atheros_WLANState *)opaque, Atheros_WLAN_MEM_SANITIZE(addr), 
val);
+       DEBUG_PRINT(("  through call: mmio_writel 0x%x (%u) val 0x%x (%u)\n", 
Atheros_WLAN_MEM_SANITIZE(addr), Atheros_WLAN_MEM_SANITIZE(addr), val, val));
+}
+
+static uint32_t Atheros_WLAN_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+       DEBUG_PRINT(("mmio_readb %u\n", addr));
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+       
+       return 0;
+}
+
+static uint32_t Atheros_WLAN_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+       DEBUG_PRINT(("mmio_readw %u\n", addr));
+       DEBUG_PRINT(("!!! DEBUG INIMPLEMENTED !!!\n"));
+
+       return 0;
+}
+
+static uint32_t Atheros_WLAN_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+       uint32_t val;
+       val = mm_readl((Atheros_WLANState *)opaque, 
Atheros_WLAN_MEM_SANITIZE(addr));
+
+       DEBUG_PRINT(("   mmio_readl 0x%x (%u) = 0x%x (%u)\n", 
Atheros_WLAN_MEM_SANITIZE(addr), Atheros_WLAN_MEM_SANITIZE(addr), val, val));
+       return val;
+}
+
+
+static void Atheros_WLAN_mmio_map(PCIDevice *pci_dev, int region_num, uint32_t 
addr, uint32_t size, int type)
+{
+       DEBUG_PRINT(("mmio_map\n"));
+       PCIAtheros_WLANState *d = (PCIAtheros_WLANState *)pci_dev;
+       Atheros_WLANState *s = &d->Atheros_WLAN;
+
+       DEBUG_PRINT(("cpu_register_physical_memory(%p, %u, %p);\n", (unsigned 
long*)addr, Atheros_WLAN_MEM_SIZE, (unsigned 
long*)s->Atheros_WLAN_mmio_io_addr));
+
+       cpu_register_physical_memory(addr + 0, Atheros_WLAN_MEM_SIZE, 
s->Atheros_WLAN_mmio_io_addr);
+}
+
+static CPUReadMemoryFunc *Atheros_WLAN_mmio_read[3] = {
+    Atheros_WLAN_mmio_readb,
+    Atheros_WLAN_mmio_readw,
+    Atheros_WLAN_mmio_readl,
+};
+
+static CPUWriteMemoryFunc *Atheros_WLAN_mmio_write[3] = {
+    Atheros_WLAN_mmio_writeb,
+    Atheros_WLAN_mmio_writew,
+    Atheros_WLAN_mmio_writel,
+};
+
+void Atheros_WLAN_setup_io(PCIAtheros_WLANState *d)
+{
+       Atheros_WLANState *s;
+       s = &d->Atheros_WLAN;
+
+       /* I/O handler for memory-mapped I/O */
+       s->Atheros_WLAN_mmio_io_addr = cpu_register_io_memory(0, 
Atheros_WLAN_mmio_read, Atheros_WLAN_mmio_write, s);
+       pci_register_io_region(&d->dev, 0, Atheros_WLAN_MEM_SIZE, 
PCI_ADDRESS_SPACE_MEM, Atheros_WLAN_mmio_map);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define FASTBINLOG(x)                                                  \
+               (x == 1)    ?  0 :                                      \
+               (x == 2)    ?  1 :                                      \
+               (x == 4)    ?  2 :                                      \
+               (x == 8)    ?  3 :                                      \
+               (x == 16)   ?  4 :                                      \
+               (x == 32)   ?  5 :                                      \
+               (x == 64)   ?  6 :                                      \
+               (x == 128)  ?  7 :                                      \
+               (x == 256)  ?  8 :                                      \
+               (x == 512)  ?  9 :                                      \
+               (x == 1024) ? 10 :                                      \
+               (x == 2048) ? 11 :                                      \
+               (x == 4096) ? 12 : 13
+
+
+
+static uint32_t mm_readl(Atheros_WLANState *s, target_phys_addr_t addr)
+{
+       uint32_t val = GET_MEM_L(s->mem, addr);
+       switch (addr)
+       {
+               case ATH_HW_IRQ_PENDING:
+                       /*
+                        * This indicates that the interrupt
+                        * routine has been called. reset interrupt
+                        * status and put the interrupt-status
+                        * number at the correct memory-location
+                        *
+                        * In case multiple interrupts are pending
+                        * this memory-location is checked multiple
+                        * times... each time, we put another interrupt
+                        * status into memory until no more interrupts
+                        * have to be handled
+                        */
+                       Atheros_WLAN_disable_irq(s);
+
+                       DEBUG_PRINT((">> irq pending? ... 0x%x\n", val));
+                       SET_MEM_L(s->mem, 0x0080, 0x0);
+                       SET_MEM_L(s->mem, 0x80ec, 0x0001c680);
+                       SET_MEM_L(s->mem, 0x80f0, 0x000055dc);
+                       SET_MEM_L(s->mem, 0x80f8, 0x0015f6fc);
+                       SET_MEM_L(s->mem, 0x9850, 0x0de8b0da);
+                       break;
+
+               /*
+                * The following registers are Read-and-Clear
+                * registers --> must be reset after a read!!
+                *
+                * However, it does not work when using linux!!
+                */
+               case AR5K_PISR:
+                       if (s->device_driver_type == WINXP_DRIVER)
+                       {
+                               addr = AR5K_RAC_PISR;
+                               // fall through...
+                       }
+                       else
+                       {
+                               break;
+                       }
+
+               case AR5K_RAC_PISR:
+                       Atheros_WLAN_update_irq(s);
+                       val = GET_MEM_L(s->mem, addr);
+                       SET_MEM_L(s->mem, addr, 0);
+                       SET_MEM_L(s->mem, AR5K_PCICFG, 0x34);
+
+                       DEBUG_PRINT((">> irq status 0x%x\n", val));
+                       break;
+
+               case AR5K_RAC_SISR0:
+               case AR5K_RAC_SISR1:
+               case AR5K_RAC_SISR2:
+               case AR5K_RAC_SISR3:
+               case AR5K_RAC_SISR4:
+                       val = 0;
+                       SET_MEM_L(s->mem, addr, 0);
+                       DEBUG_PRINT(("secondary irq status\n"));
+                       break;
+
+                       
+               /*
+                * According to the openHAL source
+                * documentation this is also read-and-clear
+                * but if it is made so, the WinDriver does
+                * not work any more...
+                */
+               case AR5K_RXDP:
+                       //SET_MEM_L(s->mem, addr, 0);
+                       break;
+
+               default:
+                       break;
+       }
+       return val;
+}
+
+static void mm_writel(Atheros_WLANState *s, target_phys_addr_t addr, uint32_t 
val)
+{
+       uint32_t h;
+       switch (addr)
+       {
+
+/******************************************************************
+ *
+ * ath5k_hw_init ---> ath5k_hw_nic_wakeup
+ *
+ ******************************************************************/
+
+               case AR5K_RESET_CTL:
+
+                       if (val == (AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI))
+                       {
+                               /* ath5k_hw.c: 613 */
+                               DEBUG_PRINT(("reset device (MAC + PCI)\n"));
+                               
+                               /*
+                                * claim device is inited
+                                */
+                               SET_MEM_L(s->mem, AR5K_STA_ID1, 0);
+                               SET_MEM_L(s->mem, AR5K_RESET_CTL, 3);
+                       }
+                       else if (val & (AR5K_RESET_CTL_CHIP | 
AR5K_RESET_CTL_PCI))
+                       {
+                               /* ath5k_hw.c: 613 */
+                               DEBUG_PRINT(("reset device (MAC + PCI + ?)\n"));
+                               
+                               /*
+                                * claim device is inited
+                                */
+                               SET_MEM_L(s->mem, AR5K_STA_ID1, 0);
+                               SET_MEM_L(s->mem, AR5K_RESET_CTL, 3);
+                       }
+                       else
+                       {
+                               /* ath5k_hw.c: 626 */
+                               DEBUG_PRINT(("reset device (generic)\n"));
+                               
+                               /*
+                                * warm-start device
+                                */
+                               SET_MEM_L(s->mem, AR5K_RESET_CTL, 0);
+                       }
+                       break;
+
+
+/******************************************************************
+ *
+ * interrupt handling
+ *
+ ******************************************************************/
+
+               case AR5K_IER:
+                       if (val == AR5K_IER_DISABLE)
+                       {
+                               /* ath5k_hw.c: 1636 */
+                               DEBUG_PRINT(("disabling interrupts\n"));
+                               SET_MEM_L(s->mem, AR5K_GPIODO, 0x0);
+                               SET_MEM_L(s->mem, AR5K_GPIODI, 0x0);
+
+                               s->interrupt_enabled = 0;
+                       }
+                       else if (val == AR5K_IER_ENABLE)
+                       {
+                               /* ath5k_hw.c: 1674 */
+                               DEBUG_PRINT(("enabling interrupts\n"));
+                               SET_MEM_L(s->mem, AR5K_GPIODO, 0x2);
+                               SET_MEM_L(s->mem, AR5K_GPIODI, 0x3);    // new
+
+                               s->interrupt_enabled = 1;
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("setting interrupt-enable to 
undefined value!!\n"));
+                       }
+                       break;
+
+               case AR5K_GPIODO:
+                       if (val == 0x2)
+                       {
+                               SET_MEM_L(s->mem, AR5K_GPIODI, 0x3);
+                       }
+                       break;
+
+               case AR5K_GPIODI:       // new
+                       if (val == 0x2)
+                       {
+                               SET_MEM_L(s->mem, AR5K_GPIODO, 0x3);
+                       }
+                       break;
+
+               case AR5K_PIMR:
+                       /* ath5k_hw.c: 1668 */
+                       DEBUG_PRINT(("setting primary interrupt-mask to 0x%x 
(%u)\n", val, val));
+                       s->interrupt_p_mask = val;
+
+                       SET_MEM_L(s->mem, addr, val);
+                       break;
+
+               case AR5K_SIMR0:
+                       DEBUG_PRINT(("setting secondary interrupt-mask 0 to 
0x%x (%u)\n", val, val));
+                       s->interrupt_s_mask[0] = val;
+                       break;
+               case AR5K_SIMR1:
+                       DEBUG_PRINT(("setting secondary interrupt-mask 1 to 
0x%x (%u)\n", val, val));
+                       s->interrupt_s_mask[1] = val;
+                       break;
+               case AR5K_SIMR2:
+                       DEBUG_PRINT(("setting secondary interrupt-mask 2 to 
0x%x (%u)\n", val, val));
+                       s->interrupt_s_mask[2] = val;
+                       break;
+               case AR5K_SIMR3:
+                       DEBUG_PRINT(("setting secondary interrupt-mask 3 to 
0x%x (%u)\n", val, val));
+                       s->interrupt_s_mask[3] = val;
+                       break;
+               case AR5K_SIMR4:
+                       DEBUG_PRINT(("setting secondary interrupt-mask 4 to 
0x%x (%u)\n", val, val));
+                       s->interrupt_s_mask[4] = val;
+                       break;
+
+/******************************************************************
+ *
+ * ath5k queuing (for transmit and receive buffers)
+ *
+ ******************************************************************/
+
+               case AR5K_QCU_TXE:
+                       /* ath5k_hw.c: 1423ff */
+                       
+                       /* enable specified queue (nr in val) */
+                       val = FASTBINLOG(val);
+
+                       DEBUG_PRINT(("queue %u enabled\n", val));
+                       if ((val >= 0) && (val < 16))
+                       {
+                               s->transmit_queue_enabled[val] = 1;
+                               Atheros_WLAN_handleTxBuffer(s, val);
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("unknown queue 0x%x (%u)\n", val, 
val));
+                       }
+                       break;
+               
+               case AR5K_QCU_TXD:
+                       /* ath5k_hw.c: 1423ff */
+
+                       /* disable specified queue (nr in val) */
+                       val = FASTBINLOG(val);
+
+                       DEBUG_PRINT(("queue %u disabled\n", val));
+                       if ((val >= 0) && (val < 16))
+                       {
+                               s->transmit_queue_enabled[val] = 0;
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("unknown queue 0x%x (%u)\n", val, 
val));
+                       }
+                       break;
+
+               case AR5K_IFS0:
+               case AR5K_IFS1:
+                       DEBUG_PRINT(("TODO: find out what inter frame spacing 
registers are used for...\n"));
+                       break;
+
+               case AR5K_CFG:
+                       
+                       if (val == AR5K_INIT_CFG)
+                       {
+                               /* ath5k_hw.c: 1261 */
+                               DEBUG_PRINT(("Reset configuration register (for 
hw bitswap)\n"));
+                       }
+                       SET_MEM_L(s->mem, AR5K_SLEEP_CTL, 0x0);
+                       break;
+
+               case AR5K_TXCFG:
+                       /* ath5k_hw.c: 1122 */
+                       DEBUG_PRINT(("Setting transmit queue size to %u 
byte\n", (1 << (val+2)) ));
+                       
+                       s->transmit_queue_size = (1 << (val+2));
+                       break;
+
+               case AR5K_CR:
+                       if (val == AR5K_CR_TXE0)        // TX Enable for queue 
0 on 5210
+                       {
+                               DEBUG_PRINT(("TX enable for queue 0\n"));
+                       }
+                       else if (val == AR5K_CR_TXE1)   // TX Enable for queue 
1 on 5210
+                       {
+                               DEBUG_PRINT(("TX enable for queue 1\n"));
+                       }
+                       else if (val == AR5K_CR_RXE)    // RX Enable
+                       {
+                               DEBUG_PRINT(("RX enable\n"));
+                               SET_MEM_L(s->mem, AR5K_DIAG_SW_5211, 0x0);
+                       }
+                       else if (val == AR5K_CR_TXD0)   // TX Disable for queue 
0 on 5210
+                       {
+                               DEBUG_PRINT(("TX disable for queue 0\n"));
+                       }
+                       else if (val == AR5K_CR_TXD1)   // TX Disable for queue 
1 on 5210
+                       {
+                               DEBUG_PRINT(("TX disable for queue 1\n"));
+                       }
+                       else if (val == AR5K_CR_RXD)    // RX Disable
+                       {
+                               DEBUG_PRINT(("RX disable\n"));
+                       }
+                       else if (val == AR5K_CR_SWI)    // unknown...
+                       {
+                               
+                               DEBUG_PRINT(("Undefined TX/RX en/disable 
CR_SWI\n"));
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("Undefined TX/RX en/disable\n"));
+                       }
+                       break;
+
+               case AR5K_RXDP:
+                       /*
+                        * unkown location, but this should
+                        * set the location of the receive
+                        * buffer's PHYSICAL address!!
+                        */
+                       DEBUG_PRINT(("Setting receive queue to address 0x%x 
(%u)\n", val, val));
+
+                       /*
+                        * This address will be queried again
+                        * later... store it!!
+                        */
+                       if (val == 0)
+                       {
+                               // hm... ar5424 resets its queue to 0 :-(
+                       }
+                       SET_MEM_L(s->mem, addr, val);
+                       s->receive_queue_address = (uint32_t *)val;
+
+                       /*
+                        * Madwifi hack: we allow only a certain
+                        * number of packets in the receive queue!!
+                        */
+                       s->receive_queue_count = 0;
+                       break;
+
+               case AR5K_QUEUE_TXDP(0):
+               case AR5K_QUEUE_TXDP(1):
+               case AR5K_QUEUE_TXDP(2):
+               case AR5K_QUEUE_TXDP(3):
+               case AR5K_QUEUE_TXDP(4):
+               case AR5K_QUEUE_TXDP(5):
+               case AR5K_QUEUE_TXDP(6):
+               case AR5K_QUEUE_TXDP(7):
+               case AR5K_QUEUE_TXDP(8):
+               case AR5K_QUEUE_TXDP(9):
+               case AR5K_QUEUE_TXDP(10):
+               case AR5K_QUEUE_TXDP(11):
+               case AR5K_QUEUE_TXDP(12):
+               case AR5K_QUEUE_TXDP(13):
+               case AR5K_QUEUE_TXDP(14):
+               case AR5K_QUEUE_TXDP(15):
+                       /*
+                        * unkown location, but this should
+                        * set the location of queue-dependent
+                        * transmit buffer's PHYSICAL address!!
+                        */
+                       DEBUG_PRINT(("Setting a transmit queue to address 0x%x 
(%u)\n", val, val));
+                       
+                       /*
+                        * This address will be queried again
+                        * later... store it!!
+                        */
+                       SET_MEM_L(s->mem, addr, val);
+                       
+                       addr -= AR5K_QCU_TXDP_BASE;
+                       addr /= 4;
+                       if (addr >= 0 && addr < 16)
+                       {
+                               /*
+                                * In case the given address specifies a
+                                * valid DMA address, let's use it and copy
+                                * the data into our device and process it
+                                * once the queue is enabled
+                                */
+                               s->transmit_queue_processed[addr] = 0;
+                               s->transmit_queue_address[addr] = (uint32_t 
*)val;
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("unknown queue 0x%x (%u)\n", addr, 
addr));
+                       }
+                       break;
+
+               case AR5K_RXCFG:
+                       /* ath5k_hw.c: 1124 */
+                       DEBUG_PRINT(("Setting receive queue size to %u byte\n", 
(1 << (val+2)) ));
+                       SET_MEM_L(s->mem, addr, val);
+                       break;
+
+               case AR5K_QUEUE_QCUMASK(0):
+               case AR5K_QUEUE_QCUMASK(1):
+               case AR5K_QUEUE_QCUMASK(2):
+               case AR5K_QUEUE_QCUMASK(3):
+               case AR5K_QUEUE_QCUMASK(4):
+               case AR5K_QUEUE_QCUMASK(5):
+               case AR5K_QUEUE_QCUMASK(6):
+               case AR5K_QUEUE_QCUMASK(7):
+               case AR5K_QUEUE_QCUMASK(8):
+               case AR5K_QUEUE_QCUMASK(9):
+               case AR5K_QUEUE_QCUMASK(10):
+               case AR5K_QUEUE_QCUMASK(11):
+               case AR5K_QUEUE_QCUMASK(12):
+               case AR5K_QUEUE_QCUMASK(13):
+               case AR5K_QUEUE_QCUMASK(14):
+               case AR5K_QUEUE_QCUMASK(15):
+                       DEBUG_PRINT(("ath5k_hw_reset_tx_queue for queue x 
(%u)\n", val));
+                       break;
+                       
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(0):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(1):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(2):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(3):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(4):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(5):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(6):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(7):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(8):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(9):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(10):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(11):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(12):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(13):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(14):
+               case AR5K_QUEUE_DFS_RETRY_LIMIT(15):
+                       DEBUG_PRINT(("setting retry-limit for queue x to 0x%x 
(%u)\n", val, val));
+                       break;
+               
+               case AR5K_QUEUE_DFS_LOCAL_IFS(0):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(1):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(2):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(3):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(4):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(5):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(6):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(7):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(8):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(9):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(10):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(11):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(12):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(13):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(14):
+               case AR5K_QUEUE_DFS_LOCAL_IFS(15):
+                       DEBUG_PRINT(("setting interframe space for queue x to 
0x%x (%u)\n", val, val));
+                       break;
+                       
+               case AR5K_QUEUE_MISC(0):
+               case AR5K_QUEUE_MISC(1):
+               case AR5K_QUEUE_MISC(2):
+               case AR5K_QUEUE_MISC(3):
+               case AR5K_QUEUE_MISC(4):
+               case AR5K_QUEUE_MISC(5):
+               case AR5K_QUEUE_MISC(6):
+               case AR5K_QUEUE_MISC(7):
+               case AR5K_QUEUE_MISC(8):
+               case AR5K_QUEUE_MISC(9):
+               case AR5K_QUEUE_MISC(10):
+               case AR5K_QUEUE_MISC(11):
+               case AR5K_QUEUE_MISC(12):
+               case AR5K_QUEUE_MISC(13):
+               case AR5K_QUEUE_MISC(14):
+               case AR5K_QUEUE_MISC(15):
+                       DEBUG_PRINT(("setting options for queue x to 0x%x 
(%u)\n", val, val));
+                       break;
+
+               case AR5K_SLEEP_CTL:
+                       SET_MEM_L(s->mem, AR5K_SLEEP_CTL, val);
+                       if (val == AR5K_SLEEP_CTL_SLE_WAKE)
+                       {
+                               DEBUG_PRINT(("waking up device\n"));
+                               
+                               /*
+                                * yes, we are awake
+                                *
+                                * basically it just checks if power-down
+                                * is false (val & AR5K_PCICFG_SPWR_DN == 0)
+                                * but my AR5212 says 20 what has the same
+                                * result but might be better ;-)
+                                */
+                               SET_MEM_L(s->mem, AR5K_PCICFG, 0x14);
+                               SET_MEM_L(s->mem, AR5K_STA_ID1, 0x00049e2e);
+//                             SET_MEM_L(s->mem, AR5K_STA_ID1, 0x0);
+
+//                             SET_MEM_L(s->mem, AR5K_PCICFG, 0x34);
+//                             SET_MEM_L(s->mem, AR5K_STA_ID1, 
AR5K_STA_ID1_PWR_SV);
+                       }
+                       else if (val == AR5K_SLEEP_CTL_SLE_SLP)
+                       {
+                               DEBUG_PRINT(("putting device to sleep\n"));
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("unknown SLEEP command %u\n", 
val));
+                       }
+                       break;
+                               
+               case AR5K_PHY_PLL:
+                       /*
+                        * ...set the PHY operating mode after reset
+                        */
+                        
+                       /* ath5k_hw.c: 632 */
+                       DEBUG_PRINT(("setting PHY operating mode (PLL)\n"));
+                       break;
+                       
+               case AR5K_PHY_MODE:
+                       /*
+                        * ...set the PHY operating mode after reset
+                        */
+
+                       /* ath5k_hw.c: 635 */
+                       DEBUG_PRINT(("setting PHY operating mode (mode)\n"));
+                       break;          
+
+               case AR5K_PHY_TURBO:
+                       /*
+                        * ...set the PHY operating mode after reset
+                        */
+
+                       /* ath5k_hw.c: 636 */
+                       DEBUG_PRINT(("setting PHY operating mode (turbo)\n"));
+                       break;
+               
+
+/******************************************************************
+ *
+ * ath5k_hw_init ---> ath5k_hw_radio_revision
+ *
+ ******************************************************************/
+
+
+               case AR5K_PHY(0):
+                       /*
+                        * Unknown
+                        */
+                       if (val == AR5K_PHY_SHIFT_2GHZ)
+                       {
+                               DEBUG_PRINT(("requesting 2GHZ radio\n"));
+                               SET_MEM_L(s->mem, AR5K_PHY(0x100), 0x4c047000);
+                       }
+                       /* ath5k_hw.c: 662 */
+                       else if (val == AR5K_PHY_SHIFT_5GHZ)
+                       {
+                               DEBUG_PRINT(("requesting 5GHZ radio\n"));
+                               SET_MEM_L(s->mem, AR5K_PHY(0x100), 0x8e000000);
+                       }
+
+                       SET_MEM_L(s->mem, AR5K_SLEEP_CTL, 0x0);
+                       break;
+
+               case AR5K_PHY(0x20):
+                       /*
+                        * request radio revision
+                        */
+
+                       /* ath5k_hw.c: 659 */
+                       if (val == AR5K_PHY_SHIFT_2GHZ)
+                       {
+                               DEBUG_PRINT(("requesting 2GHZ radio\n"));
+                               SET_MEM_L(s->mem, AR5K_PHY(0x100), 0x4c047000); 
// 1275359232);
+                       }
+                       /* ath5k_hw.c: 662 */
+                       else if (val == AR5K_PHY_SHIFT_5GHZ)
+                       {
+                               DEBUG_PRINT(("requesting 5GHZ radio\n"));
+                               SET_MEM_L(s->mem, AR5K_PHY(0x100), 0x7fffffff); 
// 2382364672);
+                       }
+                       /* ath5k_hw.c: 671 */
+                       else if (val == 0x00001c16)
+                       {
+                               DEBUG_PRINT(("requesting radio\n"));
+                       }
+                       /* ath5k_hw.c: 674 */
+                       else if (val == 0x00010000)
+                       {
+                               DEBUG_PRINT(("requesting radio 8 times...\n"));
+                               // NOW we request the radio revision (it was 
set before...)
+
+                               // SET_MEM_L(s->mem, 0x9c00, 0x8e026023);
+                               SET_MEM_L(s->mem, 0x9c00, 0x8e000000);
+                               
+                               SET_MEM_L(s->mem, 0x9c00, 0x4c047000);
+                       }
+                       
+                       break;
+                       
+               /*
+                * Setting frequency is different for AR5210/AR5211/AR5212
+                *
+                * see ath5k_hw.c: 4590 ff
+                *
+                * they all set AR5K_PHY(0x27),
+                * AR5210 sets AR5K_PHY(0x30),
+                * AR5211 sets AR5K_PHY(0x34) and
+                * AR5212 sets AR5K_PHY(0x36)
+                *
+                *
+                * The virtual device seems to read out 0x34 for
+                * the current channel (e.g. after a packet has
+                * been received)!!
+                */
+               case AR5K_PHY(0x27):
+//                     fprintf(stderr, "0x%04x => 0x%08x (27)\n", addr, val);
+                       SET_MEM_L(s->mem, addr, val);
+                       s->current_frequency_partial_data[0] = val;
+                       updateFrequency(s);
+                       break;
+               
+               case AR5K_PHY(0x34):
+//                     fprintf(stderr, "0x%04x => 0x%08x (34)\n", addr, val);
+                       SET_MEM_L(s->mem, addr, val);
+                       s->current_frequency_partial_data[1] = val;
+                       updateFrequency(s);
+                       break;
+
+               /*
+                * these are used by AR521 and AR5212 respectively,
+                * but we seem to simulate an AR5211 and the calls
+                * destroy our channel frequency mapping :-(
+                *
+               case AR5K_PHY(0x30):
+                       fprintf(stderr, "0x%04x => 0x%08x (30)\n", addr, val);
+                       SET_MEM_L(s->mem, addr, val);
+                       s->current_frequency_partial_data[1] = val;
+                       updateFrequency(s);
+                       break;
+               case AR5K_PHY(0x36):
+                       fprintf(stderr, "0x%04x => 0x%08x (36)\n", addr, val);
+                       SET_MEM_L(s->mem, addr, val);
+                       s->current_frequency_partial_data[1] = val;
+                       updateFrequency(s);
+                       break;
+                */
+
+
+
+/*
+               case AR5K_PHY(0x21):
+               case AR5K_PHY(0x22):
+               case AR5K_PHY(0x23):
+               case AR5K_PHY(0x24):
+               case AR5K_PHY(0x25):
+               case AR5K_PHY(0x26):
+               case AR5K_PHY(0x28):
+               case AR5K_PHY(0x29):
+               case AR5K_PHY(0x31):
+               case AR5K_PHY(0x32):
+               case AR5K_PHY(0x33):
+               case AR5K_PHY(0x35):
+               case AR5K_PHY(0x37):
+               case AR5K_PHY(0x38):
+               case AR5K_PHY(0x39):
+               case AR5K_PHY(0x40):
+               case AR5K_PHY(0x41):
+               case AR5K_PHY(0x42):
+               case AR5K_PHY(0x43):
+               case AR5K_PHY(0x44):
+               case AR5K_PHY(0x45):
+               case AR5K_PHY(0x46):
+               case AR5K_PHY(0x47):
+               case AR5K_PHY(0x48):
+               case AR5K_PHY(0x49):
+               case AR5K_PHY(0x50):
+                       fprintf(stderr, "0x%04x => 0x%08x\n", addr, val);
+                       break;*/
+
+/******************************************************************
+ *
+ * ath5k_hw_init ---> ath5k_hw_set_associd  (aka. set BSSID)
+ *
+ ******************************************************************/
+
+               case AR5K_BSS_IDM0:
+               case AR5K_BSS_IDM1:
+                       /*
+                        * Set simple BSSID mask on 5212
+                        */
+                        
+                       /* ath5k_hw.c: 2420 */
+                       DEBUG_PRINT(("setting bssid mask\n"));
+                       break;
+                       
+               case AR5K_BSS_ID0:
+               case AR5K_BSS_ID1:
+                       /*
+                        * Set BSSID which triggers the "SME Join" operation
+                        */
+                       
+                       /* ath5k_hw.c: 2432 & 2433 */
+                       DEBUG_PRINT(("setting bssid : %c%c%c%c \n", (val << 24) 
>> 24, (val << 16) >> 24, (val << 8) >> 24, val >> 24));
+                       break;
+
+               case AR5K_STA_ID0:
+                       /*
+                        * a set to client(adhoc|managed) | ap | monitor mode 
is coming
+                        *
+                        * if there are more than one chip present, this
+                        * call defines which chip is to be used!
+                        */
+                       
+                       /* ath5k_hw.c: 2358 */
+                       DEBUG_PRINT(("a set to client | ap | monitor mode is 
coming for station %u\n", val));
+                       
+                       // ext
+                       SET_MEM_L(s->mem, addr, val);
+                       
+                       break;
+               
+               case AR5K_STA_ID1:
+                       /*
+                        * seems to have a double-meaning:
+                        *
+                        * setting client mode AND power mode
+                        */
+                        
+                       /* ath5k_hw.c: 619 */                   
+                       DEBUG_PRINT(("setting power mode\n"));
+                       SET_MEM_L(s->mem, AR5K_STA_ID1, val);
+                       SET_MEM_L(s->mem, AR5K_STA_ID0, 0x800a1100);
+                       //SET_MEM_L(s->mem, 0xc, 0x1a7d823c);
+                       SET_MEM_L(s->mem, 0xc, 0x0);
+                       SET_MEM_L(s->mem, 0x00c0, 0x01040000);
+
+
+                       /* ath5k_hw.c: 2361 */
+                       if (val & AR5K_STA_ID1_ADHOC & 
AR5K_STA_ID1_DESC_ANTENNA)
+                       {
+                               DEBUG_PRINT(("setting device into ADHOC 
mode\n"));
+                       }
+                       else if (val & AR5K_STA_ID1_AP & 
AR5K_STA_ID1_RTS_DEF_ANTENNA)
+                       {
+                               DEBUG_PRINT(("setting device into managed 
mode\n"));
+                       }
+                       else if (val & AR5K_STA_ID1_DEFAULT_ANTENNA)
+                       {
+                               DEBUG_PRINT(("setting device into some other 
mode (probably monitor)\n"));
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("setting device into unknown 
mode\n"));
+                       }
+                       break;
+
+
+
+/******************************************************************
+ *
+ * ath5k_hw_init ---> ath5k_eeprom_init
+ *
+ ******************************************************************/
+
+               case AR5K_EEPROM_BASE:
+                       /*
+                        * an access to an offset inside the
+                        * EEPROM uses an initialization of
+                        * the address at this location
+                        */
+                        
+                       /* ath5k_hw.c: 1738 */
+                       DEBUG_PRINT(("there will be an access to the EEPROM at 
%p\n", (unsigned long*)val));
+                       
+                       /*
+                        * set the data that will be returned
+                        * after calling AR5K_EEPROM_CMD=READ
+                        */
+                       switch (val)
+                       {
+#if 0
+                               case AR5K_EEPROM_MAGIC:
+                                       WRITE_EEPROM(s->mem, 
AR5K_EEPROM_MAGIC_VALUE);
+                                       break;
+
+                               case AR5K_EEPROM_PROTECT:
+                                       WRITE_EEPROM(s->mem, 0);
+                                       break;
+
+                               case AR5K_EEPROM_REG_DOMAIN:
+                                       /*
+                                        * reg-domain central europe ???
+                                        */
+                                       WRITE_EEPROM(s->mem, 96);
+                                       break;
+
+                               case AR5K_EEPROM_VERSION:
+                                       WRITE_EEPROM(s->mem, 
AR5K_EEPROM_VERSION_3_4);
+                                       break;
+
+                               case AR5K_EEPROM_HDR:
+                                       WRITE_EEPROM(s->mem, 23046);
+                                       break;
+
+                               case 195:
+                                       /*
+                                        * an radio-GHZ specific eeprom data 
(AR5K_EEPROM_ANT_GAIN)
+                                        *
+                                        * on my AR5212 it is 0
+                                        */
+                                        
+                                       /* ath5k_hw.c: 2023 */
+                                       WRITE_EEPROM(s->mem, 0);
+                                       break;
+
+                               case 0x20:
+                                       /*
+                                        * before we read the MAC addr, we read 
this (???)
+                                        *
+                                        * ATTENTION: this value is present in 
the EEPROM!!
+                                        */
+
+                                       /* ath5k_hw.c : 2185 */
+                                       break;
+
+                               case 0x1f:
+                                       /*
+                                        * 1st part of MAC-addr
+                                        */
+                                       DEBUG_PRINT(("EEPROM request first part 
of MAC\n"));
+                                       WRITE_EEPROM(s->mem, (s->phys[0] << 8) 
| s->phys[1]);
+                                       break;
+
+                               case 0x1e:
+                                       /*
+                                        * 2nd part of MAC-addr
+                                        */
+                                       DEBUG_PRINT(("EEPROM request second 
part of MAC\n"));
+                                       WRITE_EEPROM(s->mem, (s->phys[2] << 8) 
| s->phys[3]);
+                                       break;
+
+                               case 0x1d:
+                                       /*
+                                        * 3rd part of MAC-addr
+                                        */
+                                       DEBUG_PRINT(("EEPROM request third part 
of MAC\n"));
+                                       WRITE_EEPROM(s->mem, (s->phys[4] << 8) 
| s->phys[5]);
+                                       break;
+#endif
+                               /*
+                                * ATTENTION: if we modify anything in the
+                                * eeprom, we might get (at least in linux we
+                                * do) an EEPROM-checksum error!!
+                                */
+
+                               case 0x0:
+                                       /*
+                                        * this is not part of the EEPROM dumps 
for some reason!!
+                                        */
+                                       DEBUG_PRINT(("EEPROM request 0x0\n"));
+                                       WRITE_EEPROM(s->mem, 0x13);
+                                       break;
+
+                               default:
+                                       if (!get_eeprom_data(s, val, &h))
+                                       {
+                                               /*
+                                                * we have a hit in the 
internal eeprom-buffer
+                                                */
+                                               DEBUG_PRINT(("EEPROM hit %u at 
%u\n", h, val));
+                                               WRITE_EEPROM(s->mem, h);
+                                       }
+                                       else
+                                       {
+                                               DEBUG_PRINT(("EEPROM request at 
%p is unknown\n", (unsigned long*)val));
+                                               WRITE_EEPROM(s->mem, 0);
+                                       }
+                                       break;
+                       }
+                       break;
+
+               case AR5K_EEPROM_CMD:
+                       /*
+                        * what type of access is specified as well
+                        */
+
+                       /* ath5k_hw.c: 1739 */
+                       if (val & AR5K_EEPROM_CMD_READ)
+                       {
+                               DEBUG_PRINT(("the EEPROM access will be 
READ\n"));
+                               
+                               /*
+                                * tell the device the read was successful
+                                */
+                               SET_MEM_L(s->mem, AR5K_EEPROM_STAT_5210, 
AR5K_EEPROM_STAT_RDDONE);
+                               SET_MEM_L(s->mem, AR5K_EEPROM_STAT_5211, 
AR5K_EEPROM_STAT_RDDONE);
+                               /*
+                                * and return the data that was set
+                                * during the write to AR5K_EEPROM_BASE
+                                */
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("the EEPROM access will be 
UNKNOWN\n"));
+                               fprintf(stderr, "Is this a write to the 
eeprom??\n");
+                       }
+                       break;
+
+
+/******************************************************************
+ *
+ * additional reverse engineering:
+ *
+ ******************************************************************/
+
+               case AR5K_USEC_5210:    // new
+                       SET_MEM_L(s->mem, AR5K_XRMODE, 0x2a80001a);
+                       SET_MEM_L(s->mem, AR5K_XRTIMEOUT, 0x13881c20);
+                       break;
+
+               case AR5K_PHY_AGCCTL:   // new
+                       if (val & AR5K_PHY_AGCCTL_CAL)
+                       {
+                               SET_MEM_L(s->mem, AR5K_PHY_AGCCTL, val & 
(~AR5K_PHY_AGCCTL_CAL));
+                       }
+                       else if (val & AR5K_PHY_AGCCTL_NF)
+                       {
+                               SET_MEM_L(s->mem, AR5K_PHY_AGCCTL, val & 
(~AR5K_PHY_AGCCTL_NF));
+                       }
+                       break;
+
+               default:
+                       if (addr / 4 < Atheros_WLAN_MEM_SIZE)
+                       {
+                               SET_MEM_L(s->mem, addr, val);
+                       }
+                       
+                       if ((addr >= AR5K_PCU_MIN) &&
+                               (addr <= AR5K_PCU_MAX))
+                       {
+                               DEBUG_PRINT(("Setting up 
ini-registers...!!\n"));
+                       }
+                       else
+                       {
+                               DEBUG_PRINT(("Unknown call to memory!!\n"));
+                       }
+                       break;
+       }
+}
+
diff -Naur qemu/hw/atheros_wlan_io.h qemu-altered/hw/atheros_wlan_io.h
--- qemu/hw/atheros_wlan_io.h   1970-01-01 01:00:00.000000000 +0100
+++ qemu-altered/hw/atheros_wlan_io.h   2008-03-01 12:33:11.000000000 +0100
@@ -0,0 +1,35 @@
+/**
+ * QEMU WLAN device emulation
+ * 
+ * Copyright (c) 2008 Clemens Kolbitsch
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Modifications:
+ *  2008-February-24  Clemens Kolbitsch :
+ *                                  New implementation based on ne2000.c
+ *
+ */
+
+#ifndef atheros_wlan_io_h
+#define atheros_wlan_io_h 1
+
+void Atheros_WLAN_setup_io(PCIAtheros_WLANState *d);
+
+#endif // atheros_wlan_io_h





reply via email to

[Prev in Thread] Current Thread [Next in Thread]