.psize 0
#include <linux/hdlc.h>
#include <linux/hdlc/ioctl.h>
#include "wanxl.h"
MAX_RAM_SIZE = 16 * 1024 * 1024
PCI9060_VECTOR = 0x0000006C
CPM_IRQ_BASE = 0x40
ERROR_VECTOR = CPM_IRQ_BASE * 4
SCC1_VECTOR = (CPM_IRQ_BASE + 0x1E) * 4
SCC2_VECTOR = (CPM_IRQ_BASE + 0x1D) * 4
SCC3_VECTOR = (CPM_IRQ_BASE + 0x1C) * 4
SCC4_VECTOR = (CPM_IRQ_BASE + 0x1B) * 4
CPM_IRQ_LEVEL = 4
TIMER_IRQ = 128
TIMER_IRQ_LEVEL = 4
PITR_CONST = 0x100 + 16
MBAR = 0x0003FF00
VALUE_WINDOW = 0x40000000
ORDER_WINDOW = 0xC0000000
PLX = 0xFFF90000
CSRA = 0xFFFB0000
CSRB = 0xFFFB0002
CSRC = 0xFFFB0004
CSRD = 0xFFFB0006
STATUS_CABLE_LL = 0x2000
STATUS_CABLE_DTR = 0x1000
DPRBASE = 0xFFFC0000
SCC1_BASE = DPRBASE + 0xC00
MISC_BASE = DPRBASE + 0xCB0
SCC2_BASE = DPRBASE + 0xD00
SCC3_BASE = DPRBASE + 0xE00
SCC4_BASE = DPRBASE + 0xF00
SCC_RBASE = 0
SCC_TBASE = 2
SCC_RFCR = 4
SCC_TFCR = 5
SCC_MRBLR = 6
SCC_C_MASK = 0x34
SCC_C_PRES = 0x38
SCC_MFLR = 0x46
REGBASE = DPRBASE + 0x1000
PICR = REGBASE + 0x026
PITR = REGBASE + 0x02A
OR1 = REGBASE + 0x064
CICR = REGBASE + 0x540
CIMR = REGBASE + 0x548
CISR = REGBASE + 0x54C
PADIR = REGBASE + 0x550
PAPAR = REGBASE + 0x552
PAODR = REGBASE + 0x554
PADAT = REGBASE + 0x556
PCDIR = REGBASE + 0x560
PCPAR = REGBASE + 0x562
PCSO = REGBASE + 0x564
PCDAT = REGBASE + 0x566
PCINT = REGBASE + 0x568
CR = REGBASE + 0x5C0
SCC1_REGS = REGBASE + 0x600
SCC2_REGS = REGBASE + 0x620
SCC3_REGS = REGBASE + 0x640
SCC4_REGS = REGBASE + 0x660
SICR = REGBASE + 0x6EC
SCC_GSMR_L = 0x00
SCC_GSMR_H = 0x04
SCC_PSMR = 0x08
SCC_TODR = 0x0C
SCC_DSR = 0x0E
SCC_SCCE = 0x10
SCC_SCCM = 0x14
SCC_SCCS = 0x17
#if QUICC_MEMCPY_USES_PLX
.macro memcpy_from_pci src, dest, len
addl #3, \len
andl #0xFFFFFFFC, \len
movel \src, PLX_DMA_0_PCI
movel \dest, PLX_DMA_0_LOCAL
movel \len, PLX_DMA_0_LENGTH
movel #0x0103, PLX_DMA_CMD_STS
bsr memcpy_from_pci_run
.endm
.macro memcpy_to_pci src, dest, len
addl #3, \len
andl #0xFFFFFFFC, \len
movel \src, PLX_DMA_1_LOCAL
movel \dest, PLX_DMA_1_PCI
movel \len, PLX_DMA_1_LENGTH
movel #0x0301, PLX_DMA_CMD_STS
bsr memcpy_to_pci_run
.endm
#else
.macro memcpy src, dest, len
movel %d7, -(%sp)
movel \len, %d7
lsrl #2, \len
andl \len, \len
beq 99f
subl #1, \len
98: movel (\src)+, (\dest)+
dbfw \len, 98b
99: movel %d7, \len
btstl #1, \len
beq 99f
movew (\src)+, (\dest)+
99: btstl #0, \len
beq 99f
moveb (\src)+, (\dest)+
99:
movel (%sp)+, %d7
.endm
.macro memcpy_from_pci src, dest, len
addl #VALUE_WINDOW, \src
memcpy \src, \dest, \len
.endm
.macro memcpy_to_pci src, dest, len
addl #VALUE_WINDOW, \dest
memcpy \src, \dest, \len
.endm
#endif
.macro wait_for_command
99: btstl #0, CR
bne 99b
.endm
.text
.global _start
_start: bra init
.org _start + 4
ch_status_addr: .long 0, 0, 0, 0
rx_descs_addr: .long 0
init:
#if DETECT_RAM
movel OR1, %d0
andl #0xF00007FF, %d0
orl #0xFFFF800 & ~(MAX_RAM_SIZE - 1), %d0
movel %d0, OR1
#endif
addl #VALUE_WINDOW, rx_descs_addr
clrl %d0
init_1: tstl ch_status_addr(%d0)
beq init_2
addl #VALUE_WINDOW, ch_status_addr(%d0)
init_2: addl #4, %d0
cmpl #4 * 4, %d0
bne init_1
movel #pci9060_interrupt, PCI9060_VECTOR
movel #error_interrupt, ERROR_VECTOR
movel #port_interrupt_1, SCC1_VECTOR
movel #port_interrupt_2, SCC2_VECTOR
movel #port_interrupt_3, SCC3_VECTOR
movel #port_interrupt_4, SCC4_VECTOR
movel #timer_interrupt, TIMER_IRQ * 4
movel #0x78000000, CIMR
movew #(TIMER_IRQ_LEVEL << 8) + TIMER_IRQ, PICR
movew #PITR_CONST, PITR
movel #0xD41F40 + (CPM_IRQ_LEVEL << 13), CICR
movel #0x543, PLX_DMA_0_MODE
movel #0x543, PLX_DMA_1_MODE
movel #0x0, PLX_DMA_0_DESC
movel #0x8, PLX_DMA_1_DESC
movel #0x101, PLX_DMA_CMD_STS
orl #0x000F0300, PLX_INTERRUPT_CS
#if DETECT_RAM
bsr ram_test
#else
movel #1, PLX_MAILBOX_5
#endif
bsr check_csr
movew #0xFFFF, PAPAR
clrw PADIR
clrw PCSO
main: movel channel_stats, %d7
clrl channel_stats
tstl %d7
bne main_1
stop #0x2200
movew #0x2700, %sr
bra main
main_1: clrl %d0
clrl %d6
main_l: btstl #DOORBELL_TO_CARD_CLOSE_0, %d7
beq main_op
bclrl #DOORBELL_TO_CARD_OPEN_0, %d7
bsr close_port
main_op:
btstl #DOORBELL_TO_CARD_OPEN_0, %d7
beq main_cl
bsr open_port
main_cl:
btstl #DOORBELL_TO_CARD_TX_0, %d7
beq main_txend
bsr tx
main_txend:
btstl #TASK_SCC_0, %d7
beq main_next
bsr tx_end
bsr rx
main_next:
lsrl #1, %d7
addl #4, %d0
cmpl #4 * 4, %d0
bne main_l
movel %d6, PLX_DOORBELL_FROM_CARD
bra main
open_port:
movel ch_status_addr(%d0), %a0
tstl STATUS_OPEN(%a0)
bne open_port_ret
movel #1, STATUS_OPEN(%a0)
clrl tx_in(%d0)
clrl tx_out(%d0)
clrl tx_count(%d0)
clrl rx_in(%d0)
movel SICR, %d1
andl clocking_mask(%d0), %d1
cmpl #CLOCK_TXFROMRX, STATUS_CLOCKING(%a0)
bne open_port_clock_ext
orl clocking_txfromrx(%d0), %d1
bra open_port_set_clock
open_port_clock_ext:
orl clocking_ext(%d0), %d1
open_port_set_clock:
movel %d1, SICR
orw #STATUS_CABLE_DTR, csr_output(%d0)
bsr check_csr
movel first_buffer(%d0), %d1
movel tx_first_bd(%d0), %a1
movel #TX_BUFFERS - 2, %d2
movel #0x18000000, %d3
cmpl #PARITY_NONE, STATUS_PARITY(%a0)
beq open_port_tx_loop
bsetl #26, %d3
open_port_tx_loop:
movel %d3, (%a1)+
movel %d1, (%a1)+
addl #BUFFER_LENGTH, %d1
dbfw %d2, open_port_tx_loop
bsetl #29, %d3
movel %d3, (%a1)+
movel %d1, (%a1)+
movel #RX_BUFFERS - 2, %d2
open_port_rx_loop:
movel #0x90000000, (%a1)+
movel %d1, (%a1)+
addl #BUFFER_LENGTH, %d1
dbfw %d2, open_port_rx_loop
movel #0xB0000000, (%a1)+
movel %d1, (%a1)+
movel scc_base_addr(%d0), %a1
movel scc_reg_addr(%d0), %a2
movel #0xFFFF, SCC_SCCE(%a2)
movel #0x0000, SCC_SCCM(%a2)
movel tx_first_bd(%d0), %d1
movew %d1, SCC_TBASE(%a1)
addl #TX_BUFFERS * 8, %d1
movew %d1, SCC_RBASE(%a1)
moveb #0x8, SCC_RFCR(%a1)
moveb #0x8, SCC_TFCR(%a1)
cmpl #PARITY_CRC16_PR1_CCITT, STATUS_PARITY(%a0)
bne open_port_parity_1
clrw SCC_PSMR(%a2)
movel #0xF0B8, SCC_C_MASK(%a1)
movel #0xFFFF, SCC_C_PRES(%a1)
movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1)
movew #2, parity_bytes(%d0)
bra open_port_2
open_port_parity_1:
cmpl #PARITY_CRC32_PR1_CCITT, STATUS_PARITY(%a0)
bne open_port_parity_2
movew #0x0800, SCC_PSMR(%a2)
movel #0xDEBB20E3, SCC_C_MASK(%a1)
movel #0xFFFFFFFF, SCC_C_PRES(%a1)
movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1)
movew #4, parity_bytes(%d0)
bra open_port_2
open_port_parity_2:
cmpl #PARITY_CRC16_PR0_CCITT, STATUS_PARITY(%a0)
bne open_port_parity_3
clrw SCC_PSMR(%a2)
movel #0xF0B8, SCC_C_MASK(%a1)
clrl SCC_C_PRES(%a1)
movew #HDLC_MAX_MRU + 2, SCC_MFLR(%a1)
movew #2, parity_bytes(%d0)
bra open_port_2
open_port_parity_3:
cmpl #PARITY_CRC32_PR0_CCITT, STATUS_PARITY(%a0)
bne open_port_parity_4
movew #0x0800, SCC_PSMR(%a2)
movel #0xDEBB20E3, SCC_C_MASK(%a1)
clrl SCC_C_PRES(%a1)
movew #HDLC_MAX_MRU + 4, SCC_MFLR(%a1)
movew #4, parity_bytes(%d0)
bra open_port_2
open_port_parity_4:
clrw SCC_PSMR(%a2)
movel #0xF0B8, SCC_C_MASK(%a1)
movel #0xFFFF, SCC_C_PRES(%a1)
movew #HDLC_MAX_MRU, SCC_MFLR(%a1)
clrw parity_bytes(%d0)
open_port_2:
movel #0x00000003, SCC_GSMR_H(%a2)
cmpl #ENCODING_NRZI, STATUS_ENCODING(%a0)
bne open_port_nrz
movel #0x10040900, SCC_GSMR_L(%a2)
bra open_port_3
open_port_nrz:
movel #0x10040000, SCC_GSMR_L(%a2)
open_port_3:
movew #BUFFER_LENGTH, SCC_MRBLR(%a1)
movel %d0, %d1
lsll #4, %d1
orl #1, %d1
movew %d1, CR
wait_for_command
movew #0x001F, SCC_SCCM(%a2)
orl #0x00000030, SCC_GSMR_L(%a2)
open_port_ret:
rts
close_port:
movel scc_reg_addr(%d0), %a0
clrw SCC_SCCM(%a0)
andl #0xFFFFFFCF, SCC_GSMR_L(%a0)
andw #~STATUS_CABLE_DTR, csr_output(%d0)
bsr check_csr
movel ch_status_addr(%d0), %d1
clrl STATUS_OPEN(%d1)
rts
tx:
cmpl #TX_BUFFERS, tx_count(%d0)
beq tx_ret
movel tx_out(%d0), %d1
movel %d1, %d2
mulul #DESC_LENGTH, %d2
addl ch_status_addr(%d0), %d2
addl #STATUS_TX_DESCS, %d2
cmpl #PACKET_FULL, (%d2)
bne tx_ret
movel 4(%d2), %a0
lsll #3, %d1
addl tx_first_bd(%d0), %d1
movel 4(%d1), %a1
movel 8(%d2), %d2
movew %d2, 2(%d1)
memcpy_from_pci %a0, %a1, %d2
bsetl #31, (%d1)
movel tx_out(%d0), %d1
addl #1, %d1
cmpl #TX_BUFFERS, %d1
bne tx_1
clrl %d1
tx_1: movel %d1, tx_out(%d0)
addl #1, tx_count(%d0)
bra tx
tx_ret: rts
rx: movel rx_in(%d0), %d1
lsll #3, %d1
addl rx_first_bd(%d0), %d1
movew (%d1), %d2
btstl #15, %d2
bne rx_ret
btstl #1, %d2
bne rx_overrun
tstw parity_bytes(%d0)
bne rx_parity
bclrl #2, %d2
rx_parity:
andw #0x0CBC, %d2
cmpw #0x0C00, %d2
bne rx_bad_frame
clrl %d3
movew 2(%d1), %d3
subw parity_bytes(%d0), %d3
cmpw #HDLC_MAX_MRU, %d3
bgt rx_bad_frame
rx_good_frame:
movel rx_out, %d2
mulul #DESC_LENGTH, %d2
addl rx_descs_addr, %d2
cmpl #PACKET_EMPTY, (%d2)
bne rx_overrun
movel %d3, 8(%d2)
movel 4(%d1), %a0
movel 4(%d2), %a1
tstl %a1
beq rx_ignore_data
memcpy_to_pci %a0, %a1, %d3
rx_ignore_data:
movel packet_full(%d0), (%d2)
bsetl #DOORBELL_FROM_CARD_RX, %d6
movel rx_out, %d2
addl #1, %d2
cmpl #RX_QUEUE_LENGTH, %d2
bne rx_1
clrl %d2
rx_1: movel %d2, rx_out
rx_free_bd:
andw #0xF000, (%d1)
bsetl #31, (%d1)
movel rx_in(%d0), %d1
addl #1, %d1
cmpl #RX_BUFFERS, %d1
bne rx_2
clrl %d1
rx_2: movel %d1, rx_in(%d0)
bra rx
rx_overrun:
movel ch_status_addr(%d0), %d2
addl #1, STATUS_RX_OVERRUNS(%d2)
bra rx_free_bd
rx_bad_frame:
movel ch_status_addr(%d0), %d2
addl #1, STATUS_RX_FRAME_ERRORS(%d2)
bra rx_free_bd
rx_ret: rts
tx_end: tstl tx_count(%d0)
beq tx_end_ret
movel tx_in(%d0), %d1
movel %d1, %d2
lsll #3, %d1
addl tx_first_bd(%d0), %d1
movew (%d1), %d3
btstl #15, %d3
bne tx_end_ret
orl bell_tx(%d0), %d6
subl #1, tx_count(%d0)
movel tx_in(%d0), %d1
addl #1, %d1
cmpl #TX_BUFFERS, %d1
bne tx_end_1
clrl %d1
tx_end_1:
movel %d1, tx_in(%d0)
mulul #DESC_LENGTH, %d2
addl ch_status_addr(%d0), %d2
addl #STATUS_TX_DESCS, %d2
btstl #1, %d3
bne tx_end_underrun
movel #PACKET_SENT, (%d2)
bra tx_end
tx_end_underrun:
movel #PACKET_UNDERRUN, (%d2)
bra tx_end
tx_end_ret: rts
#if QUICC_MEMCPY_USES_PLX
memcpy_from_pci_run:
movel %d0, -(%sp)
movew %sr, -(%sp)
memcpy_1:
movel PLX_DMA_CMD_STS, %d0
btstl #4, %d0
bne memcpy_end
stop #0x2200
movew #0x2700, %sr
bra memcpy_1
memcpy_to_pci_run:
movel %d0, -(%sp)
movew %sr, -(%sp)
memcpy_2:
movel PLX_DMA_CMD_STS, %d0
btstl #12, %d0
bne memcpy_end
stop #0x2200
movew #0x2700, %sr
bra memcpy_2
memcpy_end:
movew (%sp)+, %sr
movel (%sp)+, %d0
rts
#endif
pci9060_interrupt:
movel %d0, -(%sp)
movel PLX_DOORBELL_TO_CARD, %d0
movel %d0, PLX_DOORBELL_TO_CARD
orl %d0, channel_stats
movel #0x0909, PLX_DMA_CMD_STS
movel (%sp)+, %d0
rte
port_interrupt_1:
orl #0, SCC1_REGS + SCC_SCCE;
orl #1 << TASK_SCC_0, channel_stats
movel #0x40000000, CISR
rte
port_interrupt_2:
orl #0, SCC2_REGS + SCC_SCCE;
orl #1 << TASK_SCC_1, channel_stats
movel #0x20000000, CISR
rte
port_interrupt_3:
orl #0, SCC3_REGS + SCC_SCCE;
orl #1 << TASK_SCC_2, channel_stats
movel #0x10000000, CISR
rte
port_interrupt_4:
orl #0, SCC4_REGS + SCC_SCCE;
orl #1 << TASK_SCC_3, channel_stats
movel #0x08000000, CISR
rte
error_interrupt:
rte
check_csr:
movel %d0, -(%sp)
movel %d1, -(%sp)
movel %d2, -(%sp)
movel %a0, -(%sp)
movel %a1, -(%sp)
clrl %d0
movel #CSRA, %a0
check_csr_loop:
movew (%a0), %d1
andl #0xE7, %d1
cmpw #STATUS_CABLE_V35 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
bne check_csr_1
movew #0x0E08, %d1
bra check_csr_valid
check_csr_1:
cmpw #STATUS_CABLE_X21 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
bne check_csr_2
movew #0x0408, %d1
bra check_csr_valid
check_csr_2:
cmpw #STATUS_CABLE_V24 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
bne check_csr_3
movew #0x0208, %d1
bra check_csr_valid
check_csr_3:
cmpw #STATUS_CABLE_EIA530 * (1 + 1 << STATUS_CABLE_PM_SHIFT), %d1
bne check_csr_disable
movew #0x0D08, %d1
bra check_csr_valid
check_csr_disable:
movew #0x0008, %d1
movew #0x80E7, %d2
bra check_csr_write
check_csr_valid:
movew csr_output(%d0), %d2
andw #0x3000, %d2
orw %d2, %d1
movew #0x80FF, %d2
check_csr_write:
cmpw old_csr_output(%d0), %d1
beq check_csr_input
movew %d1, old_csr_output(%d0)
movew %d1, (%a0)
check_csr_input:
movew (PCDAT), %d1
andw dcd_mask(%d0), %d1
beq check_csr_dcd_on
movew (%a0), %d1
andw #~STATUS_CABLE_DCD, %d1
bra check_csr_previous
check_csr_dcd_on:
movew (%a0), %d1
orw #STATUS_CABLE_DCD, %d1
check_csr_previous:
andw %d2, %d1
movel ch_status_addr(%d0), %a1
cmpl STATUS_CABLE(%a1), %d1
beq check_csr_next
movel %d1, STATUS_CABLE(%a1)
movel bell_cable(%d0), PLX_DOORBELL_FROM_CARD
check_csr_next:
addl #2, %a0
addl #4, %d0
cmpl #4 * 4, %d0
bne check_csr_loop
movel (%sp)+, %a1
movel (%sp)+, %a0
movel (%sp)+, %d2
movel (%sp)+, %d1
movel (%sp)+, %d0
rts
timer_interrupt:
bsr check_csr
rte
#if DETECT_RAM
ram_test:
movel #0x12345678, %d1
movel %d1, (128 * 1024 - 4)
movel #128 * 1024, %d0
ram_test_size:
cmpl #MAX_RAM_SIZE, %d0
beq ram_test_size_found
movel %d0, %a0
addl #128 * 1024 - 4, %a0
cmpl (%a0), %d1
beq ram_test_size_check
ram_test_next_size:
lsll #1, %d0
bra ram_test_size
ram_test_size_check:
eorl #0xFFFFFFFF, %d1
movel %d1, (128 * 1024 - 4)
cmpl (%a0), %d1
bne ram_test_next_size
ram_test_size_found:
movel %d0, %a0
subl #firmware_end + 4, %d0
lsrl #2, %d0
movel %d0, %d1
ram_test_fill:
movel %a0, -(%a0)
dbfw %d1, ram_test_fill
subl #0x10000, %d1
cmpl #0xFFFFFFFF, %d1
bne ram_test_fill
ram_test_loop:
cmpl (%a0)+, %a0
dbnew %d0, ram_test_loop
bne ram_test_found_bad
subl #0x10000, %d0
cmpl #0xFFFFFFFF, %d0
bne ram_test_loop
bra ram_test_all_ok
ram_test_found_bad:
subl #4, %a0
ram_test_all_ok:
movel %a0, PLX_MAILBOX_5
rts
#endif
scc_reg_addr:
.long SCC1_REGS, SCC2_REGS, SCC3_REGS, SCC4_REGS
scc_base_addr:
.long SCC1_BASE, SCC2_BASE, SCC3_BASE, SCC4_BASE
tx_first_bd:
.long DPRBASE
.long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8
.long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
.long DPRBASE + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
rx_first_bd:
.long DPRBASE + TX_BUFFERS * 8
.long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8
.long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 2
.long DPRBASE + TX_BUFFERS * 8 + (TX_BUFFERS + RX_BUFFERS) * 8 * 3
first_buffer:
.long BUFFERS_ADDR
.long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH
.long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 2
.long BUFFERS_ADDR + (TX_BUFFERS + RX_BUFFERS) * BUFFER_LENGTH * 3
bell_tx:
.long 1 << DOORBELL_FROM_CARD_TX_0, 1 << DOORBELL_FROM_CARD_TX_1
.long 1 << DOORBELL_FROM_CARD_TX_2, 1 << DOORBELL_FROM_CARD_TX_3
bell_cable:
.long 1 << DOORBELL_FROM_CARD_CABLE_0, 1 << DOORBELL_FROM_CARD_CABLE_1
.long 1 << DOORBELL_FROM_CARD_CABLE_2, 1 << DOORBELL_FROM_CARD_CABLE_3
packet_full:
.long PACKET_FULL, PACKET_FULL + 1, PACKET_FULL + 2, PACKET_FULL + 3
clocking_ext:
.long 0x0000002C, 0x00003E00, 0x002C0000, 0x3E000000
clocking_txfromrx:
.long 0x0000002D, 0x00003F00, 0x002D0000, 0x3F000000
clocking_mask:
.long 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
dcd_mask:
.word 0x020, 0, 0x080, 0, 0x200, 0, 0x800
.ascii "wanXL firmware\n"
.asciz "Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl>\n"
.align 4
channel_stats: .long 0
tx_in: .long 0, 0, 0, 0
tx_out: .long 0, 0, 0, 0
tx_count: .long 0, 0, 0, 0
rx_in: .long 0, 0, 0, 0
rx_out: .long 0
parity_bytes: .word 0, 0, 0, 0, 0, 0, 0
csr_output: .word 0
old_csr_output: .word 0, 0, 0, 0, 0, 0, 0
.align 4
firmware_end: