Nintendo DS Wifi Hardware Reference

version 0.03
Originally documented by Stephen Stair (sgstair AT akkit.org)
Additional information and corrections provided by Martin Korth and anonymous contributors
Please contact me if you find errors or omissions, thanks :)

Non-Wifi Hardware

General Information
Related Registers - System control

Wifi Hardware

General Information
Wifi Hardware Overview/Capability
Wifi I/O Map
Hardware Init Sequence
BaseBand chip registers
RF chip data formats
Register Documentation
Wifi Rx Registers
Wifi Tx Registers
Wifi RF/BB Chip Control Registers
Wifi Other Registers
Wifi Unknown Registers
Additional Information
Wifi Transmit Procedure
Wifi Receive Procedure
Wifi Change Channels Procedure
About the "undefined" data in this document

Formats/etc

General Formats
802.11
Wifi Formats
Hardware TX header
Hardware RX header

Related Registers - System control

(System Control registers are accessed with a base of 0x04000000)

ARM7 System Control registers



0x01C0 - SPI_CR - Serial Interface Control (R/W)
 Bit  Description
 15   Enable (1=enabled, 0=not) When the SPI is enabled, any writes to the data register initiate a serial transfer.
  7   Busy - This bit is 1 when a transfer is currently in progress
The SPI_CR register lets you configure how SPI transfers will take place.

0x01C2 - SPI_DATA - Serial Interface Data (R/W)
Writing to this register initiates a serial transfer of the type specified in SPI_CR. The busy bit is set in SPI_CR, and when the transfer is done, the busy bit is cleared and the incoming serial data is put into SPI_DATA.

0x0204 - WAIT_CR - ARM7 Wait Control (R/W)
 Bit  Description
 0   ?
 1   ?
 2   ?
Set a bit to '1' to enable power to that system, '0' to disable.

0x0208 - IME (32bit) - ARM7 Interrupt master enable (R/W)
Set to '1' to enable ARM7 interrupts, '0' to disable them.

0x0210 - IE (32bit) - ARM7 Interrupt Enable (R/W)
 Bit  Description
  0   V-Blank
  1   H-Blank
  2   V-Match
  3   Timer0
  4   Timer1
  5   Timer2
  6   Timer3
  7   ?
  8   Dma0
  9   Dma1
  10  Dma2
  11  Dma3
  12  Keypad
  13  GBA Cart
14-18 ?
  19  DS Card control
  20  DS Card IRQ signal
21-23 ?
  24  Wifi
25-31 ?
All the bits are '1' to enable and '0' to disable the interrupt.

0x0214 - IF (32bit) - ARM7 Interrupt flags register (R/W)
(same bits as IE)
Write '1' to a bit in order to clear the interrupt bit flag

0x0304 - POWERCNT - ARM7 Power Control (R/W)
 Bit  Description
  0   Sound Power
  1   Wifi Power
2-15  Unused
Set a bit to '1' to enable power to that system, '0' to disable.

ARM9 System Control registers



0x0208 - IME (32bit) - ARM9 Interrupt master enable (R/W)
Set to '1' to enable ARM9 interrupts, '0' to disable them.

0x0210 - IE (32bit) - ARM9 Interrupt Enable (R/W)
 Bit  Description
 0   V-Blank
 1   H-Blank
 2   V-Match
 3   Timer0
 4   Timer1
 5   Timer2
 6   Timer3
 7   Unused/Reserved
 8   Dma0
 9   Dma1
 10  Dma2
 11  Dma3
 12  Keypad
 13  GBA Cart
 14  Unused/Reserved
 15  Unused/Reserved
 16-18 ?
 19  DS Card control
 20  DS Card IRQ signal
 21  ?
 22-31 ?
All the bits are '1' to enable and '0' to disable the interrupt.

0x0214 - IF (32bit) - ARM9 Interrupt flags register (R/W)
(same bits as IE)
Write '1' to a bit in order to clear the interrupt bit flag

0x0304 - POWERCNT - ARM9 Power Control (R/W)
 Bit  Description
 0   Screen Power
 1   2D Core A Power
 2   Rasterizer Engine Power
 3   Geometry Engine Power
 4-8 ?
 9   2D Core B Power
 10-14 ?
 15  LCD Swap (1=Core A on top, 0=Core B on top)
Set a bit to '1' to enable power to that system, '0' to disable.

Wifi Hardware Overview/Capability

The Wifi hardware interface is likely on-die with much of the other hardware. It is very likely a 16-bit only interface.
The hardware is entirely custom probably for a few reasons, one of which is the official nintendo "wired" wireless system.
There is an RF daughterboard on the DS, with a BaseBand chip and an RF generation chip - these two are referred to extensively as BB and RF chips in this document. They are communicated with by a few sets of registers in the hardware, and the hardware also talks to them via other methods.
The hardware is initialized almost entirely from data stored in the firmware flash of the NDS, which allows two things: for one, they could possibly change the RF chipset in the future and still maintain compatibility. Additionally, and more apparent, is that Nintendo's "wired" system that emulates wireless is indeed quite different from regular DS wifi. Having the options in flash can allow software to easily work with either system.
Many people have tried to identify the RF and BB chips on the daughterboard on the NDS, but nothing has turned up, it's very likely they are either next-gen parts or merely different revisions of current parts (either custom for Nintendo, or possibly Nintendo has "laid claim" to a new revision and the documentation has not been released to the public yet.)
The hardware at present does not seem capable of transmitting at higher than 2.0Mbit, when I tried 5.5Mbit it appeared to have jammed the frequency. I have not tested receiving yet, if we can receive at speeds higher than 2.0, this would be very useful.
Overall, the hardware seems very capable, and easy to use for the most part (besides init).


Quick rundown of the wifi memory map:
Address  | Section 
---------|--------------------        
04800000 | Main wifi register section
to       | read/write normal       
04800FFF |____________________ 
04801000 | Wifi Register section mirror
to       | read to "action" registers does not produce action (like read fifo 0x04800060)
04801FFF |____________________ 
04802000 | Wifi Register section mirror
to       | read to "action" registers does not produce action (like read fifo 0x04800060)
04802FFF |____________________ 
04803000 | Wifi Register section mirror
to       | read to "action" registers does not produce action (like read fifo 0x04800060)
04803FFF |____________________ 
04804000 | MAC Memory section
to       | tx data, rx data, wep keys kept here
         | general sram, read/write 16bit
         |
         |
04805FFF |____________________ 
04806000 | Wifi Register section mirror
to       | read to "action" registers does not produce action (like read fifo 0x04800060)
04806FFF |____________________ 
04807000 | Wifi Register section mirror
to       | read to "action" registers does not produce action (like read fifo 0x04800060)
04807FFF |____________________ 
This memory map then repeats/wraps around in the 0x04800000-0x04ffffff memory space.

Wifi I/O Map

Wifi I/O - All registers in this section are offset from 0x04800000 (16bit unless otherwise noted) Please note that while the nintendo wifi code uses registers from offsets 0x8xxx instead of 0x0xxx, they are mirrored and either works.
Offset    R/W   Name            [Init Value] Description
0x0000    R     ?               [1440] ?
0x0004    R/W   W_MODE_RST      [0000] Mode/Reset
0x0006    R/W   W_MODE_WEP      [0000] Mode / Wep modes. masks: 0x0040, 0x0018 (wep mode), 0x0003 (wifi mode)
0x0008    ?/W   ?               [0000] always set to 0?
0x000A    ?/W   Name            [0000] [bit7 - ingore rx duplicates]
0x0010    R/W   W_IF            [0000] Wifi Interrupt Request Flags (works like IF)
0x0012    R/W   W_IE            [0000] Wifi Interrupt Enable
0x0018    R/W   W_MACADDR       [0000 0000 0000] Hardware MAC Address (6 bytes)
0x0020    R/W   W_BSSID         [0000 0000 0000] BSSID (6 bytes)
0x0028    ?/W   W_AID           [0000] the AID value assigned by a BSS.
0x002A    ?/W   ?               [0000] set to the same thing as W_AID always
0x002C    ?/W   W_RETRLIMIT     [0707] Retry Limit (set from 0x00-0xFF)
0x002E    ?/?   ?               [0000]
0x0030    ?/W   W_RXCNT         [0000] Receive control, top bit = enable, bottom bit = latch rx range registers
0x0032    ?/W   Name            [0000] WEP engine enable: 0x8000 = enable, 0x0000 = disable [enables/disables WEP processing of sent/received packets]
0x0034    ?/?   ?               [0000]
0x0036    ?/W   Name            [0001] 1==disable?
0x0038    ?/W   Name            [0003] transmit-related power save or something [ bit 0 is power save related ]
0x003C    ?/W   W_POWERSTATE    [0200] Power save - [=1: queue disable power state] [=2: queue enable power state] [bit9 = current power state, read only] - "enableing" causes rx wakeup interrupt
0x0040    ?/W   W_FORCEPS       [0000] Force Power State - [bit 15: allow forcing of power state, 1=force] [bit0: power state to force 0=disable, 1=enable]
0x0044    R     W_RANDOM        [????] random value. value constantly changes to random values between 1 and 0x07ff (more info further down)
0x0048    ?/W   Name            [0000] =0, =3 [=3 is power-save related.]
0x0050    R/W   W_RXRANGEBEGIN  [4000] The first location in mac memory used for the RX circular buffer (latched when bottom bit of W_RXCNT is set)
0x0052    R/W   W_RXRANGEEND    [4800] The address immediately after the last location in MAC memory used for the RX circular buffer (latched when bottom bit of W_RXCNT is set)
0x0054    R     W_RXHWWRITECSR  [0000] The hardware Write cursor, address=value*2+0x4000 - This points to the first "free" halfword in the buffer.
0x0056    R/W   W_WRITECSRLATCH [0000] When bottom bit of W_RXCNT is set, this value is loaded into W_RXHWWRWITECSR
0x0058    R/W   W_CIRCBUFRDADR  [0000] A read cursor in the circular buffer; not used for anything but manual reading of W_CIRCBUFREAD
0x005A    R/W   W_RXREADCSR     [0000] The "Begin" location of the circular buffer; the hardware write cursor will not go past this value when writing data. Must be moved by software after reading a packet
0x005C    R/W   Name            [0000] (mask 0x0fff) Counts down; triggers wifi interrupt 9 when it reaches 0
0x0060    R     W_CIRCBUFREAD   [xxxx] every time you read this address it returns the data in the mac buffer at the address in W_CIRCBUFRDADR and increments W_CIRCBUFRDADR by 2
0x0062    R/W   Name            [0000] mask 0x1ffe
0x0064    R/W   Name            [0000] mask 0x0fff
0x0068    R/W   W_CIRCBUFWRADR  [0000] A write cursor in the circular buffer; not used for anything but manual writing to W_CIRCBUFWRITE (haven't checked to see if this actually is a circular buffer thing, the read one is though)
0x006C    R/W   Name            [0000] mask 0x0fff
0x0070    R/W   W_CIRCBUFWRITE  [xxxx] When you read, this register mirrors W_CIRCBUFREAD without modifying W_CIRCBUFRDADR.. when you write, it writes the value to the address in MAC mem specified by W_CIRCBUFWRADR, and increments it by 2.
0x0074    R/W   W_CIRCBUFWR_END [0000] Same as W_RXRANGEEND for the W_RXREADCSR, this is for W_RXWRITEADR; but there's no begin register, see the next register for more info
0x0076    ?/W   W_CIRCBUFWR_SKIP[0000] When W_RXWRITECURSOR = W_CIRCBUFWR_END, this value * 2 is added to it. So when [WRITEADR]==[END], [WRITEADR]+=[SKIP]*2;
0x0078    ?/W   Name            [0000] Appears to mirror W_CIRCBUFWRADR
0x0080    R/W   W_BEACONTRANS   [0000] Enables automatic transmission of frames at regular intervals. top bit=enable, bottom 12 bits = MAC mem address/2 of frame header
0x0084    ?/W   Name            [0000] Description
0x0088    R/W   W_LISTENCOUNT   [0000] Decrements; when it reaches zero, it's reloaded with W_LISTENINT
0x008C    R/W   W_BEACONPERIOD  [0064] Frequency in milliseconds of beacon transmission
0x008E    R/W   W_LISTENINT     [0000] Listen interval; related to W_LISTENCOUNT
0x0090    ?/W   Name            [0000] Description
0x0094    ?/W   Name            [0000] ?
0x0098    ?/W   Name            [0000] Description
0x00A0    R/W   Name            [0050] ?
0x00A0    R/W   W_TXLOC1        [0000] Transmit slot #1 (bit 0)
0x00A4    R/W   W_TXLOC2        [0000] Transmit slot #2 (bit 2)
0x00A8    R/W   W_TXLOC3        [0000] Transmit slot #3 (bit 3)
0x00AC      W   W_TXOPT         [0050] Transmit options... Options that exist are unclear.
0x00AE      W   W_TXCNT         [0050] Write here to enable the transmission of one or more of the 3 transmit slots
0x00B0    R/?   W_TXINFO        [0010] Info about transmit state
0x00B4    ?/W   Name            [0000] Description
0x00B6    R/?   Name            [0000] Description
0x00B8    R/?   W_TXSTAT        [0000] Status of recently transmitted frame
0x00BA    R/?   Name            [0000] Description
0x00BC    ?/W   Name            [0001] [ |=6: short preamble, &=~6: long preamble ]
0x00C0    R/?   Name            [0000] Description
0x00C4    R/?   Name            [0000] Description
0x00C8    R/?   Name            [0000] Description
0x00D0    R/W   W_RXFILTER      [0401] Specifies what packets to allow, combinations are unknown.
0x00D4    ?/W   Name            [0001] Description
0x00D8    ?/W   Name            [0004] Description
0x00DA    ?/W   Name            [0602] Description
0x00E0    ?/W   Name            [0008] Description
0x00E8    R/W   W_USCOUNTERCNT  [0000] Microsecond counter control, 0x0001 = enabled
0x00EA    ?/W   W_USCOMPARECNT  [0000] Microsecond compare control, 0x0001 = enabled (to enable interrupt 14)
0x00EC    ?/W   Name            [3F03] Description
0x00EE    ?/W   Name            [0001] Description
0x00F0    ?/W   W_USCOMPARE0    [FC00] F0-F7 are compared with F8 through FF - note lower 10 bits are always 0, so compare has 1/1024 microsecond resolution.
0x00F2    ?/W   W_USCOMPARE1    [FFFF] When they match, 11C is reloaded with W_BEACONPERIOD, 134 is set to FFFF, and interrupt 14 triggers (may not be related)
0x00F4    ?/W   W_USCOMPARE2    [FFFF] 
0x00F6    ?/W   W_USCOMPARE3    [FFFF] 
0x00F8    R/W   W_USCOUNTER0    [0000] Microsecond counter, bottom 16 bits
0x00FA    R/W   W_USCOUNTER1    [0000] Microsecond counter, bits 16-31
0x00FC    R/W   W_USCOUNTER2    [0000] Microsecond counter, bits 32-47
0x00FE    R/W   W_USCOUNTER3    [0000] Microsecond counter, bits 48-63
0x0100    ?/W   Name            [0000] Description
0x0102    ?/W   Name            [0000] Description
0x0104    ?/W   Name            [0000] Description
0x0106    ?/W   Name            [0000] Description
0x010C    ?/W   Name            [0000] [Set to the remaining duration of contention-free period when receiving beacons - only *really* necessary for the wimpy powersaving mode]
0x0110    ?/W   Name            [0000] Description
0x0118    ?/W   Name            [0000] Description
0x011C    ?/W   Name            [0000] (Decreases, when reaches 0 is reloaded with W_BEACONPERIOD)
0x0120    R/W   ?               [0048] 
0x0122    R/W   ?               [4840] mask 0xffff 
0x0124    R/W   ?               [0000] mask 0xffff 
0x0126    R/W   ?               [0080]
0x0128    R/W   ?               [0000] mask 0xffff
0x012A    R/W   ?               [1000]
0x0130    R/W   ?               [0142] mask 0x0fff
0x0132    R/W   ?               [8064] mask 0x8fff
0x0134    R/W   W_BEACONCOUNT   [FFFF] (I think) This is the millisecond counter that tracks when beacons are expected to be transmitted. ["Active zone time" - it tracks some aspect of the Contention-free period]
0x0140    R/W   ?               [0000] mask 0xffff 
0x0142    R/W   ?               [2443] mask 0xffff 
0x0144    R/W   ?               [0042] 
0x0146    R/W   ?               [0016] 
0x0148    R/W   ?               [0016] 
0x014A    R/W   ?               [0016] 
0x014C    R/W   ?               [162C] 
0x0150    ?/W   Name            [0204] Description 
0x0154    ?/W   Name            [0058] Description 
0x0158    ?/W   W_BBSIOCNT      [00B5] 0x6xxx - read from address xxx, 0x5xxx - write to address xxx
0x015A    ?/W   W_BBSIOWRITE    [0000] byte data to write
0x015C    ?/W   W_BBSIOREAD     [00B5] byte data read
0x015E    ?/W   W_BBSIOBUSY     [0000] Bit 0 = set when busy
0x0160    ?/W   Name            [0100] Description
0x0168    ?/W   Name            [800D] Description
0x016A    ?/W   Name            [0001] Description
0x0170    ?/W   Name            [0000] Description
0x0172    ?/W   Name            [0000] Description
0x0174    ?/W   Name            [0000] Description
0x0176    ?/W   Name            [0000] Description
0x0178    ?/W   Name            [0800] Description
0x017C    ?/W   W_RFSIODATA2    [0800] Description
0x017E    ?/W   W_RFSIODATA1    [C008] Description
0x0180    ?/W   W_RFSIOBUSY     [0000] Description
0x0184    ?/W   W_RFSIOCNT      [0018] Description
0x0190    ?/W   Name            [0000] Description
0x0194    ?/W   Name            [0000] Description
0x0198    ?/W   Name            [0000] Description
0x019C    ?/W   Name            [0004] Bit 0 = carrier sense?
0x01A0    ?/W   Name            [0000] Description
0x01A2    ?/W   Name            [0001] Description
0x01A4    ?/W   Name            [0000] Rate used when signal test is enabled (0x0A or 0x14 for 1 or 2 mbit)
0x01A8    R     Name            [0000] REG_WL_STATSINC: Bitmask for which statistics have been increased atleast once.
0x01AA    R/W   Name            [0000] REG_WL_STATSIECNTUP: Statistic Interrupt Enable Control register for Count Up. bitmasks: 0x20 = FCS_ERROR, 0x40 = FCS_OK, 0x800 = DUPE, ?
0x01AC    R     Name            [0000] REG_WL_STATSOVF. Bitmask that tells which statistics have overflowed.
0x01AE    R/W   Name            [0000] REG_WL_STATSIEOVF. Statistic Interrupt Enable Control register for Overflow. bitmasks same as STATSIECNTUP.
0x01B0    R     W_STAT          [0000] W_STAT is a collection of byte-granular statistics entries. These entries reset to 0 when read.
0x01B2    R     W_STAT          [0000] [RX_LengthErrorCount | RX_RateErrorCount]
0x01B4    R     W_STAT          [0000] 
0x01B6    R     W_STAT          [0000] 
0x01B8    R     W_STAT          [0000] 
0x01BA    R     W_STAT          [0000] 
0x01BC    R     W_STAT          [0000] 
0x01BE    R     W_STAT          [0000] 
0x01C0    R     W_STAT          [0000] 
0x01C4    R     W_STAT          [0000] 
0x01D0    R     W_STAT          [0000] [1D0 - 1DE are 15 entries related to multiplayer response errors]
0x01D2    R     W_STAT          [0000] 
0x01D4    R     W_STAT          [0000] 
0x01D6    R     W_STAT          [0000] 
0x01D8    R     W_STAT          [0000] 
0x01DA    R     W_STAT          [0000] 
0x01DC    R     W_STAT          [0000] 
0x01DE    R     W_STAT          [0000] 
0x01F0    ?/W   Name            [0000] Description
0x0204    ?/W   Name            [0000] Description
0x0208    ?/W   Name            [0000] Description
0x020C    ?/W   Name            [0050] Description
0x0210    ?/W   Name            [0000] Description
0x0214    ?/W   Name            [0009] Description
0x021C    ?/W   Name            [0000] "Force Interrupt" - writing a value here will enable the flags in W_IF
0x0220    ?/W   Name            [0000] has something to do with whether the packet is ignored or allowed by the packet filtering system
0x0224    ?/W   Name            [0003] Description
0x0228    ?/W   Name            [0000] Description
0x0230    ?/W   Name            [0047] Description
0x0234    ?/W   Name            [0EFF] Description
0x0238    ?/W   Name            [0000] Description
0x023C    ?/W   Name            [0000] Description
0x0244    ?/W   Name            [0000] Description
0x0248    ?/W   Name            [0000] Description
0x024C    ?/W   Name            [0000] Description
0x024E    ?/W   Name            [0000] Description
0x0250    ?/W   Name            [0000] Description
0x0258    ?/W   Name            [0000] Description
0x025C    ?/W   Name            [0000] Description
0x0260    ?/W   Name            [0FEF] Description
0x0264    ?/W   Name            [0000] Description
0x0268    R/W   W_RXUNITS       [0005] Contains the number of HWORDs written to MAC mem since the start of the packet (this + W_RXHWWRITECSR = next empty word in MAC mem)
0x0270    ?/W   Name            [0000] Description
0x0274    ?/W   Name            [0000] Description
0x0278    ?/W   Name            [000F] Description
0x027C    ?/W   Name            [0000] Description
0x0290    ?/W   Name            [FFFF] bit 0 = ?
0x0298    ?/W   Name            [0000] Description
0x02A0    ?/W   Name            [0000] Description
0x02A2    ?/W   Name            [7FFF] Description
0x02A4    ?/W   Name            [0000] Description
0x02A8    ?/W   Name            [0000] Description
0x02AC    ?/W   Name            [0038] Description
0x02B0    ?/W   Name            [0000] Description
0x02B4    ?/W   Name            [0000] Description
0x02B8    ?/W   Name            [0000] Description
0x02C0    ?/W   Name            [0000] Description
0x02C4    ?/W   Name            [000A] Description
0x02C8    ?/W   Name            [0000] Description
0x02CC    ?/W   Name            [0000] Description
0x02F0    ?/W   Name            [0000] Description
0x02F2    ?/W   Name            [0000] Description
0x02F4    ?/W   Name            [0000] Description
0x02F6    ?/W   Name            [0000] Description
0x4000    R/W   W_MACMEM        [random] MAC memory (0x2000 bytes)
0x5F60          ?               Used for something, not included in the rx circular buffer. (ssid maybe?)
0x5F80          W_WEPKEY1 (32 bytes) 
0x5FA0          W_WEPKEY2 (32 bytes)
0x5FC0          W_WEPKEY3 (32 bytes)
0x5FE0          W_WEPKEY4 (32 bytes)

Hardware Init Sequence

This section contains a few of the initialization sequences, and other requisite information for starting up the wireless system on the DS.
In addition, there are some pseudocode for necessary routines (notably RF_Write, BB_Write and BB_Read) which are necessary in the init sequence
[Some of the information here has been clarified since the first version, but there's still a lot unknown about this hardware. Regardless, it's perfectly possible to use it]

Main Initialization sequence

These events must be done somewhat in sequence. There is some flexibility as to how they can be ordered but it's best to follow this order:
[Init Sequence:]
 POWERCNT |= 2;                                    -- Enable power to the wifi system
 *((volatile u16 *)0x04000206) = 0x30;             -- unclear if this is necessary, or exactly what it does.
 Set Mac address - copy 6 bytes from flash[0x36] to mac address at 0x04800018
 W_IE = 0;                                         -- Disable interrupts
 
 Wake Up the wireless system:
   [u16 0x04800036] = 0                            -- (still not sure what this does)
   delay 8 ms
   [u16 0x04800168] = 0                            -- (still not sure what this does)
   temp = BB_Read(1);                              -- read baseband address 1
   BB_Write(1,temp&0x7F);                          -- clear bit 8 & write back
   BB_Write(1,temp);                               -- restore bit 8 & write back (probably an init)
   delay 30 ms
   RF_Init                                          -- same as "Init the RF system", below. this or the other one is probably not necessary.
   
 Init the Mac system:
   Set the following registers (offset from 0x04800000) to the specified values:
   reg[0x04] = 0                                   -- set hardware mode
   reg[0x08] = 0                                   -- ?
   reg[0x0A] = 0                                   -- ? (related to rx filter)
   reg[0x12] = 0                                   -- Wifi IE = 0
   reg[0x10] = 0xffff                              -- reset Wifi IF
   reg[0x254]= 0                                   -- ?
   reg[0xB4] = 0xffff                              -- ?
   reg[0x80] = 0                                   -- Disable automatic beacon transmission
   reg[0x2A] = 0                                   -- ?
   reg[0x28] = 0                                   -- set AID to 0
   reg[0xE8] = 0                                   -- Disable microsecond counter
   reg[0xEA] = 0                                   -- ?
   reg[0xEE] = 1                                   -- ?
   reg[0xEC] = 0x3F03                              -- ?
   reg[0x1A2]= 1                                   -- ?
   reg[0x1A0]= 0                                   -- ?
   reg[0x110]= 0x0800                              -- ?
   reg[0xBC] = 1                                   -- ? and disable short preamble
   reg[0xD4] = 3                                   -- ?
   reg[0xD8] = 4                                   -- ?
   reg[0xDA] = 0x0602                              -- ?
   reg[0x76] = 0                                   -- set W_CIRCBUFWR_SKIP to 0 (skip nothing when using write circular buffer)
   
 Init the RF system:
   write 16bit values from flash (starting at offset 0x44) to the following list of registers (offset from 0x04800000) - the actual assignments are also listed here for reference.
   list: 0x146, 0x148, 0x14A, 0x14C, 0x120, 0x122, 0x154, 0x144, 0x130, 0x132, 0x140, 0x142, 0x38, 0x124, 0x128, 0x150
   Actual assignments (based on present firmware dumps):
   reg[0x146] = 0x0002                             -- ? (I'm speculating wildly here, but I'd bet most of these are timing values.)
   reg[0x148] = 0x0017                             -- ?
   reg[0x14A] = 0x0026                             -- ?
   reg[0x14C] = 0x1818                             -- ?
   reg[0x120] = 0x0048                             -- ?
   reg[0x122] = 0x4840                             -- ?
   reg[0x154] = 0x0058                             -- ?
   reg[0x144] = 0x0042                             -- ?
   reg[0x130] = 0x0140                             -- ?
   reg[0x132] = 0x8064                             -- ?
   reg[0x140] = 0xE0E0                             -- ?
   reg[0x142] = 0x2443                             -- ?
   reg[0x038] = 0x000E                             -- ? [unclear, but related to power saving]
   reg[0x124] = 0x0032                             -- ?
   reg[0x128] = 0x01F4                             -- ?
   reg[0x150] = 0x0101                             -- ?
   numentries = flash byte at 0x42 (=0x0C == 12)
   numbits = flash byte at 0x41
   numbytes = (numbits+7)/8;
   reg[0x184] = ((numbits<<1) & 0x0100) | (numbits&0x7F) -- W_RFSIOCNT, specifies number of bits per transfer
   if flash byte 0x40 == 3 { -- doesn't in current firmware...
     for(i=0;i<numentries;i++) RF_Write(0x50000 | (i<<8) | flash byte at 0xCE+i);  -- not going to go over this one, as it's not the case in present firmware.
   } else {
     for(i=0;i<numentries;i++) RF_Write(numbytes flash bytes, starting at 0xCE + i*numbytes);
   }
   For the second case, which is the currently used one, the following values are written to RF_Write: (see section on RF chip for more speculation)
   RF_Write 0x00C007
   RF_Write 0x129C03
   RF_Write 0x141728
   RF_Write 0x1AE8BA
   RF_Write 0x1D456F
   RF_Write 0x23FFFA
   RF_Write 0x241D30
   RF_Write 0x280001
   RF_Write 0x2C0000
   RF_Write 0x069C03
   RF_Write 0x080022
   RF_Write 0x0DFF6F		-- really odd values, unclear exactly what they mean but it's likely they're initializing a PLL or something with various frequencies or options.

 Init the BaseBand System:  -- and you thought the RF init was bad?
   The baseband init is rather simple, just read in 105 values and write them to the baseband. simple, eh? :)
   routine goes like this:
   reg(0x160) = 0x0100
   for(i=0;i<0x69;i++) BB_Write( i, flash byte 0x64+i );
   For your convenience (or torture), all 105 values are listed here:
   BB_Write   0, 0x6D       BB_Write   1, 0x9E       BB_Write   2, 0x40       BB_Write   3, 0x05
   BB_Write   4, 0x1B       BB_Write   5, 0x6C       BB_Write   6, 0x48       BB_Write   7, 0x80
   BB_Write   8, 0x38       BB_Write   9, 0x00       BB_Write  10, 0x35       BB_Write  11, 0x07
   BB_Write  12, 0x00       BB_Write  13, 0x00       BB_Write  14, 0x00       BB_Write  15, 0x00
   BB_Write  16, 0x00       BB_Write  17, 0x00       BB_Write  18, 0x00       BB_Write  19, 0x00
   BB_Write  20, 0xB0       BB_Write  21, 0x00       BB_Write  22, 0x04       BB_Write  23, 0x01
   BB_Write  24, 0xD8       BB_Write  25, 0xFF       BB_Write  26, 0xFF       BB_Write  27, 0xC7
   BB_Write  28, 0xBB       BB_Write  29, 0x01       BB_Write  30, 0xB6       BB_Write  31, 0x7F
   BB_Write  32, 0x5A       BB_Write  33, 0x01       BB_Write  34, 0x3F       BB_Write  35, 0x01
   BB_Write  36, 0x3F       BB_Write  37, 0x36       BB_Write  38, 0x36       BB_Write  39, 0x00
   BB_Write  40, 0x78       BB_Write  41, 0x28       BB_Write  42, 0x55       BB_Write  43, 0x08
   BB_Write  44, 0x28       BB_Write  45, 0x16       BB_Write  46, 0x00       BB_Write  47, 0x01
   BB_Write  48, 0x0E       BB_Write  49, 0x20       BB_Write  50, 0x02       BB_Write  51, 0x98
   BB_Write  52, 0x98       BB_Write  53, 0x1F       BB_Write  54, 0x0A       BB_Write  55, 0x08
   BB_Write  56, 0x04       BB_Write  57, 0x01       BB_Write  58, 0x00       BB_Write  59, 0x00
   BB_Write  60, 0x00       BB_Write  61, 0xFF       BB_Write  62, 0xFF       BB_Write  63, 0xFE
   BB_Write  64, 0xFE       BB_Write  65, 0xFE       BB_Write  66, 0xFE       BB_Write  67, 0xFC
   BB_Write  68, 0xFC       BB_Write  69, 0xFA       BB_Write  70, 0xFA       BB_Write  71, 0xFA
   BB_Write  72, 0xFA       BB_Write  73, 0xFA       BB_Write  74, 0xF8       BB_Write  75, 0xF8
   BB_Write  76, 0xF6       BB_Write  77, 0xA5       BB_Write  78, 0x12       BB_Write  79, 0x14
   BB_Write  80, 0x12       BB_Write  81, 0x41       BB_Write  82, 0x23       BB_Write  83, 0x03
   BB_Write  84, 0x04       BB_Write  85, 0x70       BB_Write  86, 0x35       BB_Write  87, 0x0E
   BB_Write  86, 0x16       BB_Write  89, 0x16       BB_Write  90, 0x00       BB_Write  91, 0x00
   BB_Write  92, 0x06       BB_Write  93, 0x01       BB_Write  94, 0xFF       BB_Write  95, 0xFE
   BB_Write  98, 0xFF       BB_Write  97, 0xFF       BB_Write  98, 0x00       BB_Write  99, 0x0E
   BB_Write 100, 0x13       BB_Write 101, 0x00       BB_Write 102, 0x00       BB_Write 103, 0x28
   BB_Write 104, 0x1C 

   (--phew--)

 Set Mac address - copy 6 bytes from flash[0x36] to mac address at 0x04800018
-- now just set some default varibles
 W_RETRLIMIT=7               -- actually, we now know this needs to be set for every transmit

 Set channel (see section on changing channels)
 Set Mode 2 -- sets bottom 3 bits of W_MODE_WEP to 2
 Set Wep Mode / key -- Wep mode is bits 3..5 of W_MODE_WEP
 
 BB_Write 0x13, 0x00  -- BB register 0x13 is CCA operation (0=carrier sense only, 1=only valid with ED value, 2=CS or ED, 3=CS and ED)
 BB_Write 0x35, 0x1F  -- BB register 0x35 is ED (Energy Detection Threshold values 0..61, representing -60dBm to -80dBm - I think in that order)
 
-- To further init wifi to the point that you can properly send and receive data, there are some more variables that need to be set.
  reg[0x032] = 0x8000 -- Enable wep processing on packets which bear the WEP flag in the 802.11 header
  reg[0x134] = 0xFFFF -- resets a millisecond counter related to beacons
  reg[0x028] = 0      -- clear W_AID value
  reg[0x02A] = 0      -- ? (they just like setting it when they set W_AID)
  reg[0x0E8] = 1      -- enable microsecond counter
  reg[0x038] = 0      -- disable transmit power save
  reg[0x020] = 0      -- clear BSSID (this and the next 2 writes)
  reg[0x022] = 0
  reg[0x024] = 0
  -- TX prepare
    reg[0x0AE] = 0x000D -- flush all pending transmits
  -- RX prepare
    reg[0x030] = 0x8000 -- enable RX system
    reg[0x050] = 0x4C00 -- RX Fifo begin (these are just my default values, you can set basicly whatever you want.
    reg[0x052] = 0x5F60 -- RX Fifo end (length = 4960 bytes)
    reg[0x056] = 0x0600 -- fifo begin latch address, 0xC00/2 = 0x600
    reg[0x05A] = 0x0600 -- fifo end, same as begin at start.
    reg[0x062] = 0x5F5E -- last element of fifo (unclear if this is necessary)
    reg[0x030] = 0x8001 -- enable, and latch new fifo values for hardware use
    
  reg[0x030] = 0x8000 -- enable receive (this is duplicated)
  W_IF=0xFFFF         -- clear interrupt flags
  W_IE=(whatever)     -- set enabled interrupts
  reg[0x1AE] = 0x1FFF -- set what STAT *overflows* you would like to cause an interrupt
  reg[0x1AA] = 0      -- set what STAT *increases* you would like to cause an interrupt
  reg[0x0D0] = 0x181  -- set this to 0x581 when you successfully connect to an access point and fill W_BSSID with a mac address for it. (W_RXFILTER) [not sure on the values for this yet]
  reg[0x0E0] = 0x000B -- ?
  reg[0x008] = 0      -- ?
  reg[0x00A] = 0      -- ? [related to filtering]
  reg[0x004] = 1      -- hardware mode
  reg[0x0E8] = 1      -- enable microsecond counter (this is duplicated too)
  reg[0x0EA] = 1      -- ? [possibly related to microsecond counter compare register]
  reg[0x048] = 0      -- ? [disabling a power saving technique, no doubt]
  reg[0x038] &= ~2    -- ? [this too]
  reg[0x048] = 0      -- ? [umm, it's done again. unclear if it's necessary]
  reg[0x0AE] = 2      -- setting a bit that doesn't appear to be used; purpose is unclear.
  reg[0x03C] |= 2     -- queue enable power! (RX power, we beleive)
  reg[0x0AC] = 0xFFFF -- reset something.
 
 And, that's it. after all that the DS should be happy to send and receive packets. 
It's very possible there are unnecessary register sets in here, but this pseudocode is based very closely on my current working codebase, and it should work.
I just haven't had the time to weed out all of the unnecessary parts, and test to verify they were indeed unnecessary.

Please keep in mind that this is very preliminary information, if you find bugs or can't make it work, please let me know (contact info on the top and bottom of this page)

Support routines

The following routines were used in the earlier init sequence, and it's somewhat important to know how they work.
RF_Write(data)
  while(W_RFSIOBUSY&1);
  W_RFSIODATA1=(data & 0xFFFF);
  W_RFSIODATA2=(data >> 16);
  while(W_RFSIOBUSY&1);

BB_Write(address,data)
  counter=10000;
  while((W_BBSIOBUSY&1) && (--counter));
  if(!counter) return -1;
  W_BBSIOWRITE=data;
  W_BBSIOCNT=address | 0x5000;
  counter=10000;
  while((W_BBSIOBUSY&1) && (--counter));
  return 0;

BB_Read(address)
  counter=10000;
  while((W_BBSIOBUSY&1) && (--counter));
  if(!counter) return -1;
  W_BBSIOCNT=address | 0x6000;
  while(W_BBSIOBUSY&1);
  return W_BBSIOREAD;

Reading from flash

Undoubtedly some of you are going to want to read the values from flash (if not all of you.) In the case you haven't seen how to do it elsewhere, here's a routine to do it:
void Read_Flash(int address, char * destination, int length) {
	int i;
	while(SPI_CR&0x80);
	SPI_CR=0x8900;
	SPI_DATA=3;
	while(SPI_CR&0x80);
	SPI_DATA=(address>>16)&255;
	while(SPI_CR&0x80);
	SPI_DATA=(address>>8)&255;
	while(SPI_CR&0x80);
	SPI_DATA=(address)&255;
	while(SPI_CR&0x80);
	for(i=0;i<length;i++) {
		SPI_DATA=0;
		while(SPI_CR&0x80);
		destination[i]=SPI_DATA;
	}
	SPI_CR=0;
}

BaseBand chip registers

This section contains some solid information and a lot of speculation about what some of the baseband registers could be. (The meanings of these are *largely* unknown, and very little in the reverse engineered code modifies the values)
Address | Initial Value | Meaning
    0          0x6D       ?
    1          0x9E       [unsetting/resetting bit 7 initializes/resets the system]
    2          0x40       ?
    3          0x05       ?
    4          0x1B       ?
    5          0x6C       ?
    6          0x48       ?
    7          0x80       ?
    8          0x38       ?
    9          0x00       ?
   10          0x35       ?
   11          0x07       ?
   12          0x00       ?
   13          0x00       ?
   14          0x00       ?
   15          0x00       ?
   16          0x00       ?
   17          0x00       ?
   18          0x00       ?
   19          0x00       CCA operation - criteria for receiving (0=only use Carrier Sense (CS), 1=only use Energy Detection (ED), 2=receive if CS OR ED, 3= receive only if CS AND ED)
   20          0xB0       ?
   21          0x00       ?
   22          0x04       ?
   23          0x01       ?
   24          0xD8       ?
   25          0xFF       ?
   26          0xFF       ?
   27          0xC7       ?
   28          0xBB       ?
   29          0x01       ?
   30          0xB6       ?
   31          0x7F       ?
   32          0x5A       ?
   33          0x01       ?
   34          0x3F       ?
   35          0x01       ?
   36          0x3F       ?
   37          0x36       ?
   38          0x36       ?
   39          0x00       ?
   40          0x78       ?
   41          0x28       ?
   42          0x55       ?
   43          0x08       ?
   44          0x28       ?
   45          0x16       ?
   46          0x00       ?
   47          0x01       ?
   48          0x0E       ?
   49          0x20       ?
   50          0x02       ?
   51          0x98       ?
   52          0x98       ?
   53          0x1F       Energy Detection (ED) criteria - value 0..61 (representing energy levels of -60dBm to -80dBm)
   54          0x0A       ?
   55          0x08       ?
   56          0x04       ?
   57          0x01       ?
   58          0x00       ?
   59          0x00       ?
   60          0x00       ?
   61          0xFF       ?
   62          0xFF       ?
   63          0xFE       ?
   64          0xFE       ?
   65          0xFE       ?
   66          0xFE       ?
   67          0xFC       ?
   68          0xFC       ?
   69          0xFA       ?
   70          0xFA       ?
   71          0xFA       ?
   72          0xFA       ?
   73          0xFA       ?
   74          0xF8       ?
   75          0xF8       ?
   76          0xF6       ?
   77          0xA5       ?
   78          0x12       ?
   79          0x14       ?
   80          0x12       ?
   81          0x41       ?
   82          0x23       ?
   83          0x03       ?
   84          0x04       ?
   85          0x70       ?
   86          0x35       ?
   87          0x0E       ?
   86          0x16       ?
   89          0x16       ?
   90          0x00       ?
   91          0x00       ?
   92          0x06       ?
   93          0x01       ?
   94          0xFF       ?
   95          0xFE       ?
   98          0xFF       ?
   97          0xFF       ?
   98          0x00       ?
   99          0x0E       ?
  100          0x13       ?
  101          0x00       ?
  102          0x00       ?
  103          0x28       ?
  104          0x1C       ?

RF chip data formats

Below is a list of the various data that is sent to the RF chip at various times, and an attempt at an analysis of it.
[Used in RF init:]
   0x00C007
   0x129C03
   0x141728
   0x1AE8BA
   0x1D456F
   0x23FFFA
   0x241D30
   0x280001
   0x2C0000
   0x069C03
   0x080022
   0x0DFF6F
[Written when changing channels:]


Wifi Rx Registers

(Wifi registers are accessed with a base of 0x04800000)
0x0030 - W_RXCNT - Wifi Receive Control (R/W)
 Bit  Description
15   Enable Queuing received data to RX FIFO
 0   Latch registers for RX FIFO
Latched registers include: W_RXRANGEBEGIN, W_RXRANGEEND and also W_HWWRITECSR=W_WRITECSRLATCH

0x0050 - W_RXRANGEBEGIN - Wifi RX Fifo start location (R/W)
Set to a value in the range 0x4000..0x5FFE. This is an actual offset from the start of wifi memory, the address 0x04800000+W_RXRANGEBEGIN is the address it points to.
(Theory: This value is anded by 0x1FFE internally, perhaps even 0x1FFC, I haven't tested this though.)

0x0052 - W_RXRANGEEND - Wifi RX Fifo end location (R/W)
Set to a value in the range 0x4000..0x5FFE. This is an actual offset from the start of wifi memory, the address 0x04800000+W_RXRANGEEND is the address it points to. This is the address immediately after the last halfword that will be used by the fifo.
(Theory: This value is anded by 0x1FFE internally, perhaps even 0x1FFC, I haven't tested this though.)

0x0054 - W_RXHWWRITECSR - Wifi RX Fifo Write or "end" cursor (R)
This is a hardware controlled write location - it shows where the next packet will be written.. The value is the offset from the start of MAC memory, divided by two.
(This means that the address 0x04804508 would be represented as 0x284, the offset from the start of mac memory is 0x508, divided by two is 0x284)

0x0056 - W_WRITECSRLATCH - Wifi RX Fifo Write Cursor Latch value (R/W)
This is a value that is latched into W_RXHWWRITECSR, when the W_RXCNT latch bit is written.

0x005A - W_RXREADCSR - Wifi RX Fifo Read or "start" cursor (R/W)
This value is specified the same as W_RXHWWRITECSR - it's purely software controlled so it's up to the programmer to move the start cursor after loading a packet. if W_RXREADCSR != W_RXHWWRITECSR, then one or more packets exist in the FIFO that need to be processed. (See the section on HW RX Headers, for information on calculating packet lengths) Once a packet has been processed, the software should advance the read cursor to the beginning of the next packet.

Wifi Tx Registers

(Wifi registers are accessed with a base of 0x04800000)
0x00A0 - W_TXLOC1 - Transmit location 1 (R/W)
bottom 12 bits = offset from start of MAC memory of a TX frame header, in halfwords; top bit = set to enable record; (bits 12..14 unknown)

0x00A4 - W_TXLOC2 - Transmit location 2 (R/W)
bottom 12 bits = offset from start of MAC memory of a TX frame header, in halfwords; top bit = set to enable record; (bits 12..14 unknown)

0x00A8 - W_TXLOC3 - Transmit location 3 (R/W)
bottom 12 bits = offset from start of MAC memory of a TX frame header, in halfwords; top bit = set to enable record; (bits 12..14 unknown)

0x00AC - W_TXOPT - Set Transmit Options (W)
Values are unknown, 0xFFFF is written to clear everything AFAIK

0x00AE - W_TXCNT - Transmit Control/Enable (W)
Write a combination of the values 0x0001, 0x0004, and 0x0008 to send packets specified by W_TXLOC1, W_TXLOC2, and W_TXLOC3, respectively. If a valid frame is at one of the TXLOC records that was enabled, A frame is transmitted immediately.

0x00B0 - W_TXINFO - Info about transmit state (W)
Values are unknown, but related to setting W_TXOPT.

0x00B8 - W_TXSTAT - Status of transmitted frame (W)
Values are unknown, but related to number of transmit retries and whether an ACK was received in response to transmission.

Wifi RF/BB Chip Control Registers

(Wifi registers are accessed with a base of 0x04800000)
0x0158 - W_BBSIOCNT - Baseband serial transfer control (R/W)
Write to this register to initiate a baseband chip transfer.
bits 15..12 are a "transfer type" control, and the rest are the address to transfer to/from. Transfer type of 5 is a write transfer (W_BBSIOWRITE is written) and transfer type of 6 is a read (read to W_BBSIOREAD). All transfers are byte transfers, the method of reading/writing is not fully understood.

0x015A - W_BBSIOWRITE - Baseband serial write data (R/W)
This register holds the byte to be written to the Baseband chip on the next write command.

0x015C - W_BBSIOREAD - Baseband serial read data (R/W)
This register holds the byte read from the Baseband chip on the most recent read command.

0x015E - W_BBSIOBUSY - Baseband serial busy flag (R)
The bottom bit of this register indicates when a transfer is presently in progress (1= busy, 0=ready)

0x017C - W_RFSIODATA2 - RF chip serial data/transfer enable (?/W)
This register holds the top 16 bits of a value to send to the RF chip, and when this value is written, the transfer begins.

0x017E - W_RFSIODATA1 - RF chip serial data (?/W)
This register holds the bottom 16 bits of a value to send to the RF chip.

0x0180 - W_RFSIOBUSY - RF chip serial busy flag (?/W)
When an RF chip serial transfer is in progress, the bottom bit of this register is 1, otherwise it's 0.

0x0184 - W_RFSIOCNT - RF chip serial control (?/W)
The bottom 7 bits of this register specifiy the length of the RF chip serial transfer (default=0x0018, 24-bit transfer). Bit 8 is also used, but it's use is unknown at the moment. [Pure speculation: it's probably used to reverse the order data is sent]

Wifi Other Registers

(Wifi registers are accessed with a base of 0x04800000)
0x0004 - W_MODE_RST - Wifi Hardware mode / reset (R/W)
The bottom few bits of this register specify a hardware mode, which seems to have little effect on the hardware itself, but may do something important
The top bit of this register, when set, wipes out a good deal of the settings associated with Wifi, including a number of settings that exist just below the surface and are hard to access.

0x0006 - W_MODE_WEP - Wifi Software mode / Wep mode (R/W)
The bottom 3 bits of this register specify a software mode for wifi operation (may be related to hardware but a correlation has not yet been found)
bits 3-5 specify the hardware WEP mode - a value of 0= no WEP, 1=64bit WEP (48bit key), and 3=128bit WEP. (Values 2 and 4 exist too, but are nonstandard)

0x0010 - W_IF - Wifi Interrupt Request Flags (R/W)
 Bit  Description
 0   Receive Complete interrupt - raised immediately after a packet is received and stored in the RX fifo
 1   Transmit Complete interrupt - raised immediately after a packet is done being transmitted
 2   Receive Count Up interrupt - raised when a packet is received, regardless of whether it's stored in the RX fifo
 3   Transmit Error interrupt - raised when transmit header is incorrect, or another error occured.
 4   Statistics Count Overflow interrupt - raised when a stat is increased
 5   Statistics Ack Count Overflow interrupt - raised when a certain kind of stat is increased
 6   Start Receive interrupt - raised when a packet has just started to be received
 7   Start Transmit interrupt - raised when a packet has just started to be transmitted
 8   ?
 9   ?
 10  ?
 11  RF Wakeup Interrupt - raised when the RF system wakes up
 12  ?
 13  ?
 14  Beacon Timeslot interrupt - raised right after a beacon should have been sent, in a "safe zone" for sending data
 15  Pre Beacon Timeslot interrupt - raised right before a beacon is predicted to be sent (if the timings are configured correctly)
Write a '1' to a bit to clear it.

0x0012 - W_IE - Wifi Interrupt Enable Flags (R/W) (same bits as W_IF)
All the bits are '1' to enable and '0' to disable the interrupt.

0x8018 - MACADDR_0 - MAC Address (R/W)
0x801A - MACADDR_1 - MAC Address (R/W)
0x801C - MACADDR_2 - MAC Address (R/W)
MAC Address stored here

0x8020 - BSSID_0 - BSSID (R/W)
0x8022 - BSSID_1 - BSSID (R/W)
0x8024 - BSSID_2 - BSSID (R/W)
BSSID stored here

0x0044 - W_RANDOM - Wifi Pseudorandom number generator (R)
"For curiosity, The random generator is updated at 33MHz rate, as such:
X = (X AND 1) XOR (X ROL 1) ;(rotation within 11bit range)
The random sequence goes through 5FDh different values before it restarts.
When reading from the random register, the old latched value is returned to the CPU, and the new current random value is then latched, so reads always return the older value, timed from the previous read. Occassionally, about once every some thousand reads, the latching appears to occur 4 cycles earlier than normally, so the value on the next read will be 4 cycles older than expected.
The random register has ACTIVE mirrors."
(Thanks Martin)

0x0058 - W_CIRCBUFRDADR - Wifi CircBuf Read Address (R/W)
This is an address used for a built-in circular buffer reading system. It is a value anded by 0x1FFE, and used as an offset to 0x04804000. The circular buffer limits are the same as the range specified for the receive FIFO, however the address can be set outside of that range and will only be affected by the FIFO boundary if it crosses the FIFO end location by reading from the circular buffer.

0x0060 - W_CIRCBUFREAD - Wifi CircBuf Read Data (R/W)
When you read this address, it returns the 16bit value at the address specified by W_CIRCBUFRDADR, and increments W_CIRCBUFRDADR by 2. If the increment causes W_CIRCBUFRDADR to equal the address specified in W_RXRANGEEND, W_CIRCBUFRDADR will be reset to the address specified in W_RXRANGEBEGIN.

0x0068 - W_CIRCBUFWRADR - Wifi CircBuf Write Address (R/W)
This is an address like the one in W_CIRCBUFRDADR, only it's used for writing to the circular buffer by W_CIRCBUFWRITE The circular buffer in this case, isn't much of a circular buffer- it consists of an end value (W_CIRCBUFWR_END) and a skip value (W_CIRCBUFWR_SKIP) such that if W_CIRCBUFWRADR==end_value, then W_CIRCBUFWRADR+=skip_value*2 (yes, it's odd).

0x0070 - W_CIRCBUFWRITE - Wifi CircBuf Write Data (W)
When you read this address, it returns the 16bit value from W_CIRCBUFREAD, but doesn't modify the read address. When you write this location, the value you write is written to the address specified by W_CIRCBUFWRADR, and W_CIRCBUFWRADR is incremented by 2. see W_CIRCBUFWRADR for more information about how it's value "wraps around" if you can call it that. However, I don't consider this register to be very useful, and the behavior of the write cursor just reinforces that ;)

0x0074 - W_CIRCBUFWR_END - Wifi Write "circular buffer" end (R/W)
This address indicates the "end" of the buffer addressed by W_CIRCBUFWRADR

0x0076 - W_CIRCBUFWR_SKIP - Wifi Write Address (R/W)
When the write cursor in W_CIRCBUFWRADR hits W_CIRCBUFWR_END, W_CIRCBUFWRADR+=2*W_CIRCBUFWR_SKIP (this value) (yes, it's odd).

0x01B0, etc.. - W_STAT - Wifi statistics (R)
the W_STAT registers are a collection of registers (specificly: 0x1B0, 0x1B2, 0x1B4, 0x1B6, 0x1B8, 0x1BA, 0x1BC, 0x1BE, 0x1C0, 0x1C4, 0x1D0, 0x1D2, 0x1D4, 0x1D6, 0x1D8, 0x1DA, 0x1DC, 0x1DE)
Each halfword contains two bytes that are individual statitistics - when a halfword is read both bytes are reset to zero. The actual statistics that are represented are presently unknown, some effort will be put into trying to identify them sometime soon.
Additionally, when one of them increments, generally a "Counter overflow" or "AckCounter Overflow" interrupt is flagged. (see info on W_IE and W_IF)

0x5F80 - W_WEPKEY1 thru W_WEPKEY4 - Wifi WEP keys (R/W)
These WEP key slots store the WEP keys that are used for encryption for 802.11 keys IDs 0-3.

Wifi Unknown Registers

There are really waaaay too many of these to list at the moment. But I'll be adding information as I figure it out.

Wifi Transmit Procedure

To transmit data via wifi (Assuming you've already initialized wifi and changed channels to the channel you want):
(1) Copy the TX Header followed by the 802.11 packet to send anywhere it will fit in MAC memory (halfword-aligned)
(2) Take the offset from start of MAC memory that you put the packet, divide it by 2, and or with 0x8000 - store this in one of the W_TXLOC registers
(3) Set W_RETRLIMIT, to allow your packet to be retried until an ack is received (set it to 7, or something similar)
(4) Store the bit associated with the W_TXLOC register you used into W_TXCNT - this will send the packet.
(5) You can then read the result data in W_TXSTAT when the TX is over (you can tell either by polling or interrupt) to find out how many retries were used, and if the packet was ACK'd
Of course, this is just the simplest approach, you can be a lot more clever about it.

Wifi Receive Procedure

To receive data via wifi, you either need to handle the wifi received data interrupt, or you need to poll W_RXHWWRITECSR - whenever it is != W_RXREADCSR, there is a new packet. When there is a new packet, take the following approach:
(1) Calculate the length of the new packet (read "received frame length" which is +8 bytes from the start of the packet) - total frame length is (12 + received frame length) padded to a multiple of 4 bytes.
(2) Read the data out of the RX FIFO area (keep in mind it's a circular buffer and you may have to wrap around the end of the buffer)
(3) Set the value of W_RXREADCSR to the location of the next packet (add the length of the packet, and wrap around if necessary)
Keep in mind, W_RXREADCSR and W_RXHWWRITECSR must be multiplied by 2 to get a byte offset from the start of MAC memory.

Wifi Change Channels Procedure

You can set the channel to any channel number between 1 and 13 (inclusive) on the DS hardware. here's some pseudocode to do it:
read 3 bytes of flash starting at (0xF2+(channel-1)*6) to a temporary value
call RF_Write with the 3 bytes you just read (as a 0-padded long value)
read 3 bytes of flash starting at (0xF5+(channel-1)*6) to a temporary value
again, call RF_Write with the 3 bytes you just read (as a 0-padded long value)
delay a few milliseconds
call BB_Write with parameters 0x1E, and the byte in flash at 0x146+(channel-1)
Congrats, you are now ready to transmit/receive on whatever channel you picked.

About the "undefined" data in this document

This document is a collection of information that I've found over the course of several months of digging through complex code, in an attempt to understand how it works. A good number of the variables in the wifi space are not touched more than once, if they're touched at all by the code I've been disassembling, and there's really no way to know exactly what they do without extensive tinkering or official documentation. As the official documentation isn't going to show up in my hands any time soon, I've spent a lot of time tinkering with registers in an attempt to understand how they work when the code doesn't make it very clear. As much as I'd love to do this for each and every register in the DS Wifi, I really won't live that long... There are over a hundred registers in the wifi area, even close to 200. I've probably only documented about a third of them, but as it's entirely possible to use the implementation without all of them, I still consider this a success. Perhaps someday we'll find the actual hardware documentation for this device, but until then, this is all we have to work with... If you've figured some things out via tinkering, feel free to let me know, I'll be happy to add it to the documentation (My contact info is linked at the bottom of this page). Until then, good luck with the hardware, I hope it works as well or better for you as it does for me :)
-Stephen

802.11

Info on 802.11 is not being included yet because it's very well (over)documented elsewhere. mainly the 802.11 specification, which is open to public use at the moment. just google "get ieee 802" and follow links from there.
I will eventually add information on the IEEE 802.11 format here, because the IEEE document is huge, bloated, unclear, and hard to understand (it is very thorough, though). But, for now I need to divert my time to other things.
[Version 0.02 of this doc comes around, and the same holds true. 802.11 is just a pain, good luck if you're trying to use it :)]

Hardware TX header

The TX header is a structure needed by the wifi hardware, it contains important information such as the length of the packet being sent and the rate at which to send (possibly other things too). The TX header is always 12 bytes, it immediately precedes the data to be sent, and should be put at the location that will be given to the register activating a transmission.
The TX header takes the following form: (entries are halfwords)
Offset Description
 +0    Unknown (used by hardware)
 +2    Unknown (used by hardware)
 +4    Unknown (used by hardware)
 +6    Unknown (used by hardware)
 +8    Transmit rate (speed in megabits multiplied by 10 - 1.0Mbit is 0x0A, 2.0Mbit is 0x14)
 +10   Transmit length (bytes) transmits the data at +12 through +12+length-1 inclusive.
Important note! TX length includes the length of a 4-byte "FCS" (checksum) for the packet. The hardware generates the FCS for you, but you still must include it in the packet length. Also note that if the 802.11 WEP enabled bit is set in the header, the packet will be automatically encrypted via the wep algorithm - however, the software is responsible for providing the 4-byte IV block with the WEP key ID and the 24bit IV value. - ALSO, you must include the length of the *encrypted* FCS used in packets that have wep enabled (increase the tx length by another 4 bytes) - this value is calculated automaticly for you, but you are responsible for including it in the length of your packet (if you have data there, it'll be replaced by the FCS.)

Hardware RX header

The RX header is an informational structure that provides needed information about a received packet. It is written right before the received packet data in the rx circular buffer. The RX header is always 12 bytes.
The RX header takes the following form: (entries are halfwords)
Offset Description
 +0    Unknown (used by hardware)
 +2    Unknown (used by hardware)
 +4    Unknown (used by hardware)
 +6    Unknown (used by hardware)
 +8    Received frame length (bytes)
 +10   RSSI Range (Bottom 8 bits are MAX RSSI, top 8 bits are MIN RSSI, during the receipt of the packet)
Important Note: Received frame lengths are always multiples of 4 bytes. While the actual header length + received frame length may be less, when incrementing the read cursor you must pad the length to a multiple of 4 bytes