summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-02-18 16:46:36 +0100
committerHarald Welte <laforge@gnumonks.org>2010-02-18 16:46:36 +0100
commitfbe7b94c9c65f2df74acd5dff7503c9833ec2579 (patch)
tree5f47a597f2f396662719c5a76ac6bf26eda69f6c
Initial import of OsmocomBB into git repository
-rw-r--r--doc/calypso-block.svg707
-rw-r--r--doc/calypso-gsm-notes.txt2
-rw-r--r--doc/calypso-signals.txt184
-rw-r--r--doc/gsmdevboard-block.svg746
-rw-r--r--include/l1a_l23_interface.h134
-rwxr-xr-xsrc/host/calypso_pll/pll.pl10
-rw-r--r--src/host/layer2/.gitignore14
-rw-r--r--src/host/layer2/Makefile.am3
-rw-r--r--src/host/layer2/configure.ac24
-rw-r--r--src/host/layer2/include/Makefile.am2
l---------src/host/layer2/include/l1a_l23_interface.h1
-rw-r--r--src/host/layer2/include/osmocom/Makefile.am4
l---------src/host/layer2/include/osmocom/debug.h1
l---------src/host/layer2/include/osmocom/gsm_04_08.h1
l---------src/host/layer2/include/osmocom/linuxlist.h1
l---------src/host/layer2/include/osmocom/meas_rep.h1
l---------src/host/layer2/include/osmocom/msgb.h1
-rw-r--r--src/host/layer2/include/osmocom/osmocom_data.h22
-rw-r--r--src/host/layer2/include/osmocom/osmocom_layer2.h12
l---------src/host/layer2/include/osmocom/select.h1
l---------src/host/layer2/include/osmocom/talloc.h1
l---------src/host/layer2/include/osmocom/timer.h1
-rw-r--r--src/host/layer2/src/Makefile.am10
-rw-r--r--src/host/layer2/src/layer2_main.c205
l---------src/host/layer2/src/libosmocom/debug.c1
l---------src/host/layer2/src/libosmocom/msgb.c1
l---------src/host/layer2/src/libosmocom/select.c1
l---------src/host/layer2/src/libosmocom/signal.c1
l---------src/host/layer2/src/libosmocom/talloc.c1
l---------src/host/layer2/src/libosmocom/timer.c1
-rw-r--r--src/host/layer2/src/osmocom_layer2.c226
-rw-r--r--src/host/libosmocom/README1
-rw-r--r--src/host/libosmocom/include/osmocom/debug.h131
-rw-r--r--src/host/libosmocom/include/osmocom/gsm_04_08.h796
-rw-r--r--src/host/libosmocom/include/osmocom/gsmtap.h60
-rw-r--r--src/host/libosmocom/include/osmocom/linuxlist.h360
-rw-r--r--src/host/libosmocom/include/osmocom/meas_rep.h85
-rw-r--r--src/host/libosmocom/include/osmocom/msgb.h114
-rw-r--r--src/host/libosmocom/include/osmocom/select.h22
-rw-r--r--src/host/libosmocom/include/osmocom/talloc.h192
-rw-r--r--src/host/libosmocom/include/osmocom/timer.h72
-rw-r--r--src/host/libosmocom/src/debug.c463
-rw-r--r--src/host/libosmocom/src/msgb.c97
-rw-r--r--src/host/libosmocom/src/select.c124
-rw-r--r--src/host/libosmocom/src/signal.c83
-rw-r--r--src/host/libosmocom/src/talloc.c1805
-rw-r--r--src/host/libosmocom/src/timer.c185
-rw-r--r--src/host/osmocon/.gitignore9
-rw-r--r--src/host/osmocon/Makefile19
-rwxr-xr-xsrc/host/osmocon/memdump_convert.pl29
-rw-r--r--src/host/osmocon/osmocon.c660
-rwxr-xr-xsrc/host/rita_pll/rita_pll.pl111
-rw-r--r--src/host/rita_pll/rita_pll.txt3625
-rw-r--r--src/host/rita_pll/rita_pll_notes.txt8
-rw-r--r--src/target/firmware/.gitignore7
-rw-r--r--src/target/firmware/Makefile69
-rw-r--r--src/target/firmware/Makefile.inc19
-rw-r--r--src/target/firmware/abb/twl3025.c291
-rw-r--r--src/target/firmware/apps/compal_dsp_dump/main.c78
-rw-r--r--src/target/firmware/apps/compal_dump/main.c90
-rw-r--r--src/target/firmware/apps/hello_world/main.c126
-rw-r--r--src/target/firmware/apps/l1test/main.c289
-rw-r--r--src/target/firmware/apps/layer1/main.c214
-rw-r--r--src/target/firmware/board/common/compal_ramload.lds83
-rw-r--r--src/target/firmware/board/common/compal_ramload_start.S257
-rw-r--r--src/target/firmware/board/common/rffe_compal_dualband.c70
-rw-r--r--src/target/firmware/board/compal_e88/init.c126
-rw-r--r--src/target/firmware/calypso/Makefile17
-rw-r--r--src/target/firmware/calypso/arm.c26
-rw-r--r--src/target/firmware/calypso/backlight.c67
-rw-r--r--src/target/firmware/calypso/clock.c202
-rw-r--r--src/target/firmware/calypso/dma.c44
-rw-r--r--src/target/firmware/calypso/dsp.c391
-rw-r--r--src/target/firmware/calypso/dsp_bootcode.c9
-rw-r--r--src/target/firmware/calypso/dsp_dumpcode.c45
-rw-r--r--src/target/firmware/calypso/dsp_params.c94
-rw-r--r--src/target/firmware/calypso/du.c51
-rw-r--r--src/target/firmware/calypso/i2c.c123
-rw-r--r--src/target/firmware/calypso/irq.c266
-rw-r--r--src/target/firmware/calypso/keypad.c165
-rw-r--r--src/target/firmware/calypso/misc.c60
-rw-r--r--src/target/firmware/calypso/rtc.c82
-rw-r--r--src/target/firmware/calypso/spi.c141
-rw-r--r--src/target/firmware/calypso/timer.c127
-rw-r--r--src/target/firmware/calypso/tpu.c288
-rw-r--r--src/target/firmware/calypso/tsp.c121
-rw-r--r--src/target/firmware/calypso/uart.c396
-rw-r--r--src/target/firmware/comm/Makefile26
-rw-r--r--src/target/firmware/comm/msgb.c134
-rw-r--r--src/target/firmware/comm/sercomm.c244
-rw-r--r--src/target/firmware/comm/sercomm_cons.c126
-rw-r--r--src/target/firmware/display/font_r8x8.cbin0 -> 50349 bytes
-rw-r--r--src/target/firmware/display/st7558.c122
-rw-r--r--src/target/firmware/flash/cfi_flash.c435
-rw-r--r--src/target/firmware/include/abb/twl3025.h128
-rw-r--r--src/target/firmware/include/arm.h7
-rw-r--r--src/target/firmware/include/asm/assembler.h97
-rw-r--r--src/target/firmware/include/asm/atomic.h106
-rw-r--r--src/target/firmware/include/asm/bitops.h225
-rw-r--r--src/target/firmware/include/asm/ctype.h54
-rw-r--r--src/target/firmware/include/asm/div64.h48
-rw-r--r--src/target/firmware/include/asm/linkage.h18
-rw-r--r--src/target/firmware/include/asm/ptrace.h128
-rw-r--r--src/target/firmware/include/asm/system.h109
-rw-r--r--src/target/firmware/include/board.h6
-rw-r--r--src/target/firmware/include/calypso/backlight.h10
-rw-r--r--src/target/firmware/include/calypso/clock.h67
-rw-r--r--src/target/firmware/include/calypso/dma.h6
-rw-r--r--src/target/firmware/include/calypso/dsp.h31
-rw-r--r--src/target/firmware/include/calypso/dsp_api.h1554
-rw-r--r--src/target/firmware/include/calypso/du.h32
-rw-r--r--src/target/firmware/include/calypso/irq.h49
-rw-r--r--src/target/firmware/include/calypso/l1_environment.h365
-rw-r--r--src/target/firmware/include/calypso/misc.h7
-rw-r--r--src/target/firmware/include/calypso/rtc.h6
-rw-r--r--src/target/firmware/include/calypso/timer.h22
-rw-r--r--src/target/firmware/include/calypso/tpu.h117
-rw-r--r--src/target/firmware/include/calypso/tsp.h30
-rw-r--r--src/target/firmware/include/calypso/uart.h30
-rw-r--r--src/target/firmware/include/cfi_flash.h68
-rw-r--r--src/target/firmware/include/comm/msgb.h104
-rw-r--r--src/target/firmware/include/comm/sercomm.h57
-rw-r--r--src/target/firmware/include/comm/sercomm_cons.h10
-rw-r--r--src/target/firmware/include/console.h20
-rw-r--r--src/target/firmware/include/debug.h31
-rw-r--r--src/target/firmware/include/delay.h7
-rw-r--r--src/target/firmware/include/display/st7558.h15
-rw-r--r--src/target/firmware/include/gsm.h29
-rw-r--r--src/target/firmware/include/i2c.h7
-rw-r--r--src/target/firmware/include/keypad.h66
-rw-r--r--src/target/firmware/include/layer1/afc.h13
-rw-r--r--src/target/firmware/include/layer1/agc.h6
-rw-r--r--src/target/firmware/include/layer1/avg.h23
-rw-r--r--src/target/firmware/include/layer1/l23_api.h11
-rw-r--r--src/target/firmware/include/layer1/sync.h75
-rw-r--r--src/target/firmware/include/layer1/tdma_sched.h52
-rw-r--r--src/target/firmware/include/layer1/tpu_window.h17
-rw-r--r--src/target/firmware/include/linuxlist.h360
-rw-r--r--src/target/firmware/include/memory.h28
-rw-r--r--src/target/firmware/include/rf/trf6151.h35
-rw-r--r--src/target/firmware/include/rffe.h15
-rw-r--r--src/target/firmware/include/spi.h7
-rw-r--r--src/target/firmware/include/stdio.h47
-rw-r--r--src/target/firmware/include/string.h12
-rw-r--r--src/target/firmware/layer1/Makefile18
-rw-r--r--src/target/firmware/layer1/afc.c122
-rw-r--r--src/target/firmware/layer1/agc.c67
-rw-r--r--src/target/firmware/layer1/avg.c57
-rw-r--r--src/target/firmware/layer1/gsm.c117
-rw-r--r--src/target/firmware/layer1/init.c70
-rw-r--r--src/target/firmware/layer1/l23_api.c63
-rw-r--r--src/target/firmware/layer1/sync.c911
-rw-r--r--src/target/firmware/layer1/tdma_sched.c163
-rw-r--r--src/target/firmware/layer1/tpu_window.c94
-rw-r--r--src/target/firmware/lib/Makefile26
-rw-r--r--src/target/firmware/lib/bitops.h33
-rw-r--r--src/target/firmware/lib/changebit.S21
-rw-r--r--src/target/firmware/lib/clearbit.S22
-rw-r--r--src/target/firmware/lib/console.c202
-rw-r--r--src/target/firmware/lib/copy_template.S255
-rw-r--r--src/target/firmware/lib/ctype.c34
-rw-r--r--src/target/firmware/lib/div64.S200
-rw-r--r--src/target/firmware/lib/lib1funcs.S334
-rw-r--r--src/target/firmware/lib/memcpy.S59
-rw-r--r--src/target/firmware/lib/memset.S80
-rw-r--r--src/target/firmware/lib/printf.c19
-rw-r--r--src/target/firmware/lib/setbit.S22
-rw-r--r--src/target/firmware/lib/string.c50
-rw-r--r--src/target/firmware/lib/testchangebit.S18
-rw-r--r--src/target/firmware/lib/testclearbit.S18
-rw-r--r--src/target/firmware/lib/testsetbit.S18
-rw-r--r--src/target/firmware/lib/vsprintf.c847
-rw-r--r--src/target/firmware/rf/trf6151.c380
-rw-r--r--src/target_dsp/.gitignore4
-rw-r--r--src/target_dsp/calypso/Makefile7
-rwxr-xr-xsrc/target_dsp/calypso/bin2cfile.py50
-rw-r--r--src/target_dsp/calypso/bl_stage3.S142
-rw-r--r--src/target_dsp/calypso/dsp_dump.lds22
178 files changed, 25804 insertions, 0 deletions
diff --git a/doc/calypso-block.svg b/doc/calypso-block.svg
new file mode 100644
index 00000000..6f872676
--- /dev/null
+++ b/doc/calypso-block.svg
@@ -0,0 +1,707 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="297mm"
+ height="210mm"
+ id="svg2383"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="calypso-block.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/home/laforge/calypso-block.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs2385">
+ <marker
+ inkscape:stockid="CurveIn"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="CurveIn"
+ style="overflow:visible">
+ <path
+ id="path3349"
+ d="M 4.6254930,-5.0456926 C 1.8654930,-5.0456926 -0.37450702,-2.8056926 -0.37450702,-0.045692580 C -0.37450702,2.7143074 1.8654930,4.9543074 4.6254930,4.9543074"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none;fill:none"
+ transform="scale(0.6)" />
+ </marker>
+ <marker
+ inkscape:stockid="DotM"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="DotM"
+ style="overflow:visible">
+ <path
+ id="path3229"
+ d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none"
+ transform="scale(0.4) translate(7.4, 1)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mstart"
+ style="overflow:visible">
+ <path
+ id="path7719"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ id="path3191"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Send"
+ style="overflow:visible;">
+ <path
+ id="path3179"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.2) rotate(180) translate(6,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mend"
+ style="overflow:visible;">
+ <path
+ id="path3173"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.4) rotate(180) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutL"
+ style="overflow:visible">
+ <path
+ id="path3307"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path3185"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lend"
+ style="overflow:visible;">
+ <path
+ id="path3188"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.8) rotate(180) translate(12.5,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 372.04724 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="1052.3622 : 372.04724 : 1"
+ inkscape:persp3d-origin="526.18109 : 248.03149 : 1"
+ id="perspective2392" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:document-units="mm"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.96166971"
+ inkscape:cx="576.3753"
+ inkscape:cy="495.79724"
+ inkscape:current-layer="layer1"
+ id="namedview2387"
+ showgrid="true"
+ inkscape:snap-global="true"
+ inkscape:window-width="1022"
+ inkscape:window-height="731"
+ inkscape:window-x="1024"
+ inkscape:window-y="0"
+ inkscape:snap-guide="true"
+ inkscape:object-paths="false"
+ inkscape:object-nodes="false"
+ objecttolerance="3"
+ gridtolerance="10000">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2400"
+ visible="true"
+ enabled="true"
+ units="mm"
+ spacingx="5mm"
+ spacingy="5mm"
+ empspacing="2" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata2389">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#CurveIn);stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 992.12598,230.31495 L 1045.2756,230.31495 L 1045.2756,159.44881 L 1045.2756,159.44881"
+ id="path22123" />
+ <g
+ id="g12239">
+ <rect
+ y="35.433064"
+ x="70.866142"
+ height="265.74802"
+ width="177.16536"
+ id="rect7161"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.77165353000000003;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text7163"
+ y="53.149601"
+ x="72.866142"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="53.149601"
+ x="72.866142"
+ id="tspan7165"
+ sodipodi:role="line">CALYPSO</tspan></text>
+ </g>
+ <g
+ id="g20347">
+ <rect
+ y="70.77356"
+ x="389.63159"
+ height="230.24446"
+ width="106.56361"
+ id="rect2406"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.50725651;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ transform="scale(1.0221827,0.9782987)"
+ sodipodi:linespacing="100%"
+ id="text7157"
+ y="92.63372"
+ x="381.30542"
+ style="font-size:21.45465279px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="92.63372"
+ x="381.30542"
+ id="tspan7159"
+ sodipodi:role="line">TWL3025</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12244"
+ y="216.1601"
+ x="394.66666"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="216.1601"
+ x="394.66666"
+ id="tspan12246"
+ sodipodi:role="line">BSP</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12248"
+ y="252.99342"
+ x="395.16666"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="252.99342"
+ x="395.16666"
+ id="tspan12250"
+ sodipodi:role="line">USP</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12252"
+ y="286.42783"
+ x="396.16666"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="286.42783"
+ x="396.16666"
+ id="tspan12254"
+ sodipodi:role="line">TSP</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text20330"
+ y="163.44881"
+ x="464.62991"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="163.44881"
+ x="464.62991"
+ id="tspan20332"
+ sodipodi:role="line">BUL</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text20334"
+ y="146.96971"
+ x="463.70053"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="146.96971"
+ x="463.70053"
+ id="tspan20336"
+ sodipodi:role="line">BDL</tspan></text>
+ </g>
+ <g
+ id="g13450">
+ <rect
+ y="177.16687"
+ x="885.82831"
+ height="88.888702"
+ width="106.29617"
+ id="rect12310"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.77468574;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text13440"
+ y="230.31496"
+ x="903.54333"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="230.31496"
+ x="903.54333"
+ id="tspan13442"
+ sodipodi:role="line">Antenna</tspan><tspan
+ id="tspan13444"
+ y="242.31496"
+ x="903.54333"
+ sodipodi:role="line">Switch</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text13446"
+ y="194.88188"
+ x="887.82678"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="194.88188"
+ x="887.82678"
+ id="tspan13448"
+ sodipodi:role="line">ASM4532</tspan></text>
+ </g>
+ <rect
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.61511528;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect11596"
+ width="142.16623"
+ height="88.074844"
+ x="885.74847"
+ y="35.354794" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#550000;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+ d="M 496.06299,283.46456 L 850.3937,283.46456 L 850.3937,106.29921 L 885.82677,106.29921"
+ id="path21554" />
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.54330707;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 248.0315,212.59842 L 389.76378,212.59842 L 389.76378,212.59842"
+ id="path7167" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:3.54330708999999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+ d="M 248.0315,283.46456 L 389.76378,283.46456"
+ id="path7171" />
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.54330707;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 248.03149,248.03149 L 389.76378,248.03149 L 389.76378,248.03149"
+ id="path9925" />
+ <g
+ id="g12217">
+ <rect
+ y="35.433064"
+ x="637.79529"
+ height="212.59842"
+ width="141.73228"
+ id="rect2408"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.77165354;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text7153"
+ y="53.149601"
+ x="637.79529"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan11602"
+ y="78.149597"
+ x="637.79529"
+ sodipodi:role="line">TRF6151</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12175"
+ y="88.582672"
+ x="655.51184"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="88.582672"
+ x="655.51184"
+ id="tspan12177"
+ sodipodi:role="line">Transceiver</tspan><tspan
+ id="tspan12179"
+ y="104.58267"
+ x="655.51184"
+ sodipodi:role="line">Mixers</tspan><tspan
+ id="tspan12183"
+ y="120.58267"
+ x="655.51184"
+ sodipodi:role="line">VCO</tspan><tspan
+ id="tspan12181"
+ y="136.58267"
+ x="655.51184"
+ sodipodi:role="line">PLL</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="885.82678"
+ y="53.149601"
+ id="text11598"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan11600"
+ x="885.82678"
+ y="53.149601">RF3166</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="903.54333"
+ y="88.582672"
+ id="text12185"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ x="903.54333"
+ y="88.582672"
+ id="tspan12193">RF PA</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="218.59842"
+ y="287.46457"
+ id="text12256"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan12258"
+ x="218.59842"
+ y="287.46457">TSP</tspan></text>
+ <g
+ id="g12268">
+ <path
+ id="path11606"
+ d="M 779.52756,53.149601 L 885.82677,53.149601 L 885.82677,53.149601"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12260"
+ y="51.149601"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="51.149601"
+ x="814.96063"
+ id="tspan12262"
+ sodipodi:role="line">GSM</tspan></text>
+ </g>
+ <g
+ id="g12273">
+ <path
+ id="path12195"
+ d="M 779.52756,70.866136 L 885.82677,70.866136 L 885.82677,70.866136"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12264"
+ y="68.866135"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="68.866135"
+ x="814.96063"
+ id="tspan12266"
+ sodipodi:role="line">DCS/PCS</tspan></text>
+ </g>
+ <g
+ id="g12290">
+ <path
+ id="path12197"
+ d="M 885.82677,194.88188 L 779.52756,194.88188 L 779.52756,194.88188"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12278"
+ y="192.88188"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="192.88188"
+ x="814.96063"
+ id="tspan12280"
+ sodipodi:role="line">GSM</tspan></text>
+ </g>
+ <g
+ id="g12295">
+ <path
+ id="path12165"
+ d="M 885.82677,212.59841 L 779.52756,212.59841 L 779.52756,212.59841"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12282"
+ y="210.59842"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="210.59842"
+ x="814.96063"
+ id="tspan12284"
+ sodipodi:role="line">DCS</tspan></text>
+ </g>
+ <g
+ id="g12300">
+ <path
+ id="path12199"
+ d="M 885.82677,230.31495 L 779.52756,230.31495 L 779.52756,230.31495"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12286"
+ y="228.31496"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="228.31496"
+ x="814.96063"
+ id="tspan12288"
+ sodipodi:role="line">PCS</tspan></text>
+ </g>
+ <g
+ id="g18005">
+ <text
+ sodipodi:linespacing="100%"
+ id="text14594"
+ y="49.149601"
+ x="425.21259"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan14598"
+ y="49.149601"
+ x="425.21259"
+ sodipodi:role="line">RFCLK</tspan></text>
+ <path
+ id="path14605"
+ d="M 637.79528,53.149601 L 248.0315,53.149601 L 248.0315,53.149601"
+ style="fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)" />
+ </g>
+ <g
+ id="g18583">
+ <path
+ inkscape:label="#path2410"
+ id="path241011111"
+ d="M 496.06299,141.73228 L 637.79528,141.73228 L 637.79528,141.73228 L 637.79528,141.73228"
+ style="fill:#00ff00;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12167"
+ y="137.73228"
+ x="539.21259"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="137.73228"
+ x="539.21259"
+ id="tspan12169"
+ sodipodi:role="line">I/Q Analog</tspan></text>
+ <path
+ id="path15170"
+ d="M 531.49606,141.73228 L 531.49606,159.44881 L 496.06299,159.44881 L 496.06299,159.44881"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <g
+ id="g18000">
+ <path
+ id="path17431"
+ d="M 248.0315,88.582671 L 389.76378,88.582671"
+ style="fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text17996"
+ y="84.582672"
+ x="295.18109"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="84.582672"
+ x="295.18109"
+ id="tspan17998"
+ sodipodi:role="line">CLK13M</tspan></text>
+ </g>
+ <g
+ id="g18593">
+ <path
+ id="path18010"
+ d="M 496.06299,194.88188 L 637.79528,194.88188"
+ style="fill:none;fill-rule:evenodd;stroke:#550000;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text18589"
+ y="188.88188"
+ x="537.49603"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="188.88188"
+ x="537.49603"
+ id="tspan18591"
+ sodipodi:role="line">AFC Analog</tspan></text>
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+ d="M 212.59843,301.1811 L 212.59843,372.04724 L 921.25984,372.04724 L 921.25984,265.74803"
+ id="path19726" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="354.33072"
+ y="368.04724"
+ id="text20291"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan20293"
+ x="354.33072"
+ y="368.04724">TSP Parallel</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="356.33072"
+ y="330.89764"
+ id="text20295"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan20297"
+ x="356.33072"
+ y="330.89764">TSP Serial</tspan></text>
+ <g
+ id="g20314"
+ transform="translate(-4.7244095e-7,-17.716533)">
+ <path
+ id="path20301"
+ d="M 248.0315,124.01574 L 389.76378,124.01574"
+ style="fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text20303"
+ y="120.01574"
+ x="295.18109"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan20310"
+ y="120.01574"
+ x="295.18109"
+ sodipodi:role="line">CLK32K</tspan></text>
+ </g>
+ <g
+ id="g20421">
+ <path
+ id="path12871"
+ d="M 956.69291,124.01574 L 956.69291,177.16535"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ transform="matrix(0,-1,1,0,0,0)"
+ sodipodi:linespacing="100%"
+ id="text20402"
+ y="952.69293"
+ x="-159.44881"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="952.69293"
+ x="-159.44881"
+ id="tspan20404"
+ sodipodi:role="line">GSM</tspan></text>
+ </g>
+ <g
+ id="g20415">
+ <g
+ id="g20410">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 921.25984,124.01574 L 921.25984,177.16535"
+ id="path12312" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.36807537px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="-184.69075"
+ y="867.06183"
+ id="text20406"
+ sodipodi:linespacing="100%"
+ transform="matrix(0,-0.9473396,1.0555877,0,0,0)"><tspan
+ sodipodi:role="line"
+ id="tspan20408"
+ x="-184.69075"
+ y="867.06183">DCS/PCS</tspan></text>
+ </g>
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-start:url(#DotM);marker-end:url(#Arrow2Mend)"
+ d="M 921.25984,372.04724 L 1009.8425,372.04724 L 1009.8425,124.01574 L 1009.8425,124.01574"
+ id="path20426" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="539.21259"
+ y="279.46457"
+ id="text22119"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan22121"
+ x="539.21259"
+ y="279.46457">APC Analog</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 318.89764,283.46456 L 318.89764,336.61417 L 673.22835,336.61417 L 673.22835,248.03149"
+ id="path18598" />
+ </g>
+</svg>
diff --git a/doc/calypso-gsm-notes.txt b/doc/calypso-gsm-notes.txt
new file mode 100644
index 00000000..4377ceb4
--- /dev/null
+++ b/doc/calypso-gsm-notes.txt
@@ -0,0 +1,2 @@
+GSM burst duration: 577uS
+RITA synthesizer retuning max: 170uS
diff --git a/doc/calypso-signals.txt b/doc/calypso-signals.txt
new file mode 100644
index 00000000..be49cf03
--- /dev/null
+++ b/doc/calypso-signals.txt
@@ -0,0 +1,184 @@
+CALYPSO PAD AND NAME I/O CONNECTS TO TO BFIN?
+========================================================================================================
+C12 CLK32K_OUT O TWL3025:CLK32K (32kHz clock input) M
+F12 CLK13M_OUT_START_BIT O TWL3025:CLK13M (master clock input) M
+D12 nRESPWON I TWL3025:RESPWONz (dbb power-on reset @ batt insert) O
+P1 EXT-FIQ I TWL3025:INT1 O
+M3 EXT-IRQ I TWL3025:INT2 M
+A12 TCXOEN O TRF6151:XSEL,XEN (enable 26MHz oscillator) M
+F10 ON_OFF I TWL3025:ON_nOFF (dbb reset @ each switch on) O
+B14 IT_WAKEUP O TWL3025:ITWAKEUP (real-time wake-up irq) O
+B11 NEMU0 NC
+E10 NEMU1 NC
+D11 NBSCAN NC
+D10 TDI I
+C10 TDO O
+B10 TCK I
+E9 TMS I
+L11 BFSR I TWL3025:BFSX (bb-serial tx frame sync) M
+K10 BDR I TWL3025:BDX (bb-serial tx data) M
+P12 BFSX O TWL3025:BFSR (bb-serial rx frame sync) M
+M11 BDX O TWL3025:BDR (bb-serial rx data) M
+N11 BCLKX-IO6 NC
+P11 BCLKR-ARMCLK GND
+P14 VDX O TWL3025:VDR (vb-serial rx data)
+N13 VDR I TWL3025:VDX (vb-serial tx data)
+M13 VFSRX I TWL3025:VFS (vb-serial frame sync)
+N12 VCLKRX I TWL3025:VCK (vb-serial clock)
+N7 MCUDI I TWL3025:UDX (spi output) M
+M7 MCUDO O TWL3025:UDR (spi input) M
+M8 MCUEN0 O TWL3025:UEN (spi enable) M
+P8 MCUEN1-IO9 NC
+L8 MCUEN2-IO13 NC
+G13 SIM_IO IO TWL3025:DBBSIO (sim card shifter data) L
+F13 SIM_CLK O TWL3025:DBBSCK (sim card shifter clock) L
+G10 SIM_RST O TWL3025:DBBSRST (sim card shifter reset inp) L
+G11 SIM_CD-MAS0 V_IO
+F14 SIM_PWRCTRL-IO5 O TWL3025:DBBSIO (via 10k) L
+B13 OSC32K_OUT O XTAL
+C13 OSC32K_IN I XTAL
+A14 VSSO GND
+E13 CLKTCXO I TRF6151C:RFCLK (TCXO clock output) M
+M2 IDDQ GND
+N1 NI BOOT GND (via 100k)
+N2 nRESET_OUT O NC
+M4 IO3-SIM_RNW NC
+L4 IO2-IRQ4 NC
+P3 IO1-TPU_IDLE O S3C2410
+N3 IO0-TPU_WAIT NC
+L7 LT-PWL NC
+K7 BU-PWT NC
+L6 KBR4-XDIO7 NC
+N6 KBR3-XDIO6 NC
+P6 KBR2-XDIO5 NC
+M6 KBR1-XDIO4 NC
+K6 KBR0-XDIO3 NC
+M5 KBC4-XDIO2 NC
+P5 KBC3-XDIO1 NC
+L5 KBC2-XDIO0 NC
+K5 KBC1-nIRQ NC
+N4 KBC0-nFIQ NC
+K9 MCSI_FSYNCH-IO12 NC
+N10 MCSI_CLI-IO11 NC
+M10 MCSI_RXD-IO10 NC
+L10 MCSI_TXD-IO9 NC
+C9 CTS_MODEM-X_F S3C24xx
+D9 DSR_MODEM-LPG S3c24xx
+E8 RTS_MODEM-TOUT S3c24xx
+A9 RX_MODEM I S3c24xx
+B9 TX_MODEM O S3c24xx
+B8 SD_IRDA-CLKOUT_DSP NC
+A8 RXIR_IRDA-X_A1 NC
+C7 TXIR_IRDA-X_A4 NC
+D8 RX_IRDA I socket
+C8 TX_IRDA O socket
+N9 NSCS(1)-X_A32 NC
+L9 NSCS0-SCL NC
+M9 SDI-SDA I V-IO
+K8 SDO-nINT10 I NC
+P9 SCLK-nINT1 I INT0
+I14 TSPCLKX O TRF6151:CLK (serial clock) M
+H11 TSPDO O TWL3025:TDR,TRF6151:DATA (serial data) M
+H10 DSPDI-IO4 I NC
+H13 TSPEN0 O TWL3025:TEN (TSP enable) M
+H12 TSPEN1 NC
+H14 TSPEN2 TRF6151:STROBE (serial strobe) M
+G12 TSPEN3-nSCS2 NC
+M12 TSPACT0 O TRF6151:RESETz (serial interface reset) M
+M14 TSPACT1 O ASM4532:VC2 M
+L12 TSPACT2 O ASM4532:VC1 M
+L13 TSPACT3 O RF3166:BAND_SELECT M
+I10 TSPACT4-nRDYMEM O ASM4532:VC3 M
+K11 TSPACT5-DPLLCLK NC
+K13 TSPACT6-nCS6 NC
+K12 TSPACT7-CLKX_SPI NC
+K14 TSPACT8-nMREQ NC
+I11 TSPACT9-MAS1 RF3166:TX_ENABLE (PA TX) M
+I12 TSPACT10-nWAIT NC
+I13 TSPACT11-MCLK NC
+B7 DATA0 RAM/FLASH
+D7 DATA1 RAM/FLASH
+E7 DATA2 RAM/FLASH
+D6 DATA3 RAM/FLASH
+A6 DATA4 RAM/FLASH
+C6 DATA5 RAM/FLASH
+E6 DATA6 RAM/FLASH
+C6 DATA7 RAM/FLASH
+B5 DATA8 RAM/FLASH
+D5 DATA9 RAM/FLASH
+E5 DATA10 RAM/FLASH
+B4 DATA11 RAM/FLASH
+C4 DATA12 RAM/FLASH
+D4 DATA13 RAM/FLASH
+A3 DATA14 RAM/FLASH
+B3 DATA15 RAM/FLASH
+F3 ADD0 RAM/FLASH
+F2 ADD1 RAM/FLASH
+G5 ADD2 RAM/FLASH
+G4 ADD3 RAM/FLASH
+G2 ADD4 RAM/FLASH
+G3 ADD5 RAM/FLASH
+H1 ADD6 RAM/FLASH
+H3 ADD7 RAM/FLASH
+H2 ADD8 RAM/FLASH
+H4 ADD9 RAM/FLASH
+H5 ADD10 RAM/FLASH
+I1 ADD11 RAM/FLASH
+I2 ADD12 RAM/FLASH
+I3 ADD13 RAM/FLASH
+K3 ADD15 RAM/FLASH
+K2 ADD16 RAM/FLASH
+K4 ADD17 RAM/FLASH
+I5 ADD18 RAM/FLASH
+L1 ADD19 RAM/FLASH
+L2 ADD20 RAM/FLASH
+L3 ADD21-CLK16X_IRDA RAM/FLASH
+B2 RNW RAM/FLASH
+E3 nFEW-X_A0 NC
+E2 nFOE-X_A3 RAM/FLASH
+F4 FDP-nIACK RAM/FLASH
+E4 nBLE-IO15 RAM/FLASH
+F5 nBHE-IO14 RAM/FLASH
+C2 nCS0
+C3 nCS1 RAM/FLASH
+C1 nCS2 NC
+D3 nCS3-nINT4 NC
+D2 CS4-ADD22 RAM/FLASH
+C11 nCS4-CO35 RAM/FLASH
+A4 VDDS-MF1 V-FLASH
+B6 VDDS-MF2 V-FLASH
+G1 VDDS-MF3 V-FLASH
+D1 VDDS-MF4 V-FLASH
+A11 VDDS_2 V-IO
+L14 VDDS_1 V-IO
+N5 VDDS_1 V-IO
+A5 VDD1 V-DBB
+B12 VDD2 V-DBB
+N14 VDD3 V-DBB
+P7 VDD4 V-DBB
+M1 VDD5 V-DBB
+E1 VDD6 V-DBB
+F1 VSS1 GND
+N8 VSS2 GND
+K1 VSS3 GND
+P2 VSS4 GND
+P4 VSS5 GND
+P10 VSS6 GND
+P13 VSS7 GND
+G14 BSS8 GND
+A10 VSS9 GND
+A7 VSS10 GND
+A2 VSS11 GND
+B1 VSS12 GND
+D13 VDDS_RTC V-RTC
+D14 VDD_RTC V-RTC
+C14 VSS_RTC GND
+E11 VDD_ANG V-IO
+E12 VSS_ANG GND
+F11 VDD_PLL V-DBB
+E14 VSS_PLL GND
+
+Other signals
+
+MODEM_ON
+MODEM_RST
diff --git a/doc/gsmdevboard-block.svg b/doc/gsmdevboard-block.svg
new file mode 100644
index 00000000..cb19bc0a
--- /dev/null
+++ b/doc/gsmdevboard-block.svg
@@ -0,0 +1,746 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="297mm"
+ height="210mm"
+ id="svg2383"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="gsmdevboard-block.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/sunbeam/home/laforge/gsmdevboard-block.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs2385">
+ <marker
+ inkscape:stockid="CurveIn"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="CurveIn"
+ style="overflow:visible">
+ <path
+ id="path3349"
+ d="M 4.6254930,-5.0456926 C 1.8654930,-5.0456926 -0.37450702,-2.8056926 -0.37450702,-0.045692580 C -0.37450702,2.7143074 1.8654930,4.9543074 4.6254930,4.9543074"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none;fill:none"
+ transform="scale(0.6)" />
+ </marker>
+ <marker
+ inkscape:stockid="DotM"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="DotM"
+ style="overflow:visible">
+ <path
+ id="path3229"
+ d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none"
+ transform="scale(0.4) translate(7.4, 1)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mstart"
+ style="overflow:visible">
+ <path
+ id="path7719"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ id="path3191"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Send"
+ style="overflow:visible;">
+ <path
+ id="path3179"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.2) rotate(180) translate(6,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mend"
+ style="overflow:visible;">
+ <path
+ id="path3173"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.4) rotate(180) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutL"
+ style="overflow:visible">
+ <path
+ id="path3307"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path3185"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lend"
+ style="overflow:visible;">
+ <path
+ id="path3188"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.8) rotate(180) translate(12.5,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 372.04724 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="1052.3622 : 372.04724 : 1"
+ inkscape:persp3d-origin="526.18109 : 248.03149 : 1"
+ id="perspective2392" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:document-units="mm"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.96166971"
+ inkscape:cx="386.08127"
+ inkscape:cy="495.79724"
+ inkscape:current-layer="layer1"
+ id="namedview2387"
+ showgrid="true"
+ inkscape:snap-global="true"
+ inkscape:window-width="1598"
+ inkscape:window-height="1163"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:snap-guide="true"
+ inkscape:object-paths="false"
+ inkscape:object-nodes="false"
+ objecttolerance="3"
+ gridtolerance="10000">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2400"
+ visible="true"
+ enabled="true"
+ units="mm"
+ spacingx="5mm"
+ spacingy="5mm"
+ empspacing="2" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata2389">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#CurveIn);stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 992.12598,230.31495 L 1045.2756,230.31495 L 1045.2756,159.44881 L 1045.2756,159.44881"
+ id="path22123" />
+ <g
+ id="g20347">
+ <rect
+ y="70.77356"
+ x="389.63159"
+ height="230.24446"
+ width="106.56361"
+ id="rect2406"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.50725651;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ transform="scale(1.0221827,0.9782987)"
+ sodipodi:linespacing="100%"
+ id="text7157"
+ y="92.63372"
+ x="381.30542"
+ style="font-size:21.45465279px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="92.63372"
+ x="381.30542"
+ id="tspan7159"
+ sodipodi:role="line">TWL3025</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12244"
+ y="216.1601"
+ x="394.66666"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="216.1601"
+ x="394.66666"
+ id="tspan12246"
+ sodipodi:role="line">BSP</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12248"
+ y="252.99342"
+ x="395.16666"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="252.99342"
+ x="395.16666"
+ id="tspan12250"
+ sodipodi:role="line">USP</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12252"
+ y="286.42783"
+ x="396.16666"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="286.42783"
+ x="396.16666"
+ id="tspan12254"
+ sodipodi:role="line">TSP</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text20330"
+ y="163.44881"
+ x="464.62991"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="163.44881"
+ x="464.62991"
+ id="tspan20332"
+ sodipodi:role="line">BUL</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text20334"
+ y="146.96971"
+ x="463.70053"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="146.96971"
+ x="463.70053"
+ id="tspan20336"
+ sodipodi:role="line">BDL</tspan></text>
+ </g>
+ <g
+ id="g13450">
+ <rect
+ y="177.16687"
+ x="885.82831"
+ height="88.888702"
+ width="106.29617"
+ id="rect12310"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.77468574;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text13440"
+ y="230.31496"
+ x="903.54333"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="230.31496"
+ x="903.54333"
+ id="tspan13442"
+ sodipodi:role="line">Antenna</tspan><tspan
+ id="tspan13444"
+ y="242.31496"
+ x="903.54333"
+ sodipodi:role="line">Switch</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text13446"
+ y="194.88188"
+ x="887.82678"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="194.88188"
+ x="887.82678"
+ id="tspan13448"
+ sodipodi:role="line">ASM4532</tspan></text>
+ </g>
+ <rect
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.61511528;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect11596"
+ width="142.16623"
+ height="88.074844"
+ x="885.74847"
+ y="35.354794" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#550000;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+ d="M 496.06299,283.46456 L 850.3937,283.46456 L 850.3937,106.29921 L 885.82677,106.29921"
+ id="path21554" />
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.54330707;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 248.0315,212.59842 L 389.76378,212.59842 L 389.76378,212.59842"
+ id="path7167" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:3.54330708999999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+ d="M 248.0315,283.46456 L 389.76378,283.46456"
+ id="path7171" />
+ <path
+ style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.54330707;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 248.03149,248.03149 L 389.76378,248.03149 L 389.76378,248.03149"
+ id="path9925" />
+ <g
+ id="g12217">
+ <rect
+ y="35.433064"
+ x="637.79529"
+ height="212.59842"
+ width="141.73228"
+ id="rect2408"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.77165354;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text7153"
+ y="53.149601"
+ x="637.79529"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan11602"
+ y="78.149597"
+ x="637.79529"
+ sodipodi:role="line">TRF6151</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12175"
+ y="88.582672"
+ x="655.51184"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="88.582672"
+ x="655.51184"
+ id="tspan12177"
+ sodipodi:role="line">Transceiver</tspan><tspan
+ id="tspan12179"
+ y="104.58267"
+ x="655.51184"
+ sodipodi:role="line">Mixers</tspan><tspan
+ id="tspan12183"
+ y="120.58267"
+ x="655.51184"
+ sodipodi:role="line">VCO</tspan><tspan
+ id="tspan12181"
+ y="136.58267"
+ x="655.51184"
+ sodipodi:role="line">PLL</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="885.82678"
+ y="53.149601"
+ id="text11598"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan11600"
+ x="885.82678"
+ y="53.149601">RF3166</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="903.54333"
+ y="88.582672"
+ id="text12185"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ x="903.54333"
+ y="88.582672"
+ id="tspan12193">RF PA</tspan></text>
+ <g
+ id="g12268">
+ <path
+ id="path11606"
+ d="M 779.52756,53.149601 L 885.82677,53.149601 L 885.82677,53.149601"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12260"
+ y="51.149601"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="51.149601"
+ x="814.96063"
+ id="tspan12262"
+ sodipodi:role="line">GSM</tspan></text>
+ </g>
+ <g
+ id="g12273">
+ <path
+ id="path12195"
+ d="M 779.52756,70.866136 L 885.82677,70.866136 L 885.82677,70.866136"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12264"
+ y="68.866135"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="68.866135"
+ x="814.96063"
+ id="tspan12266"
+ sodipodi:role="line">DCS/PCS</tspan></text>
+ </g>
+ <g
+ id="g12290">
+ <path
+ id="path12197"
+ d="M 885.82677,194.88188 L 779.52756,194.88188 L 779.52756,194.88188"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12278"
+ y="192.88188"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="192.88188"
+ x="814.96063"
+ id="tspan12280"
+ sodipodi:role="line">GSM</tspan></text>
+ </g>
+ <g
+ id="g12295">
+ <path
+ id="path12165"
+ d="M 885.82677,212.59841 L 779.52756,212.59841 L 779.52756,212.59841"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12282"
+ y="210.59842"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="210.59842"
+ x="814.96063"
+ id="tspan12284"
+ sodipodi:role="line">DCS</tspan></text>
+ </g>
+ <g
+ id="g12300">
+ <path
+ id="path12199"
+ d="M 885.82677,230.31495 L 779.52756,230.31495 L 779.52756,230.31495"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12286"
+ y="228.31496"
+ x="814.96063"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="228.31496"
+ x="814.96063"
+ id="tspan12288"
+ sodipodi:role="line">PCS</tspan></text>
+ </g>
+ <g
+ id="g18005">
+ <text
+ sodipodi:linespacing="100%"
+ id="text14594"
+ y="49.149601"
+ x="425.21259"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan14598"
+ y="49.149601"
+ x="425.21259"
+ sodipodi:role="line">RFCLK</tspan></text>
+ <path
+ id="path14605"
+ d="M 637.79528,53.149601 L 248.0315,53.149601 L 248.0315,53.149601"
+ style="fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)" />
+ </g>
+ <g
+ id="g18583">
+ <path
+ inkscape:label="#path2410"
+ id="path241011111"
+ d="M 496.06299,141.73228 L 637.79528,141.73228 L 637.79528,141.73228 L 637.79528,141.73228"
+ style="fill:#00ff00;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text12167"
+ y="137.73228"
+ x="539.21259"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="137.73228"
+ x="539.21259"
+ id="tspan12169"
+ sodipodi:role="line">I/Q Analog</tspan></text>
+ <path
+ id="path15170"
+ d="M 531.49606,141.73228 L 531.49606,159.44881 L 496.06299,159.44881 L 496.06299,159.44881"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow2Mstart);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <g
+ id="g18000">
+ <path
+ id="path17431"
+ d="M 248.0315,88.582671 L 389.76378,88.582671"
+ style="fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text17996"
+ y="84.582672"
+ x="295.18109"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="84.582672"
+ x="295.18109"
+ id="tspan17998"
+ sodipodi:role="line">CLK13M</tspan></text>
+ </g>
+ <g
+ id="g18593">
+ <path
+ id="path18010"
+ d="M 496.06299,194.88188 L 637.79528,194.88188"
+ style="fill:none;fill-rule:evenodd;stroke:#550000;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text18589"
+ y="188.88188"
+ x="537.49603"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="188.88188"
+ x="537.49603"
+ id="tspan18591"
+ sodipodi:role="line">AFC Analog</tspan></text>
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+ d="M 212.59843,301.1811 L 212.59843,372.04724 L 921.25984,372.04724 L 921.25984,265.74803"
+ id="path19726" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="354.33072"
+ y="368.04724"
+ id="text20291"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan20293"
+ x="354.33072"
+ y="368.04724">TSP Parallel</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="356.33072"
+ y="330.89764"
+ id="text20295"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan20297"
+ x="356.33072"
+ y="330.89764">TSP Serial</tspan></text>
+ <g
+ id="g20314"
+ transform="translate(-4.7244095e-7,-17.716533)">
+ <path
+ id="path20301"
+ d="M 248.0315,124.01574 L 389.76378,124.01574"
+ style="fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text20303"
+ y="120.01574"
+ x="295.18109"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan20310"
+ y="120.01574"
+ x="295.18109"
+ sodipodi:role="line">CLK32K</tspan></text>
+ </g>
+ <g
+ id="g20421">
+ <path
+ id="path12871"
+ d="M 956.69291,124.01574 L 956.69291,177.16535"
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464575;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ transform="matrix(0,-1,1,0,0,0)"
+ sodipodi:linespacing="100%"
+ id="text20402"
+ y="952.69293"
+ x="-159.44881"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="952.69293"
+ x="-159.44881"
+ id="tspan20404"
+ sodipodi:role="line">GSM</tspan></text>
+ </g>
+ <g
+ id="g20415">
+ <g
+ id="g20410">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 921.25984,124.01574 L 921.25984,177.16535"
+ id="path12312" />
+ <text
+ xml:space="preserve"
+ style="font-size:11.36807537px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="-184.69075"
+ y="867.06183"
+ id="text20406"
+ sodipodi:linespacing="100%"
+ transform="matrix(0,-0.9473396,1.0555877,0,0,0)"><tspan
+ sodipodi:role="line"
+ id="tspan20408"
+ x="-184.69075"
+ y="867.06183">DCS/PCS</tspan></text>
+ </g>
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-start:url(#DotM);marker-end:url(#Arrow2Mend)"
+ d="M 921.25984,372.04724 L 1009.8425,372.04724 L 1009.8425,124.01574 L 1009.8425,124.01574"
+ id="path20426" />
+ <text
+ xml:space="preserve"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="539.21259"
+ y="279.46457"
+ id="text22119"
+ sodipodi:linespacing="100%"><tspan
+ sodipodi:role="line"
+ id="tspan22121"
+ x="539.21259"
+ y="279.46457">APC Analog</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:2.83464567;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM);marker-end:url(#Arrow2Mend);stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 318.89764,283.46456 L 318.89764,336.61417 L 673.22835,336.61417 L 673.22835,248.03149"
+ id="path18598" />
+ <g
+ id="g3366">
+ <rect
+ y="35.433064"
+ x="70.866142"
+ height="265.74802"
+ width="177.16536"
+ id="rect7161"
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.77165353;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text7163"
+ y="53.149601"
+ x="72.866142"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3352"
+ y="53.149601"
+ x="72.866142"
+ sodipodi:role="line">BF537</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text12256"
+ y="287.46457"
+ x="218.59842"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="287.46457"
+ x="218.59842"
+ id="tspan12258"
+ sodipodi:role="line">TSP</tspan></text>
+ <path
+ d="M 158.52718,76.505608 A 0.46875,0.46875 0 1 1 157.58968,76.505608 A 0.46875,0.46875 0 1 1 158.52718,76.505608 z"
+ sodipodi:ry="0.46875"
+ sodipodi:rx="0.46875"
+ sodipodi:cy="76.505608"
+ sodipodi:cx="158.05843"
+ style="fill:#000000;stroke:none"
+ id="path2520"
+ sodipodi:type="arc" />
+ <path
+ id="path2522"
+ d="M 159.44882,35.327311 L 159.44882,301.07535 L 159.44882,301.07535 L 159.44882,301.07535 L 159.44882,301.07535"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.47677553;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="100%"
+ id="text3348"
+ y="53.149601"
+ x="159.44882"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3358"
+ y="53.149601"
+ x="159.44882"
+ sodipodi:role="line">Spartan</tspan><tspan
+ id="tspan3356"
+ y="73.149597"
+ x="159.44882"
+ sodipodi:role="line">3E</tspan></text>
+ <text
+ sodipodi:linespacing="100%"
+ id="text3362"
+ y="290.92511"
+ x="89.994156"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ y="290.92511"
+ x="89.994156"
+ id="tspan3364"
+ sodipodi:role="line">Ethernet</tspan></text>
+ </g>
+ </g>
+</svg>
diff --git a/include/l1a_l23_interface.h b/include/l1a_l23_interface.h
new file mode 100644
index 00000000..fc03d720
--- /dev/null
+++ b/include/l1a_l23_interface.h
@@ -0,0 +1,134 @@
+/* Messages to be sent between the different layers */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef l1a_l23_interface_h
+#define l1a_l23_interface_h
+
+#define SYNC_NEW_CCCH_REQ 1
+#define SYNC_NEW_CCCH_RESP 2
+#define CCCH_INFO_IND 3
+#define CCCH_RACH_REQ 4
+#define DEDIC_MODE_EST_REQ 5
+#define DEDIC_MODE_DATA_IND 6
+#define DEDIC_MODE_DATA_REQ 7
+#define LAYER1_RESET 8
+
+/*
+ * NOTE: struct size. We do add manual padding out of the believe
+ * that it will avoid some unaligned access.
+ */
+
+struct gsm_time {
+ uint32_t fn; /* FN count */
+ uint16_t t1; /* FN div (26*51) */
+ uint8_t t2; /* FN modulo 26 */
+ uint8_t t3; /* FN modulo 51 */
+ uint8_t tc;
+};
+
+/*
+ * downlink info ... down from the BTS..
+ */
+struct l1_info_dl {
+ uint8_t msg_type;
+ uint8_t padding;
+ /* the ARFCN and the band. */
+ uint16_t band_arfcn;
+
+ struct gsm_time time;
+ uint8_t rx_level;
+ uint16_t snr[4];
+} __attribute__((packed));
+
+/* new CCCH was found. This is following the header */
+struct l1_sync_new_ccch_resp {
+ uint8_t bsic;
+ uint8_t padding[3];
+} __attribute__((packed));
+
+/* data on the CCCH was found. This is following the header */
+struct l1_ccch_info_ind {
+ uint8_t data[23];
+} __attribute__((packed));
+
+/*
+ * uplink info
+ */
+struct l1_info_ul {
+ uint8_t msg_type;
+ uint8_t padding;
+ uint8_t tx_power;
+ uint8_t channel_number;
+ uint32_t tdma_frame;
+} __attribute__((packed));
+
+/*
+ * msg for SYNC_NEW_CCCH_REQ
+ * the l1_info_ul header is in front
+ */
+struct l1_sync_new_ccch_req {
+ uint16_t band_arfcn;
+} __attribute__((packed));
+
+
+/* the l1_info_ul header is in front */
+struct l1_rach_req {
+ uint8_t ra;
+ uint8_t padding[3];
+} __attribute__((packed));
+
+struct l1_dedic_mode_est_req {
+ struct l1_info_ul header;
+ uint16_t band_arfcn;
+ union {
+ struct {
+ uint8_t maio_high:4,
+ h:1,
+ tsc:3;
+ uint8_t hsn:6,
+ maio_low:2;
+ } h1;
+ struct {
+ uint8_t arfcn_high:2,
+ spare:2,
+ h:1,
+ tsc:3;
+ uint8_t arfcn_low;
+ } h0;
+ };
+} __attribute__((packed));
+
+/* it is like the ccch ind... unite it? */
+
+/* the l1_info_dl header is in front */
+struct l1_dedic_mode_data_ind {
+ uint8_t data[23];
+} __attribute__((packed));
+
+/* the l1_info_ul header is in front */
+struct l1_dedic_mode_data_req {
+ uint8_t data[23];
+} __attribute__((packed));
+
+
+#endif
diff --git a/src/host/calypso_pll/pll.pl b/src/host/calypso_pll/pll.pl
new file mode 100755
index 00000000..52c91319
--- /dev/null
+++ b/src/host/calypso_pll/pll.pl
@@ -0,0 +1,10 @@
+#!/usr/bin/perl
+
+my $f_in = 26*1000*1000;
+
+for (my $mult = 1; $mult < 31; $mult++) {
+ for (my $div = 0; $div < 3; $div++) {
+ my $fout = $f_in * ($mult / ($div+1));
+ printf("%03.1f MHz (mult=%2u, div=%1u)\n", $fout/(1000*1000), $mult, $div);
+ }
+}
diff --git a/src/host/layer2/.gitignore b/src/host/layer2/.gitignore
new file mode 100644
index 00000000..d3594665
--- /dev/null
+++ b/src/host/layer2/.gitignore
@@ -0,0 +1,14 @@
+Makefile
+Makefile.in
+aclocal.m4
+configure
+missing
+*.o
+depcomp
+config.*
+*.sw?
+*.deps
+layer2
+install-sh
+autom4te.cache
+*.a
diff --git a/src/host/layer2/Makefile.am b/src/host/layer2/Makefile.am
new file mode 100644
index 00000000..bc3910fa
--- /dev/null
+++ b/src/host/layer2/Makefile.am
@@ -0,0 +1,3 @@
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+SUBDIRS = include src
diff --git a/src/host/layer2/configure.ac b/src/host/layer2/configure.ac
new file mode 100644
index 00000000..72ed2f82
--- /dev/null
+++ b/src/host/layer2/configure.ac
@@ -0,0 +1,24 @@
+dnl Process this file with autoconf to produce a configure script
+AC_INIT
+
+AM_INIT_AUTOMAKE(layer2, 0.0.0)
+
+dnl kernel style compile messages
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+dnl checks for programs
+AC_PROG_MAKE_SET
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+
+dnl checks for header files
+AC_HEADER_STDC
+
+dnl Checks for typedefs, structures and compiler characteristics
+
+AC_OUTPUT(
+ src/Makefile
+ include/Makefile
+ include/osmocom/Makefile
+ Makefile)
diff --git a/src/host/layer2/include/Makefile.am b/src/host/layer2/include/Makefile.am
new file mode 100644
index 00000000..ca774b6b
--- /dev/null
+++ b/src/host/layer2/include/Makefile.am
@@ -0,0 +1,2 @@
+noinst_HEADERS = l1a_l23_interface.h
+SUBDIRS = osmocom
diff --git a/src/host/layer2/include/l1a_l23_interface.h b/src/host/layer2/include/l1a_l23_interface.h
new file mode 120000
index 00000000..2bbc9679
--- /dev/null
+++ b/src/host/layer2/include/l1a_l23_interface.h
@@ -0,0 +1 @@
+../../../../include/l1a_l23_interface.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/Makefile.am b/src/host/layer2/include/osmocom/Makefile.am
new file mode 100644
index 00000000..7a5a088c
--- /dev/null
+++ b/src/host/layer2/include/osmocom/Makefile.am
@@ -0,0 +1,4 @@
+# headers from OpenBSC
+noinst_HEADERS = debug.h gsm_04_08.h linuxlist.h meas_rep.h msgb.h \
+ select.h talloc.h timer.h
+noinst_HEADERS += osmocom_layer2.h osmocom_data.h
diff --git a/src/host/layer2/include/osmocom/debug.h b/src/host/layer2/include/osmocom/debug.h
new file mode 120000
index 00000000..ae7c52c3
--- /dev/null
+++ b/src/host/layer2/include/osmocom/debug.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/debug.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/gsm_04_08.h b/src/host/layer2/include/osmocom/gsm_04_08.h
new file mode 120000
index 00000000..64dbbe0b
--- /dev/null
+++ b/src/host/layer2/include/osmocom/gsm_04_08.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/gsm_04_08.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/linuxlist.h b/src/host/layer2/include/osmocom/linuxlist.h
new file mode 120000
index 00000000..40851e84
--- /dev/null
+++ b/src/host/layer2/include/osmocom/linuxlist.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/linuxlist.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/meas_rep.h b/src/host/layer2/include/osmocom/meas_rep.h
new file mode 120000
index 00000000..2ab68561
--- /dev/null
+++ b/src/host/layer2/include/osmocom/meas_rep.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/meas_rep.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/msgb.h b/src/host/layer2/include/osmocom/msgb.h
new file mode 120000
index 00000000..eb079008
--- /dev/null
+++ b/src/host/layer2/include/osmocom/msgb.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/msgb.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/osmocom_data.h b/src/host/layer2/include/osmocom/osmocom_data.h
new file mode 100644
index 00000000..dd930a2f
--- /dev/null
+++ b/src/host/layer2/include/osmocom/osmocom_data.h
@@ -0,0 +1,22 @@
+#ifndef osmocom_data_h
+#define osmocom_data_h
+
+#include <osmocom/select.h>
+
+/* taken from OpenBSC */
+enum gsm_band {
+ GSM_BAND_400,
+ GSM_BAND_850,
+ GSM_BAND_900,
+ GSM_BAND_1800,
+ GSM_BAND_1900,
+};
+
+/* One Mobilestation for osmocom */
+struct osmocom_ms {
+ struct bsc_fd bfd;
+ enum gsm_band band;
+ int arfcn;
+};
+
+#endif
diff --git a/src/host/layer2/include/osmocom/osmocom_layer2.h b/src/host/layer2/include/osmocom/osmocom_layer2.h
new file mode 100644
index 00000000..af71873c
--- /dev/null
+++ b/src/host/layer2/include/osmocom/osmocom_layer2.h
@@ -0,0 +1,12 @@
+#ifndef osmocom_layer2_h
+#define osmocom_layer2_h
+
+#include <osmocom/msgb.h>
+
+struct osmocom_ms;
+
+int osmo_recv(struct osmocom_ms *ms, struct msgb *msg);
+
+extern int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg);
+
+#endif
diff --git a/src/host/layer2/include/osmocom/select.h b/src/host/layer2/include/osmocom/select.h
new file mode 120000
index 00000000..557060f7
--- /dev/null
+++ b/src/host/layer2/include/osmocom/select.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/select.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/talloc.h b/src/host/layer2/include/osmocom/talloc.h
new file mode 120000
index 00000000..7929944b
--- /dev/null
+++ b/src/host/layer2/include/osmocom/talloc.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/talloc.h \ No newline at end of file
diff --git a/src/host/layer2/include/osmocom/timer.h b/src/host/layer2/include/osmocom/timer.h
new file mode 120000
index 00000000..7cffef20
--- /dev/null
+++ b/src/host/layer2/include/osmocom/timer.h
@@ -0,0 +1 @@
+../../../libosmocom/include/osmocom/timer.h \ No newline at end of file
diff --git a/src/host/layer2/src/Makefile.am b/src/host/layer2/src/Makefile.am
new file mode 100644
index 00000000..5cca4afa
--- /dev/null
+++ b/src/host/layer2/src/Makefile.am
@@ -0,0 +1,10 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS=-Wall
+
+noinst_LIBRARIES = libosmocom.a
+libosmocom_a_SOURCES = libosmocom/debug.c libosmocom/msgb.c libosmocom/select.c \
+ libosmocom/talloc.c libosmocom/timer.c
+
+sbin_PROGRAMS = layer2
+layer2_SOURCES = layer2_main.c osmocom_layer2.c
+layer2_LDADD = libosmocom.a
diff --git a/src/host/layer2/src/layer2_main.c b/src/host/layer2/src/layer2_main.c
new file mode 100644
index 00000000..c84cce49
--- /dev/null
+++ b/src/host/layer2/src/layer2_main.c
@@ -0,0 +1,205 @@
+/* Main method of the layer2 stack */
+/* (C) 2010 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <osmocom/osmocom_layer2.h>
+#include <osmocom/osmocom_data.h>
+
+#include <osmocom/debug.h>
+#include <osmocom/msgb.h>
+#include <osmocom/talloc.h>
+
+#include <arpa/inet.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#define GSM_L2_LENGTH 256
+
+static void *l2_ctx = NULL;
+static char *socket_path = "/tmp/osmocom_l2";
+static struct osmocom_ms *ms = NULL;
+
+static int layer2_read(struct bsc_fd *fd, unsigned int flags)
+{
+ struct msgb *msg;
+ u_int16_t len;
+ int rc;
+
+ msg = msgb_alloc(GSM_L2_LENGTH, "Layer2");
+ if (!msg) {
+ fprintf(stderr, "Failed to allocate msg.\n");
+ return -1;
+ }
+
+ rc = read(fd->fd, &len, sizeof(len));
+ if (rc < sizeof(len)) {
+ fprintf(stderr, "Short read. Error.\n");
+ exit(2);
+ }
+
+ if (ntohs(len) > GSM_L2_LENGTH) {
+ fprintf(stderr, "Length is too big: %u\n", ntohs(len));
+ msgb_free(msg);
+ return -1;
+ }
+
+
+ /* blocking read for the poor... we can starve in here... */
+ msg->l2h = msgb_put(msg, ntohs(len));
+ rc = read(fd->fd, msg->l2h, msgb_l2len(msg));
+ if (rc != msgb_l2len(msg)) {
+ fprintf(stderr, "Can not read data: rc: %d errno: %d\n", rc, errno);
+ msgb_free(msg);
+ return -1;
+ }
+
+ osmo_recv((struct osmocom_ms *) fd->data, msg);
+ msgb_free(msg);
+ return 0;
+}
+
+int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg)
+{
+ int rc;
+ uint16_t *len;
+
+ LOGP(DMUX, LOGL_INFO, "Sending: '%s'\n", hexdump(msg->data, msg->len));
+
+
+ len = (uint16_t *) msgb_push(msg, sizeof(*len));
+ *len = htons(msg->len - sizeof(*len));
+
+ /* TODO: just enqueue the message and wait for ready write.. */
+ rc = write(ms->bfd.fd, msg->data, msg->len);
+ if (rc != msg->len) {
+ fprintf(stderr, "Failed to write data: rc: %d\n", rc);
+ msgb_free(msg);
+ return -1;
+ }
+
+ msgb_free(msg);
+ return 0;
+}
+
+static void print_usage()
+{
+ printf("Usage: ./layer2\n");
+}
+
+static void print_help()
+{
+ printf(" Some help...\n");
+ printf(" -h --help this text\n");
+ printf(" -s --socket /tmp/osmocom_l2. Path to the unix domain socket\n");
+ printf(" -a --arfcn NR. The ARFCN to be used for layer2.\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+ while (1) {
+ int option_index = 0, c;
+ static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"socket", 1, 0, 's'},
+ {"arfcn", 1, 0, 'a'},
+ {0, 0, 0, 0},
+ };
+
+ c = getopt_long(argc, argv, "hs:a:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage();
+ print_help();
+ exit(0);
+ break;
+ case 's':
+ socket_path = talloc_strdup(l2_ctx, optarg);
+ break;
+ case 'a':
+ ms->arfcn = atoi(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+ struct sockaddr_un local;
+
+ l2_ctx = talloc_named_const(NULL, 1, "layer2 context");
+
+ ms = talloc_zero(l2_ctx, struct osmocom_ms);
+ if (!ms) {
+ fprintf(stderr, "Failed to allocate MS\n");
+ exit(1);
+ }
+
+ ms->arfcn = 871;
+
+ handle_options(argc, argv);
+
+ ms->bfd.fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (ms->bfd.fd < 0) {
+ fprintf(stderr, "Failed to create unix domain socket.\n");
+ exit(1);
+ }
+
+ local.sun_family = AF_UNIX;
+ strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
+ local.sun_path[sizeof(local.sun_path) - 1] = '\0';
+
+ rc = connect(ms->bfd.fd, (struct sockaddr *) &local,
+ sizeof(local.sun_family) + strlen(local.sun_path));
+ if (rc < 0) {
+ fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
+ exit(1);
+ }
+
+ ms->bfd.when = BSC_FD_READ;
+ ms->bfd.cb = layer2_read;
+ ms->bfd.data = ms;
+
+ if (bsc_register_fd(&ms->bfd) != 0) {
+ fprintf(stderr, "Failed to register fd.\n");
+ exit(1);
+ }
+
+ while (1) {
+ bsc_select_main(0);
+ }
+
+
+ return 0;
+}
diff --git a/src/host/layer2/src/libosmocom/debug.c b/src/host/layer2/src/libosmocom/debug.c
new file mode 120000
index 00000000..acf42611
--- /dev/null
+++ b/src/host/layer2/src/libosmocom/debug.c
@@ -0,0 +1 @@
+../../../libosmocom/src/debug.c \ No newline at end of file
diff --git a/src/host/layer2/src/libosmocom/msgb.c b/src/host/layer2/src/libosmocom/msgb.c
new file mode 120000
index 00000000..42624f80
--- /dev/null
+++ b/src/host/layer2/src/libosmocom/msgb.c
@@ -0,0 +1 @@
+../../../libosmocom/src/msgb.c \ No newline at end of file
diff --git a/src/host/layer2/src/libosmocom/select.c b/src/host/layer2/src/libosmocom/select.c
new file mode 120000
index 00000000..005d21bb
--- /dev/null
+++ b/src/host/layer2/src/libosmocom/select.c
@@ -0,0 +1 @@
+../../../libosmocom/src/select.c \ No newline at end of file
diff --git a/src/host/layer2/src/libosmocom/signal.c b/src/host/layer2/src/libosmocom/signal.c
new file mode 120000
index 00000000..d1651c39
--- /dev/null
+++ b/src/host/layer2/src/libosmocom/signal.c
@@ -0,0 +1 @@
+../../../libosmocom/src/signal.c \ No newline at end of file
diff --git a/src/host/layer2/src/libosmocom/talloc.c b/src/host/layer2/src/libosmocom/talloc.c
new file mode 120000
index 00000000..dcc53fa7
--- /dev/null
+++ b/src/host/layer2/src/libosmocom/talloc.c
@@ -0,0 +1 @@
+../../../libosmocom/src/talloc.c \ No newline at end of file
diff --git a/src/host/layer2/src/libosmocom/timer.c b/src/host/layer2/src/libosmocom/timer.c
new file mode 120000
index 00000000..142a2aa0
--- /dev/null
+++ b/src/host/layer2/src/libosmocom/timer.c
@@ -0,0 +1 @@
+../../../libosmocom/src/timer.c \ No newline at end of file
diff --git a/src/host/layer2/src/osmocom_layer2.c b/src/host/layer2/src/osmocom_layer2.c
new file mode 100644
index 00000000..0be0a4c4
--- /dev/null
+++ b/src/host/layer2/src/osmocom_layer2.c
@@ -0,0 +1,226 @@
+/* Layer2 handling code... LAPD and stuff
+ *
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <osmocom/osmocom_layer2.h>
+#include <osmocom/osmocom_data.h>
+#include <osmocom/debug.h>
+#include <osmocom/gsm_04_08.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <l1a_l23_interface.h>
+
+
+static struct msgb *osmo_l1_alloc(uint8_t msg_type)
+{
+ struct l1_info_ul *ul;
+ struct msgb *msg = msgb_alloc_headroom(256, 4, "osmo_l1");
+
+ if (!msg) {
+ fprintf(stderr, "Failed to allocate memory.\n");
+ return NULL;
+ }
+
+ ul = (struct l1_info_ul *) msgb_put(msg, sizeof(*ul));
+ ul->msg_type = msg_type;
+
+ return msg;
+}
+
+static int osmo_make_band_arfcn(struct osmocom_ms *ms)
+{
+ /* TODO: Include the band */
+ return ms->arfcn;
+}
+
+static int osmo_l2_ccch_resp(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct l1_info_dl *dl;
+ struct l1_sync_new_ccch_resp *sb;
+
+ if (msgb_l3len(msg) < sizeof(*sb)) {
+ fprintf(stderr, "MSG too short for CCCH RESP: %u\n", msgb_l3len(msg));
+ return -1;
+ }
+
+ dl = (struct l1_info_dl *) msg->l2h;
+ sb = (struct l1_sync_new_ccch_resp *) msg->l3h;
+
+ printf("Found sync burst: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n",
+ dl->snr[0], dl->time.t1, dl->time.t2, dl->time.t3, sb->bsic);
+ return 0;
+}
+
+static void dump_bcch(u_int8_t tc, const uint8_t *data)
+{
+ struct gsm48_system_information_type_header *si_hdr;
+ si_hdr = (struct gsm48_system_information_type_header *) data;;
+
+ /* GSM 05.02 §6.3.1.3 Mapping of BCCH data */
+ switch (si_hdr->system_information) {
+ case GSM48_MT_RR_SYSINFO_1:
+ fprintf(stderr, "\tSI1");
+ if (tc != 0)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_2:
+ fprintf(stderr, "\tSI2");
+ if (tc != 1)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_3:
+ fprintf(stderr, "\tSI3");
+ if (tc != 2 && tc != 6)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_4:
+ fprintf(stderr, "\tSI4");
+ if (tc != 3 && tc != 7)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_5:
+ fprintf(stderr, "\tSI5");
+ break;
+ case GSM48_MT_RR_SYSINFO_6:
+ fprintf(stderr, "\tSI6");
+ break;
+ case GSM48_MT_RR_SYSINFO_7:
+ fprintf(stderr, "\tSI7");
+ if (tc != 7)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_8:
+ fprintf(stderr, "\tSI8");
+ if (tc != 3)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_9:
+ fprintf(stderr, "\tSI9");
+ if (tc != 4)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_13:
+ fprintf(stderr, "\tSI13");
+ if (tc != 4 && tc != 0)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_16:
+ fprintf(stderr, "\tSI16");
+ if (tc != 6)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_17:
+ fprintf(stderr, "\tSI17");
+ if (tc != 2)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_2bis:
+ fprintf(stderr, "\tSI2bis");
+ if (tc != 5)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_2ter:
+ fprintf(stderr, "\tSI2ter");
+ if (tc != 5 && tc != 4)
+ fprintf(stderr, " on wrong TC");
+ break;
+ case GSM48_MT_RR_SYSINFO_5bis:
+ fprintf(stderr, "\tSI5bis");
+ break;
+ case GSM48_MT_RR_SYSINFO_5ter:
+ fprintf(stderr, "\tSI5ter");
+ break;
+ default:
+ fprintf(stderr, "\tUnknown SI");
+ break;
+ };
+
+ fprintf(stderr, "\n");
+}
+
+static int osmo_l2_ccch_data(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct l1_info_dl *dl;
+ struct l1_ccch_info_ind *ccch;
+
+ if (msgb_l3len(msg) < sizeof(*ccch)) {
+ fprintf(stderr, "MSG too short CCCH Data Ind: %u\n", msgb_l3len(msg));
+ return -1;
+ }
+
+ dl = (struct l1_info_dl *) msg->l2h;
+ ccch = (struct l1_ccch_info_ind *) msg->l3h;
+ printf("Found CCCH burst(s): TDMA: (%.4u/%.2u/%.2u) tc:%d %s si: 0x%x\n",
+ dl->time.t1, dl->time.t2, dl->time.t3, dl->time.tc,
+ hexdump(ccch->data, sizeof(ccch->data)), ccch->data[2]);
+
+ dump_bcch(dl->time.tc, ccch->data);
+ return 0;
+}
+
+static int osmo_l1_reset(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+ struct l1_sync_new_ccch_req *req;
+
+ msg = osmo_l1_alloc(SYNC_NEW_CCCH_REQ);
+ if (!msg)
+ return -1;
+
+ printf("Layer1 Reset.\n");
+ req = (struct l1_sync_new_ccch_req *) msgb_put(msg, sizeof(*req));
+ req->band_arfcn = osmo_make_band_arfcn(ms);
+
+ return osmo_send_l1(ms, msg);
+}
+
+
+int osmo_recv(struct osmocom_ms *ms, struct msgb *msg)
+{
+ int rc = 0;
+ struct l1_info_dl *dl;
+
+ if (msgb_l2len(msg) < sizeof(*dl)) {
+ fprintf(stderr, "Short Layer2 message: %u\n", msgb_l2len(msg));
+ return -1;
+ }
+
+ dl = (struct l1_info_dl *) msg->l2h;
+ msg->l3h = &msg->l2h[0] + sizeof(*dl);
+
+ switch (dl->msg_type) {
+ case SYNC_NEW_CCCH_RESP:
+ rc = osmo_l2_ccch_resp(ms, msg);
+ break;
+ case CCCH_INFO_IND:
+ rc = osmo_l2_ccch_data(ms, msg);
+ break;
+ case LAYER1_RESET:
+ rc = osmo_l1_reset(ms);
+ break;
+ default:
+ fprintf(stderr, "Unknown MSG: %u\n", dl->msg_type);
+ break;
+ }
+
+ return rc;
+}
diff --git a/src/host/libosmocom/README b/src/host/libosmocom/README
new file mode 100644
index 00000000..1a97beac
--- /dev/null
+++ b/src/host/libosmocom/README
@@ -0,0 +1 @@
+This is a copy of OpenBSC header and sources. Do not edit them.
diff --git a/src/host/libosmocom/include/osmocom/debug.h b/src/host/libosmocom/include/osmocom/debug.h
new file mode 100644
index 00000000..c40eec3f
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/debug.h
@@ -0,0 +1,131 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#include <stdio.h>
+#include "linuxlist.h"
+
+#define DEBUG
+
+/* Debug Areas of the code */
+enum {
+ DRLL,
+ DCC,
+ DMM,
+ DRR,
+ DRSL,
+ DNM,
+ DMNCC,
+ DSMS,
+ DPAG,
+ DMEAS,
+ DMI,
+ DMIB,
+ DMUX,
+ DINP,
+ DSCCP,
+ DMSC,
+ DMGCP,
+ DHO,
+ DDB,
+ DREF,
+ Debug_LastEntry,
+};
+
+#ifdef DEBUG
+#define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args)
+#define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args)
+#else
+#define DEBUGP(xss, fmt, args...)
+#define DEBUGPC(ss, fmt, args...)
+#endif
+
+
+#define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
+
+char *hexdump(const unsigned char *buf, int len);
+void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
+
+/* new logging interface */
+#define LOGP(ss, level, fmt, args...) debugp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
+#define LOGPC(ss, level, fmt, args...) debugp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
+
+/* different levels */
+#define LOGL_DEBUG 1 /* debugging information */
+#define LOGL_INFO 3
+#define LOGL_NOTICE 5 /* abnormal/unexpected condition */
+#define LOGL_ERROR 7 /* error condition, requires user action */
+#define LOGL_FATAL 8 /* fatal, program aborted */
+
+/* context */
+#define BSC_CTX_LCHAN 0
+#define BSC_CTX_SUBSCR 1
+#define BSC_CTX_BTS 2
+#define BSC_CTX_SCCP 3
+
+/* target */
+
+enum {
+ DEBUG_FILTER_IMSI = 1 << 0,
+ DEBUG_FILTER_ALL = 1 << 1,
+};
+
+struct debug_category {
+ int enabled;
+ int loglevel;
+};
+
+struct debug_target {
+ int filter_map;
+ char *imsi_filter;
+
+
+ struct debug_category categories[Debug_LastEntry];
+ int use_color;
+ int print_timestamp;
+ int loglevel;
+
+ union {
+ struct {
+ FILE *out;
+ } tgt_stdout;
+
+ struct {
+ int priority;
+ } tgt_syslog;
+
+ struct {
+ void *vty;
+ } tgt_vty;
+ };
+
+ void (*output) (struct debug_target *target, const char *string);
+
+ struct llist_head entry;
+};
+
+/* use the above macros */
+void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 6, 7)));
+void debug_init(void);
+
+/* context management */
+void debug_reset_context(void);
+void debug_set_context(int ctx, void *value);
+
+/* filter on the targets */
+void debug_set_imsi_filter(struct debug_target *target, const char *imsi);
+void debug_set_all_filter(struct debug_target *target, int);
+void debug_set_use_color(struct debug_target *target, int);
+void debug_set_print_timestamp(struct debug_target *target, int);
+void debug_set_log_level(struct debug_target *target, int log_level);
+void debug_parse_category_mask(struct debug_target *target, const char* mask);
+int debug_parse_level(const char *lvl);
+int debug_parse_category(const char *category);
+void debug_set_category_filter(struct debug_target *target, int category, int enable, int level);
+
+
+/* management of the targets */
+struct debug_target *debug_target_create(void);
+struct debug_target *debug_target_create_stderr(void);
+void debug_add_target(struct debug_target *target);
+void debug_del_target(struct debug_target *target);
+#endif /* _DEBUG_H */
diff --git a/src/host/libosmocom/include/osmocom/gsm_04_08.h b/src/host/libosmocom/include/osmocom/gsm_04_08.h
new file mode 100644
index 00000000..84b9b5d1
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/gsm_04_08.h
@@ -0,0 +1,796 @@
+#ifndef _GSM_04_08_H
+#define _GSM_04_08_H
+
+#include <osmocom/meas_rep.h>
+
+/* GSM TS 04.08 definitions */
+struct gsm_lchan;
+
+struct gsm48_classmark1 {
+ u_int8_t spare:1,
+ rev_level:2,
+ es_ind:1,
+ a5_1:1,
+ pwr_lev:3;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.5 */
+struct gsm48_chan_desc {
+ u_int8_t chan_nr;
+ union {
+ struct {
+ u_int8_t maio_high:4,
+ h:1,
+ tsc:3;
+ u_int8_t hsn:6,
+ maio_low:2;
+ } h1;
+ struct {
+ u_int8_t arfcn_high:2,
+ spare:2,
+ h:1,
+ tsc:3;
+ u_int8_t arfcn_low;
+ } h0;
+ };
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.21aa */
+struct gsm48_multi_rate_conf {
+ u_int8_t smod : 2,
+ spare: 1,
+ icmi : 1,
+ nscb : 1,
+ ver : 3;
+ u_int8_t m4_75 : 1,
+ m5_15 : 1,
+ m5_90 : 1,
+ m6_70 : 1,
+ m7_40 : 1,
+ m7_95 : 1,
+ m10_2 : 1,
+ m12_2 : 1;
+} __attribute__((packed));
+
+/* Chapter 10.5.2.30 */
+struct gsm48_req_ref {
+ u_int8_t ra;
+ u_int8_t t3_high:3,
+ t1_:5;
+ u_int8_t t2:5,
+ t3_low:3;
+} __attribute__ ((packed));
+
+/*
+ * Chapter 9.1.5/9.1.6
+ *
+ * For 9.1.6 the chan_desc has the meaning of 10.5.2.5a
+ */
+struct gsm48_chan_mode_modify {
+ struct gsm48_chan_desc chan_desc;
+ u_int8_t mode;
+} __attribute__ ((packed));
+
+enum gsm48_chan_mode {
+ GSM48_CMODE_SIGN = 0x00,
+ GSM48_CMODE_SPEECH_V1 = 0x01,
+ GSM48_CMODE_SPEECH_EFR = 0x21,
+ GSM48_CMODE_SPEECH_AMR = 0x41,
+ GSM48_CMODE_DATA_14k5 = 0x0f,
+ GSM48_CMODE_DATA_12k0 = 0x03,
+ GSM48_CMODE_DATA_6k0 = 0x0b,
+ GSM48_CMODE_DATA_3k6 = 0x23,
+};
+
+/* Chapter 9.1.2 */
+struct gsm48_ass_cmd {
+ /* Semantic is from 10.5.2.5a */
+ struct gsm48_chan_desc chan_desc;
+ u_int8_t power_command;
+ u_int8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 10.5.2.2 */
+struct gsm48_cell_desc {
+ u_int8_t bcc:3,
+ ncc:3,
+ arfcn_hi:2;
+ u_int8_t arfcn_lo;
+} __attribute__((packed));
+
+/* Chapter 9.1.15 */
+struct gsm48_ho_cmd {
+ struct gsm48_cell_desc cell_desc;
+ struct gsm48_chan_desc chan_desc;
+ u_int8_t ho_ref;
+ u_int8_t power_command;
+ u_int8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 9.1.18 */
+struct gsm48_imm_ass {
+ u_int8_t l2_plen;
+ u_int8_t proto_discr;
+ u_int8_t msg_type;
+ u_int8_t page_mode;
+ struct gsm48_chan_desc chan_desc;
+ struct gsm48_req_ref req_ref;
+ u_int8_t timing_advance;
+ u_int8_t mob_alloc_len;
+ u_int8_t mob_alloc[0];
+} __attribute__ ((packed));
+
+/* Chapter 10.5.1.3 */
+struct gsm48_loc_area_id {
+ u_int8_t digits[3]; /* BCD! */
+ u_int16_t lac;
+} __attribute__ ((packed));
+
+/* Section 9.2.2 */
+struct gsm48_auth_req {
+ u_int8_t key_seq:4,
+ spare:4;
+ u_int8_t rand[16];
+} __attribute__ ((packed));
+
+/* Section 9.2.15 */
+struct gsm48_loc_upd_req {
+ u_int8_t type:4,
+ key_seq:4;
+ struct gsm48_loc_area_id lai;
+ struct gsm48_classmark1 classmark1;
+ u_int8_t mi_len;
+ u_int8_t mi[0];
+} __attribute__ ((packed));
+
+/* Section 10.1 */
+struct gsm48_hdr {
+ u_int8_t proto_discr;
+ u_int8_t msg_type;
+ u_int8_t data[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.3x System information Type header */
+struct gsm48_system_information_type_header {
+ u_int8_t l2_plen;
+ u_int8_t rr_protocol_discriminator :4,
+ skip_indicator:4;
+ u_int8_t system_information;
+} __attribute__ ((packed));
+
+struct gsm48_rach_control {
+ u_int8_t re :1,
+ cell_bar :1,
+ tx_integer :4,
+ max_trans :2;
+ u_int8_t t2;
+ u_int8_t t3;
+} __attribute__ ((packed));
+
+/* Section 10.5.2.4 Cell Selection Parameters */
+struct gsm48_cell_sel_par {
+ u_int8_t ms_txpwr_max_ccch:5, /* GSM 05.08 MS-TXPWR-MAX-CCCH */
+ cell_resel_hyst:3; /* GSM 05.08 CELL-RESELECT-HYSTERESIS */
+ u_int8_t rxlev_acc_min:6, /* GSM 05.08 RXLEV-ACCESS-MIN */
+ neci:1,
+ acs:1;
+} __attribute__ ((packed));
+
+/* Section 10.5.2.11 Control Channel Description , Figure 10.5.33 */
+struct gsm48_control_channel_descr {
+ u_int8_t ccch_conf :3,
+ bs_ag_blks_res :3,
+ att :1,
+ spare1 :1;
+ u_int8_t bs_pa_mfrms : 3,
+ spare2 :5;
+ u_int8_t t3212;
+} __attribute__ ((packed));
+
+struct gsm48_cell_options {
+ u_int8_t radio_link_timeout:4,
+ dtx:2,
+ pwrc:1,
+ spare:1;
+} __attribute__ ((packed));
+
+/* Section 9.2.9 CM service request */
+struct gsm48_service_request {
+ u_int8_t cm_service_type : 4,
+ cipher_key_seq : 4;
+ /* length + 3 bytes */
+ u_int32_t classmark;
+ u_int8_t mi_len;
+ u_int8_t mi[0];
+ /* optional priority level */
+} __attribute__ ((packed));
+
+/* Section 9.1.31 System information Type 1 */
+struct gsm48_system_information_type_1 {
+ struct gsm48_system_information_type_header header;
+ u_int8_t cell_channel_description[16];
+ struct gsm48_rach_control rach_control;
+ u_int8_t rest_octets[0]; /* NCH position on the CCCH */
+} __attribute__ ((packed));
+
+/* Section 9.1.32 System information Type 2 */
+struct gsm48_system_information_type_2 {
+ struct gsm48_system_information_type_header header;
+ u_int8_t bcch_frequency_list[16];
+ u_int8_t ncc_permitted;
+ struct gsm48_rach_control rach_control;
+} __attribute__ ((packed));
+
+/* Section 9.1.35 System information Type 3 */
+struct gsm48_system_information_type_3 {
+ struct gsm48_system_information_type_header header;
+ u_int16_t cell_identity;
+ struct gsm48_loc_area_id lai;
+ struct gsm48_control_channel_descr control_channel_desc;
+ struct gsm48_cell_options cell_options;
+ struct gsm48_cell_sel_par cell_sel_par;
+ struct gsm48_rach_control rach_control;
+ u_int8_t rest_octets[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.36 System information Type 4 */
+struct gsm48_system_information_type_4 {
+ struct gsm48_system_information_type_header header;
+ struct gsm48_loc_area_id lai;
+ struct gsm48_cell_sel_par cell_sel_par;
+ struct gsm48_rach_control rach_control;
+ /* optional CBCH conditional CBCH... followed by
+ mandantory SI 4 Reset Octets
+ */
+ u_int8_t data[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.37 System information Type 5 */
+struct gsm48_system_information_type_5 {
+ u_int8_t rr_protocol_discriminator :4,
+ skip_indicator:4;
+ u_int8_t system_information;
+ u_int8_t bcch_frequency_list[16];
+} __attribute__ ((packed));
+
+/* Section 9.1.40 System information Type 6 */
+struct gsm48_system_information_type_6 {
+ u_int8_t rr_protocol_discriminator :4,
+ skip_indicator:4;
+ u_int8_t system_information;
+ u_int16_t cell_identity;
+ struct gsm48_loc_area_id lai;
+ struct gsm48_cell_options cell_options;
+ u_int8_t ncc_permitted;
+ u_int8_t rest_octets[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.43a System Information type 13 */
+struct gsm48_system_information_type_13 {
+ struct gsm48_system_information_type_header header;
+ u_int8_t rest_octets[0];
+} __attribute__ ((packed));
+
+/* Section 9.2.12 IMSI Detach Indication */
+struct gsm48_imsi_detach_ind {
+ struct gsm48_classmark1 classmark1;
+ u_int8_t mi_len;
+ u_int8_t mi[0];
+} __attribute__ ((packed));
+
+/* Section 10.2 + GSM 04.07 12.2.3.1.1 */
+#define GSM48_PDISC_GROUP_CC 0x00
+#define GSM48_PDISC_BCAST_CC 0x01
+#define GSM48_PDISC_PDSS1 0x02
+#define GSM48_PDISC_CC 0x03
+#define GSM48_PDISC_PDSS2 0x04
+#define GSM48_PDISC_MM 0x05
+#define GSM48_PDISC_RR 0x06
+#define GSM48_PDISC_MM_GPRS 0x08
+#define GSM48_PDISC_SMS 0x09
+#define GSM48_PDISC_SM_GPRS 0x0a
+#define GSM48_PDISC_NC_SS 0x0b
+#define GSM48_PDISC_LOC 0x0c
+#define GSM48_PDISC_MASK 0x0f
+#define GSM48_PDISC_USSD 0x11
+
+/* Section 10.4 */
+#define GSM48_MT_RR_INIT_REQ 0x3c
+#define GSM48_MT_RR_ADD_ASS 0x3b
+#define GSM48_MT_RR_IMM_ASS 0x3f
+#define GSM48_MT_RR_IMM_ASS_EXT 0x39
+#define GSM48_MT_RR_IMM_ASS_REJ 0x3a
+
+#define GSM48_MT_RR_CIPH_M_CMD 0x35
+#define GSM48_MT_RR_CIPH_M_COMPL 0x32
+
+#define GSM48_MT_RR_CFG_CHG_CMD 0x30
+#define GSM48_MT_RR_CFG_CHG_ACK 0x31
+#define GSM48_MT_RR_CFG_CHG_REJ 0x33
+
+#define GSM48_MT_RR_ASS_CMD 0x2e
+#define GSM48_MT_RR_ASS_COMPL 0x29
+#define GSM48_MT_RR_ASS_FAIL 0x2f
+#define GSM48_MT_RR_HANDO_CMD 0x2b
+#define GSM48_MT_RR_HANDO_COMPL 0x2c
+#define GSM48_MT_RR_HANDO_FAIL 0x28
+#define GSM48_MT_RR_HANDO_INFO 0x2d
+
+#define GSM48_MT_RR_CELL_CHG_ORDER 0x08
+#define GSM48_MT_RR_PDCH_ASS_CMD 0x23
+
+#define GSM48_MT_RR_CHAN_REL 0x0d
+#define GSM48_MT_RR_PART_REL 0x0a
+#define GSM48_MT_RR_PART_REL_COMP 0x0f
+
+#define GSM48_MT_RR_PAG_REQ_1 0x21
+#define GSM48_MT_RR_PAG_REQ_2 0x22
+#define GSM48_MT_RR_PAG_REQ_3 0x24
+#define GSM48_MT_RR_PAG_RESP 0x27
+#define GSM48_MT_RR_NOTIF_NCH 0x20
+#define GSM48_MT_RR_NOTIF_FACCH 0x25
+#define GSM48_MT_RR_NOTIF_RESP 0x26
+
+#define GSM48_MT_RR_SYSINFO_8 0x18
+#define GSM48_MT_RR_SYSINFO_1 0x19
+#define GSM48_MT_RR_SYSINFO_2 0x1a
+#define GSM48_MT_RR_SYSINFO_3 0x1b
+#define GSM48_MT_RR_SYSINFO_4 0x1c
+#define GSM48_MT_RR_SYSINFO_5 0x1d
+#define GSM48_MT_RR_SYSINFO_6 0x1e
+#define GSM48_MT_RR_SYSINFO_7 0x1f
+
+#define GSM48_MT_RR_SYSINFO_2bis 0x02
+#define GSM48_MT_RR_SYSINFO_2ter 0x03
+#define GSM48_MT_RR_SYSINFO_5bis 0x05
+#define GSM48_MT_RR_SYSINFO_5ter 0x06
+#define GSM48_MT_RR_SYSINFO_9 0x04
+#define GSM48_MT_RR_SYSINFO_13 0x00
+
+#define GSM48_MT_RR_SYSINFO_16 0x3d
+#define GSM48_MT_RR_SYSINFO_17 0x3e
+
+#define GSM48_MT_RR_CHAN_MODE_MODIF 0x10
+#define GSM48_MT_RR_STATUS 0x12
+#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK 0x17
+#define GSM48_MT_RR_FREQ_REDEF 0x14
+#define GSM48_MT_RR_MEAS_REP 0x15
+#define GSM48_MT_RR_CLSM_CHG 0x16
+#define GSM48_MT_RR_CLSM_ENQ 0x13
+#define GSM48_MT_RR_EXT_MEAS_REP 0x36
+#define GSM48_MT_RR_EXT_MEAS_REP_ORD 0x37
+#define GSM48_MT_RR_GPRS_SUSP_REQ 0x34
+
+#define GSM48_MT_RR_VGCS_UPL_GRANT 0x08
+#define GSM48_MT_RR_UPLINK_RELEASE 0x0e
+#define GSM48_MT_RR_UPLINK_FREE 0x0c
+#define GSM48_MT_RR_UPLINK_BUSY 0x2a
+#define GSM48_MT_RR_TALKER_IND 0x11
+
+#define GSM48_MT_RR_APP_INFO 0x38
+
+/* Table 10.2/3GPP TS 04.08 */
+#define GSM48_MT_MM_IMSI_DETACH_IND 0x01
+#define GSM48_MT_MM_LOC_UPD_ACCEPT 0x02
+#define GSM48_MT_MM_LOC_UPD_REJECT 0x04
+#define GSM48_MT_MM_LOC_UPD_REQUEST 0x08
+
+#define GSM48_MT_MM_AUTH_REJ 0x11
+#define GSM48_MT_MM_AUTH_REQ 0x12
+#define GSM48_MT_MM_AUTH_RESP 0x14
+#define GSM48_MT_MM_ID_REQ 0x18
+#define GSM48_MT_MM_ID_RESP 0x19
+#define GSM48_MT_MM_TMSI_REALL_CMD 0x1a
+#define GSM48_MT_MM_TMSI_REALL_COMPL 0x1b
+
+#define GSM48_MT_MM_CM_SERV_ACC 0x21
+#define GSM48_MT_MM_CM_SERV_REJ 0x22
+#define GSM48_MT_MM_CM_SERV_ABORT 0x23
+#define GSM48_MT_MM_CM_SERV_REQ 0x24
+#define GSM48_MT_MM_CM_SERV_PROMPT 0x25
+#define GSM48_MT_MM_CM_REEST_REQ 0x28
+#define GSM48_MT_MM_ABORT 0x29
+
+#define GSM48_MT_MM_NULL 0x30
+#define GSM48_MT_MM_STATUS 0x31
+#define GSM48_MT_MM_INFO 0x32
+
+/* Table 10.3/3GPP TS 04.08 */
+#define GSM48_MT_CC_ALERTING 0x01
+#define GSM48_MT_CC_CALL_CONF 0x08
+#define GSM48_MT_CC_CALL_PROC 0x02
+#define GSM48_MT_CC_CONNECT 0x07
+#define GSM48_MT_CC_CONNECT_ACK 0x0f
+#define GSM48_MT_CC_EMERG_SETUP 0x0e
+#define GSM48_MT_CC_PROGRESS 0x03
+#define GSM48_MT_CC_ESTAB 0x04
+#define GSM48_MT_CC_ESTAB_CONF 0x06
+#define GSM48_MT_CC_RECALL 0x0b
+#define GSM48_MT_CC_START_CC 0x09
+#define GSM48_MT_CC_SETUP 0x05
+
+#define GSM48_MT_CC_MODIFY 0x17
+#define GSM48_MT_CC_MODIFY_COMPL 0x1f
+#define GSM48_MT_CC_MODIFY_REJECT 0x13
+#define GSM48_MT_CC_USER_INFO 0x10
+#define GSM48_MT_CC_HOLD 0x18
+#define GSM48_MT_CC_HOLD_ACK 0x19
+#define GSM48_MT_CC_HOLD_REJ 0x1a
+#define GSM48_MT_CC_RETR 0x1c
+#define GSM48_MT_CC_RETR_ACK 0x1d
+#define GSM48_MT_CC_RETR_REJ 0x1e
+
+#define GSM48_MT_CC_DISCONNECT 0x25
+#define GSM48_MT_CC_RELEASE 0x2d
+#define GSM48_MT_CC_RELEASE_COMPL 0x2a
+
+#define GSM48_MT_CC_CONG_CTRL 0x39
+#define GSM48_MT_CC_NOTIFY 0x3e
+#define GSM48_MT_CC_STATUS 0x3d
+#define GSM48_MT_CC_STATUS_ENQ 0x34
+#define GSM48_MT_CC_START_DTMF 0x35
+#define GSM48_MT_CC_STOP_DTMF 0x31
+#define GSM48_MT_CC_STOP_DTMF_ACK 0x32
+#define GSM48_MT_CC_START_DTMF_ACK 0x36
+#define GSM48_MT_CC_START_DTMF_REJ 0x37
+#define GSM48_MT_CC_FACILITY 0x3a
+
+/* FIXME: Table 10.4 / 10.4a (GPRS) */
+
+/* Section 10.5.2.26, Table 10.5.64 */
+#define GSM48_PM_MASK 0x03
+#define GSM48_PM_NORMAL 0x00
+#define GSM48_PM_EXTENDED 0x01
+#define GSM48_PM_REORG 0x02
+#define GSM48_PM_SAME 0x03
+
+/* Chapter 10.5.3.5 / Table 10.5.93 */
+#define GSM48_LUPD_NORMAL 0x0
+#define GSM48_LUPD_PERIODIC 0x1
+#define GSM48_LUPD_IMSI_ATT 0x2
+#define GSM48_LUPD_RESERVED 0x3
+
+/* Table 10.5.4 */
+#define GSM_MI_TYPE_MASK 0x07
+#define GSM_MI_TYPE_NONE 0x00
+#define GSM_MI_TYPE_IMSI 0x01
+#define GSM_MI_TYPE_IMEI 0x02
+#define GSM_MI_TYPE_IMEISV 0x03
+#define GSM_MI_TYPE_TMSI 0x04
+#define GSM_MI_ODD 0x08
+
+#define GSM48_IE_MUL_RATE_CFG 0x03 /* 10.5.2.21aa */
+#define GSM48_IE_MOBILE_ID 0x17
+#define GSM48_IE_NAME_LONG 0x43 /* 10.5.3.5a */
+#define GSM48_IE_NAME_SHORT 0x45 /* 10.5.3.5a */
+#define GSM48_IE_UTC 0x46 /* 10.5.3.8 */
+#define GSM48_IE_NET_TIME_TZ 0x47 /* 10.5.3.9 */
+#define GSM48_IE_LSA_IDENT 0x48 /* 10.5.3.11 */
+
+#define GSM48_IE_BEARER_CAP 0x04 /* 10.5.4.5 */
+#define GSM48_IE_CAUSE 0x08 /* 10.5.4.11 */
+#define GSM48_IE_CC_CAP 0x15 /* 10.5.4.5a */
+#define GSM48_IE_ALERT 0x19 /* 10.5.4.26 */
+#define GSM48_IE_FACILITY 0x1c /* 10.5.4.15 */
+#define GSM48_IE_PROGR_IND 0x1e /* 10.5.4.21 */
+#define GSM48_IE_AUX_STATUS 0x24 /* 10.5.4.4 */
+#define GSM48_IE_NOTIFY 0x27 /* 10.5.4.20 */
+#define GSM48_IE_KPD_FACILITY 0x2c /* 10.5.4.17 */
+#define GSM48_IE_SIGNAL 0x34 /* 10.5.4.23 */
+#define GSM48_IE_CONN_BCD 0x4c /* 10.5.4.13 */
+#define GSM48_IE_CONN_SUB 0x4d /* 10.5.4.14 */
+#define GSM48_IE_CALLING_BCD 0x5c /* 10.5.4.9 */
+#define GSM48_IE_CALLING_SUB 0x5d /* 10.5.4.10 */
+#define GSM48_IE_CALLED_BCD 0x5e /* 10.5.4.7 */
+#define GSM48_IE_CALLED_SUB 0x6d /* 10.5.4.8 */
+#define GSM48_IE_REDIR_BCD 0x74 /* 10.5.4.21a */
+#define GSM48_IE_REDIR_SUB 0x75 /* 10.5.4.21b */
+#define GSM48_IE_LOWL_COMPAT 0x7c /* 10.5.4.18 */
+#define GSM48_IE_HIGHL_COMPAT 0x7d /* 10.5.4.16 */
+#define GSM48_IE_USER_USER 0x7e /* 10.5.4.25 */
+#define GSM48_IE_SS_VERS 0x7f /* 10.5.4.24 */
+#define GSM48_IE_MORE_DATA 0xa0 /* 10.5.4.19 */
+#define GSM48_IE_CLIR_SUPP 0xa1 /* 10.5.4.11a */
+#define GSM48_IE_CLIR_INVOC 0xa2 /* 10.5.4.11b */
+#define GSM48_IE_REV_C_SETUP 0xa3 /* 10.5.4.22a */
+#define GSM48_IE_REPEAT_CIR 0xd1 /* 10.5.4.22 */
+#define GSM48_IE_REPEAT_SEQ 0xd3 /* 10.5.4.22 */
+
+/* Section 10.5.4.11 / Table 10.5.122 */
+#define GSM48_CAUSE_CS_GSM 0x60
+
+/* Section 9.1.2 / Table 9.3 */
+#define GSM48_IE_FRQLIST_AFTER 0x05
+#define GSM48_IE_CELL_CH_DESC 0x62
+#define GSM48_IE_MSLOT_DESC 0x10
+#define GSM48_IE_CHANMODE_1 0x63
+#define GSM48_IE_CHANMODE_2 0x11
+#define GSM48_IE_CHANMODE_3 0x13
+#define GSM48_IE_CHANMODE_4 0x14
+#define GSM48_IE_CHANMODE_5 0x15
+#define GSM48_IE_CHANMODE_6 0x16
+#define GSM48_IE_CHANMODE_7 0x17
+#define GSM48_IE_CHANMODE_8 0x18
+#define GSM48_IE_CHANDESC_2 0x64
+/* FIXME */
+
+/* Section 10.5.4.23 / Table 10.5.130 */
+enum gsm48_signal_val {
+ GSM48_SIGNAL_DIALTONE = 0x00,
+ GSM48_SIGNAL_RINGBACK = 0x01,
+ GSM48_SIGNAL_INTERCEPT = 0x02,
+ GSM48_SIGNAL_NET_CONG = 0x03,
+ GSM48_SIGNAL_BUSY = 0x04,
+ GSM48_SIGNAL_CONFIRM = 0x05,
+ GSM48_SIGNAL_ANSWER = 0x06,
+ GSM48_SIGNAL_CALL_WAIT = 0x07,
+ GSM48_SIGNAL_OFF_HOOK = 0x08,
+ GSM48_SIGNAL_OFF = 0x3f,
+ GSM48_SIGNAL_ALERT_OFF = 0x4f,
+};
+
+enum gsm48_cause_loc {
+ GSM48_CAUSE_LOC_USER = 0x00,
+ GSM48_CAUSE_LOC_PRN_S_LU = 0x01,
+ GSM48_CAUSE_LOC_PUN_S_LU = 0x02,
+ GSM48_CAUSE_LOC_TRANS_NET = 0x03,
+ GSM48_CAUSE_LOC_PUN_S_RU = 0x04,
+ GSM48_CAUSE_LOC_PRN_S_RU = 0x05,
+ /* not defined */
+ GSM48_CAUSE_LOC_INN_NET = 0x07,
+ GSM48_CAUSE_LOC_NET_BEYOND = 0x0a,
+};
+
+/* Section 10.5.2.31 RR Cause / Table 10.5.70 */
+enum gsm48_rr_cause {
+ GSM48_RR_CAUSE_NORMAL = 0x00,
+ GSM48_RR_CAUSE_ABNORMAL_UNSPEC = 0x01,
+ GSM48_RR_CAUSE_ABNORMAL_UNACCT = 0x02,
+ GSM48_RR_CAUSE_ABNORMAL_TIMER = 0x03,
+ GSM48_RR_CAUSE_ABNORMAL_NOACT = 0x04,
+ GSM48_RR_CAUSE_PREMPTIVE_REL = 0x05,
+ GSM48_RR_CAUSE_HNDOVER_IMP = 0x06,
+ GSM48_RR_CAUSE_CHAN_MODE_UNACCT = 0x07,
+ GSM48_RR_CAUSE_FREQ_NOT_IMPL = 0x08,
+ GSM48_RR_CAUSE_CALL_CLEARED = 0x41,
+ GSM48_RR_CAUSE_SEMANT_INCORR = 0x5f,
+ GSM48_RR_CAUSE_INVALID_MAND_INF = 0x60,
+ GSM48_RR_CAUSE_MSG_TYPE_N = 0x61,
+ GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT= 0x62,
+ GSM48_RR_CAUSE_COND_IE_ERROR = 0x64,
+ GSM48_RR_CAUSE_NO_CELL_ALLOC_A = 0x65,
+ GSM48_RR_CAUSE_PROT_ERROR_UNSPC = 0x6f,
+};
+
+/* Section 10.5.4.11 CC Cause / Table 10.5.123 */
+enum gsm48_cc_cause {
+ GSM48_CC_CAUSE_UNASSIGNED_NR = 1,
+ GSM48_CC_CAUSE_NO_ROUTE = 3,
+ GSM48_CC_CAUSE_CHAN_UNACCEPT = 6,
+ GSM48_CC_CAUSE_OP_DET_BARRING = 8,
+ GSM48_CC_CAUSE_NORM_CALL_CLEAR = 16,
+ GSM48_CC_CAUSE_USER_BUSY = 17,
+ GSM48_CC_CAUSE_USER_NOTRESPOND = 18,
+ GSM48_CC_CAUSE_USER_ALERTING_NA = 19,
+ GSM48_CC_CAUSE_CALL_REJECTED = 21,
+ GSM48_CC_CAUSE_NUMBER_CHANGED = 22,
+ GSM48_CC_CAUSE_PRE_EMPTION = 25,
+ GSM48_CC_CAUSE_NONSE_USER_CLR = 26,
+ GSM48_CC_CAUSE_DEST_OOO = 27,
+ GSM48_CC_CAUSE_INV_NR_FORMAT = 28,
+ GSM48_CC_CAUSE_FACILITY_REJ = 29,
+ GSM48_CC_CAUSE_RESP_STATUS_INQ = 30,
+ GSM48_CC_CAUSE_NORMAL_UNSPEC = 31,
+ GSM48_CC_CAUSE_NO_CIRCUIT_CHAN = 34,
+ GSM48_CC_CAUSE_NETWORK_OOO = 38,
+ GSM48_CC_CAUSE_TEMP_FAILURE = 41,
+ GSM48_CC_CAUSE_SWITCH_CONG = 42,
+ GSM48_CC_CAUSE_ACC_INF_DISCARD = 43,
+ GSM48_CC_CAUSE_REQ_CHAN_UNAVAIL = 44,
+ GSM48_CC_CAUSE_RESOURCE_UNAVAIL = 47,
+ GSM48_CC_CAUSE_QOS_UNAVAIL = 49,
+ GSM48_CC_CAUSE_REQ_FAC_NOT_SUBSC= 50,
+ GSM48_CC_CAUSE_INC_BARRED_CUG = 55,
+ GSM48_CC_CAUSE_BEARER_CAP_UNAUTH= 57,
+ GSM48_CC_CAUSE_BEARER_CA_UNAVAIL= 58,
+ GSM48_CC_CAUSE_SERV_OPT_UNAVAIL = 63,
+ GSM48_CC_CAUSE_BEARERSERV_UNIMPL= 65,
+ GSM48_CC_CAUSE_ACM_GE_ACM_MAX = 68,
+ GSM48_CC_CAUSE_REQ_FAC_NOTIMPL = 69,
+ GSM48_CC_CAUSE_RESTR_BCAP_AVAIL = 70,
+ GSM48_CC_CAUSE_SERV_OPT_UNIMPL = 79,
+ GSM48_CC_CAUSE_INVAL_TRANS_ID = 81,
+ GSM48_CC_CAUSE_USER_NOT_IN_CUG = 87,
+ GSM48_CC_CAUSE_INCOMPAT_DEST = 88,
+ GSM48_CC_CAUSE_INVAL_TRANS_NET = 91,
+ GSM48_CC_CAUSE_SEMANTIC_INCORR = 95,
+ GSM48_CC_CAUSE_INVAL_MAND_INF = 96,
+ GSM48_CC_CAUSE_MSGTYPE_NOTEXIST = 97,
+ GSM48_CC_CAUSE_MSGTYPE_INCOMPAT = 98,
+ GSM48_CC_CAUSE_IE_NOTEXIST = 99,
+ GSM48_CC_CAUSE_COND_IE_ERR = 100,
+ GSM48_CC_CAUSE_MSG_INCOMP_STATE = 101,
+ GSM48_CC_CAUSE_RECOVERY_TIMER = 102,
+ GSM48_CC_CAUSE_PROTO_ERR = 111,
+ GSM48_CC_CAUSE_INTERWORKING = 127,
+};
+
+/* Annex G, GSM specific cause values for mobility management */
+enum gsm48_reject_value {
+ GSM48_REJECT_IMSI_UNKNOWN_IN_HLR = 2,
+ GSM48_REJECT_ILLEGAL_MS = 3,
+ GSM48_REJECT_IMSI_UNKNOWN_IN_VLR = 4,
+ GSM48_REJECT_IMEI_NOT_ACCEPTED = 5,
+ GSM48_REJECT_ILLEGAL_ME = 6,
+ GSM48_REJECT_PLMN_NOT_ALLOWED = 11,
+ GSM48_REJECT_LOC_NOT_ALLOWED = 12,
+ GSM48_REJECT_ROAMING_NOT_ALLOWED = 13,
+ GSM48_REJECT_NETWORK_FAILURE = 17,
+ GSM48_REJECT_CONGESTION = 22,
+ GSM48_REJECT_SRV_OPT_NOT_SUPPORTED = 32,
+ GSM48_REJECT_RQD_SRV_OPT_NOT_SUPPORTED = 33,
+ GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER = 34,
+ GSM48_REJECT_CALL_CAN_NOT_BE_IDENTIFIED = 38,
+ GSM48_REJECT_INCORRECT_MESSAGE = 95,
+ GSM48_REJECT_INVALID_MANDANTORY_INF = 96,
+ GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED = 97,
+ GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE = 98,
+ GSM48_REJECT_INF_ELEME_NOT_IMPLEMENTED = 99,
+ GSM48_REJECT_CONDTIONAL_IE_ERROR = 100,
+ GSM48_REJECT_MSG_NOT_COMPATIBLE = 101,
+ GSM48_REJECT_PROTOCOL_ERROR = 111,
+
+ /* according to G.6 Additional cause codes for GMM */
+ GSM48_REJECT_GPRS_NOT_ALLOWED = 7,
+ GSM48_REJECT_SERVICES_NOT_ALLOWED = 8,
+ GSM48_REJECT_MS_IDENTITY_NOT_DERVIVABLE = 9,
+ GSM48_REJECT_IMPLICITLY_DETACHED = 10,
+ GSM48_REJECT_GPRS_NOT_ALLOWED_IN_PLMN = 14,
+ GSM48_REJECT_MSC_TMP_NOT_REACHABLE = 16,
+};
+
+enum chreq_type {
+ CHREQ_T_EMERG_CALL,
+ CHREQ_T_CALL_REEST_TCH_F,
+ CHREQ_T_CALL_REEST_TCH_H,
+ CHREQ_T_CALL_REEST_TCH_H_DBL,
+ CHREQ_T_SDCCH,
+ CHREQ_T_TCH_F,
+ CHREQ_T_VOICE_CALL_TCH_H,
+ CHREQ_T_DATA_CALL_TCH_H,
+ CHREQ_T_LOCATION_UPD,
+ CHREQ_T_PAG_R_ANY_NECI0,
+ CHREQ_T_PAG_R_ANY_NECI1,
+ CHREQ_T_PAG_R_TCH_F,
+ CHREQ_T_PAG_R_TCH_FH,
+ CHREQ_T_LMU,
+ CHREQ_T_RESERVED_SDCCH,
+ CHREQ_T_RESERVED_IGNORE,
+};
+
+/* Chapter 11.3 */
+#define GSM48_T301 180, 0
+#define GSM48_T303 30, 0
+#define GSM48_T305 30, 0
+#define GSM48_T306 30, 0
+#define GSM48_T308 10, 0
+#define GSM48_T310 180, 0
+#define GSM48_T313 30, 0
+#define GSM48_T323 30, 0
+#define GSM48_T331 30, 0
+#define GSM48_T333 30, 0
+#define GSM48_T334 25, 0 /* min 15 */
+#define GSM48_T338 30, 0
+
+/* Chapter 5.1.2.2 */
+#define GSM_CSTATE_NULL 0
+#define GSM_CSTATE_INITIATED 1
+#define GSM_CSTATE_MO_CALL_PROC 3
+#define GSM_CSTATE_CALL_DELIVERED 4
+#define GSM_CSTATE_CALL_PRESENT 6
+#define GSM_CSTATE_CALL_RECEIVED 7
+#define GSM_CSTATE_CONNECT_REQUEST 8
+#define GSM_CSTATE_MO_TERM_CALL_CONF 9
+#define GSM_CSTATE_ACTIVE 10
+#define GSM_CSTATE_DISCONNECT_REQ 12
+#define GSM_CSTATE_DISCONNECT_IND 12
+#define GSM_CSTATE_RELEASE_REQ 19
+#define GSM_CSTATE_MO_ORIG_MODIFY 26
+#define GSM_CSTATE_MO_TERM_MODIFY 27
+#define GSM_CSTATE_CONNECT_IND 28
+
+#define SBIT(a) (1 << a)
+#define ALL_STATES 0xffffffff
+
+/* Table 10.5.3/3GPP TS 04.08: Location Area Identification information element */
+#define GSM_LAC_RESERVED_DETACHED 0x0
+#define GSM_LAC_RESERVED_ALL_BTS 0xfffe
+
+/* GSM 04.08 Bearer Capability: Information Transfer Capability */
+enum gsm48_bcap_itcap {
+ GSM48_BCAP_ITCAP_SPEECH = 0,
+ GSM48_BCAP_ITCAP_UNR_DIG_INF = 1,
+ GSM48_BCAP_ITCAP_3k1_AUDIO = 2,
+ GSM48_BCAP_ITCAP_FAX_G3 = 3,
+ GSM48_BCAP_ITCAP_OTHER = 5,
+ GSM48_BCAP_ITCAP_RESERVED = 7,
+};
+
+/* GSM 04.08 Bearer Capability: Transfer Mode */
+enum gsm48_bcap_tmod {
+ GSM48_BCAP_TMOD_CIRCUIT = 0,
+ GSM48_BCAP_TMOD_PACKET = 1,
+};
+
+/* GSM 04.08 Bearer Capability: Coding Standard */
+enum gsm48_bcap_coding {
+ GSM48_BCAP_CODING_GSM_STD = 0,
+};
+
+/* GSM 04.08 Bearer Capability: Radio Channel Requirements */
+enum gsm48_bcap_rrq {
+ GSM48_BCAP_RRQ_FR_ONLY = 1,
+ GSM48_BCAP_RRQ_DUAL_HR = 2,
+ GSM48_BCAP_RRQ_DUAL_FR = 3,
+};
+
+
+#define GSM48_TMSI_LEN 5
+#define GSM48_MID_TMSI_LEN (GSM48_TMSI_LEN + 2)
+#define GSM48_MI_SIZE 32
+
+
+struct msgb;
+struct gsm_bts;
+struct gsm_subscriber;
+struct gsm_network;
+struct gsm_trans;
+
+/* config options controlling the behaviour of the lower leves */
+void gsm0408_allow_everyone(int allow);
+
+int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id);
+void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
+ u_int16_t mnc, u_int16_t lac);
+enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
+enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
+
+int gsm48_tx_mm_info(struct gsm_lchan *lchan);
+int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq);
+int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan);
+struct msgb *gsm48_msgb_alloc(void);
+int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans);
+int gsm48_generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
+int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char* imsi);
+int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len);
+
+int gsm48_send_rr_release(struct gsm_lchan *lchan);
+int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
+int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
+ u_int8_t apdu_len, const u_int8_t *apdu);
+int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_class);
+int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
+ u_int8_t power_command, u_int8_t ho_ref);
+
+int bsc_upqueue(struct gsm_network *net);
+
+int mncc_send(struct gsm_network *net, int msg_type, void *arg);
+
+/* convert a ASCII phone number to call-control BCD */
+int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
+ int h_len, const char *input);
+int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
+ int h_len);
+
+extern const char *gsm0408_cc_msg_names[];
+
+int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
+int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
+int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
+
+int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode);
+int gsm48_rx_rr_modif_ack(struct msgb *msg);
+int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg);
+
+
+#endif
diff --git a/src/host/libosmocom/include/osmocom/gsmtap.h b/src/host/libosmocom/include/osmocom/gsmtap.h
new file mode 100644
index 00000000..316e73d1
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/gsmtap.h
@@ -0,0 +1,60 @@
+#ifndef _GSMTAP_H
+#define _GSMTAP_H
+
+/* gsmtap header, pseudo-header in front of the actua GSM payload*/
+
+#include <sys/types.h>
+
+#define GSMTAP_VERSION 0x01
+
+#define GSMTAP_TYPE_UM 0x01
+#define GSMTAP_TYPE_ABIS 0x02
+#define GSMTAP_TYPE_UM_BURST 0x03 /* raw burst bits */
+
+#define GSMTAP_BURST_UNKNOWN 0x00
+#define GSMTAP_BURST_FCCH 0x01
+#define GSMTAP_BURST_PARTIAL_SCH 0x02
+#define GSMTAP_BURST_SCH 0x03
+#define GSMTAP_BURST_CTS_SCH 0x04
+#define GSMTAP_BURST_COMPACT_SCH 0x05
+#define GSMTAP_BURST_NORMAL 0x06
+#define GSMTAP_BURST_DUMMY 0x07
+#define GSMTAP_BURST_ACCESS 0x08
+#define GSMTAP_BURST_NONE 0x09
+
+struct gsmtap_hdr {
+ u_int8_t version; /* version, set to 0x01 currently */
+ u_int8_t hdr_len; /* length in number of 32bit words */
+ u_int8_t type; /* see GSMTAP_TYPE_* */
+ u_int8_t timeslot; /* timeslot (0..7 on Um) */
+
+ u_int16_t arfcn; /* ARFCN (frequency) */
+ u_int8_t noise_db; /* noise figure in dB */
+ u_int8_t signal_db; /* signal level in dB */
+
+ u_int32_t frame_number; /* GSM Frame Number (FN) */
+
+ u_int8_t burst_type; /* Type of burst, see above */
+ u_int8_t antenna_nr; /* Antenna Number */
+ u_int16_t res; /* reserved for future use (RFU) */
+
+} __attribute__((packed));
+
+
+/* PCAP related definitions */
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+#ifndef LINKTYPE_GSMTAP
+#define LINKTYPE_GSMTAP 2342
+#endif
+struct pcap_timeval {
+ int32_t tv_sec;
+ int32_t tv_usec;
+};
+
+struct pcap_sf_pkthdr {
+ struct pcap_timeval ts; /* time stamp */
+ u_int32_t caplen; /* lenght of portion present */
+ u_int32_t len; /* length of this packet */
+};
+
+#endif /* _GSMTAP_H */
diff --git a/src/host/libosmocom/include/osmocom/linuxlist.h b/src/host/libosmocom/include/osmocom/linuxlist.h
new file mode 100644
index 00000000..6b77a31d
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/linuxlist.h
@@ -0,0 +1,360 @@
+#ifndef _LINUX_LLIST_H
+#define _LINUX_LLIST_H
+
+#include <stddef.h>
+
+#ifndef inline
+#define inline __inline__
+#endif
+
+static inline void prefetch(const void *x) {;}
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (typeof( ((type *)0)->member ) *)(ptr); \
+ (type *)( (char *)__mptr - offsetof(type, member) );})
+
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized llist entries.
+ */
+#define LLIST_POISON1 ((void *) 0x00100100)
+#define LLIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked llist implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole llists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct llist_head {
+ struct llist_head *next, *prev;
+};
+
+#define LLIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LLIST_HEAD(name) \
+ struct llist_head name = LLIST_HEAD_INIT(name)
+
+#define INIT_LLIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_add(struct llist_head *_new,
+ struct llist_head *prev,
+ struct llist_head *next)
+{
+ next->prev = _new;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+}
+
+/**
+ * llist_add - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void llist_add(struct llist_head *_new, struct llist_head *head)
+{
+ __llist_add(_new, head, head->next);
+}
+
+/**
+ * llist_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
+{
+ __llist_add(_new, head->prev, head);
+}
+
+/*
+ * Delete a llist entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * llist_del - deletes entry from llist.
+ * @entry: the element to delete from the llist.
+ * Note: llist_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void llist_del(struct llist_head *entry)
+{
+ __llist_del(entry->prev, entry->next);
+ entry->next = (struct llist_head *)LLIST_POISON1;
+ entry->prev = (struct llist_head *)LLIST_POISON2;
+}
+
+/**
+ * llist_del_init - deletes entry from llist and reinitialize it.
+ * @entry: the element to delete from the llist.
+ */
+static inline void llist_del_init(struct llist_head *entry)
+{
+ __llist_del(entry->prev, entry->next);
+ INIT_LLIST_HEAD(entry);
+}
+
+/**
+ * llist_move - delete from one llist and add as another's head
+ * @llist: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void llist_move(struct llist_head *llist, struct llist_head *head)
+{
+ __llist_del(llist->prev, llist->next);
+ llist_add(llist, head);
+}
+
+/**
+ * llist_move_tail - delete from one llist and add as another's tail
+ * @llist: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void llist_move_tail(struct llist_head *llist,
+ struct llist_head *head)
+{
+ __llist_del(llist->prev, llist->next);
+ llist_add_tail(llist, head);
+}
+
+/**
+ * llist_empty - tests whether a llist is empty
+ * @head: the llist to test.
+ */
+static inline int llist_empty(const struct llist_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __llist_splice(struct llist_head *llist,
+ struct llist_head *head)
+{
+ struct llist_head *first = llist->next;
+ struct llist_head *last = llist->prev;
+ struct llist_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * llist_splice - join two llists
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ */
+static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
+{
+ if (!llist_empty(llist))
+ __llist_splice(llist, head);
+}
+
+/**
+ * llist_splice_init - join two llists and reinitialise the emptied llist.
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ *
+ * The llist at @llist is reinitialised
+ */
+static inline void llist_splice_init(struct llist_head *llist,
+ struct llist_head *head)
+{
+ if (!llist_empty(llist)) {
+ __llist_splice(llist, head);
+ INIT_LLIST_HEAD(llist);
+ }
+}
+
+/**
+ * llist_entry - get the struct for this entry
+ * @ptr: the &struct llist_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * llist_for_each - iterate over a llist
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __llist_for_each - iterate over a llist
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ *
+ * This variant differs from llist_for_each() in that it's the
+ * simplest possible llist iteration code, no prefetching is done.
+ * Use this for code that knows the llist to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __llist_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * llist_for_each_prev - iterate over a llist backwards
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * llist_for_each_safe - iterate over a llist safe against removal of llist entry
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @n: another &struct llist_head to use as temporary storage
+ * @head: the head for your llist.
+ */
+#define llist_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * llist_for_each_entry - iterate over llist of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry(pos, head, member) \
+ for (pos = llist_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_reverse - iterate backwards over llist of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_reverse(pos, head, member) \
+ for (pos = llist_entry((head)->prev, typeof(*pos), member), \
+ prefetch(pos->member.prev); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.prev, typeof(*pos), member), \
+ prefetch(pos->member.prev))
+
+/**
+ * llist_for_each_entry_continue - iterate over llist of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_continue(pos, head, member) \
+ for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = llist_entry((head)->next, typeof(*pos), member), \
+ n = llist_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = llist_entry(n->member.next, typeof(*n), member))
+
+/**
+ * llist_for_each_rcu - iterate over an rcu-protected llist
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each_rcu(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
+
+#define __llist_for_each_rcu(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
+
+/**
+ * llist_for_each_safe_rcu - iterate over an rcu-protected llist safe
+ * against removal of llist entry
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @n: another &struct llist_head to use as temporary storage
+ * @head: the head for your llist.
+ */
+#define llist_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
+
+/**
+ * llist_for_each_entry_rcu - iterate over rcu llist of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_rcu(pos, head, member) \
+ for (pos = llist_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ ({ smp_read_barrier_depends(); 0;}), \
+ prefetch(pos->member.next))
+
+
+/**
+ * llist_for_each_continue_rcu - iterate over an rcu-protected llist
+ * continuing after existing point.
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
+ (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
+
+
+#endif
diff --git a/src/host/libosmocom/include/osmocom/meas_rep.h b/src/host/libosmocom/include/osmocom/meas_rep.h
new file mode 100644
index 00000000..3c2c8d1c
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/meas_rep.h
@@ -0,0 +1,85 @@
+#ifndef _MEAS_REP_H
+#define _MEAS_REP_H
+
+#define MRC_F_PROCESSED 0x0001
+
+/* extracted from a L3 measurement report IE */
+struct gsm_meas_rep_cell {
+ u_int8_t rxlev;
+ u_int8_t bsic;
+ u_int8_t neigh_idx;
+ u_int16_t arfcn;
+ unsigned int flags;
+};
+
+/* RX Level and RX Quality */
+struct gsm_rx_lev_qual {
+ u_int8_t rx_lev;
+ u_int8_t rx_qual;
+};
+
+/* unidirectional measumrement report */
+struct gsm_meas_rep_unidir {
+ struct gsm_rx_lev_qual full;
+ struct gsm_rx_lev_qual sub;
+};
+
+#define MEAS_REP_F_UL_DTX 0x01
+#define MEAS_REP_F_DL_VALID 0x02
+#define MEAS_REP_F_BA1 0x04
+#define MEAS_REP_F_DL_DTX 0x08
+#define MEAS_REP_F_MS_TO 0x10
+#define MEAS_REP_F_MS_L1 0x20
+#define MEAS_REP_F_FPC 0x40
+
+/* parsed uplink and downlink measurement result */
+struct gsm_meas_rep {
+ /* back-pointer to the logical channel */
+ struct gsm_lchan *lchan;
+
+ /* number of the measurement report */
+ u_int8_t nr;
+ /* flags, see MEAS_REP_F_* */
+ unsigned int flags;
+
+ /* uplink and downlink rxlev, rxqual; full and sub */
+ struct gsm_meas_rep_unidir ul;
+ struct gsm_meas_rep_unidir dl;
+
+ u_int8_t bs_power;
+ u_int8_t ms_timing_offset;
+ struct {
+ int8_t pwr; /* MS power in dBm */
+ u_int8_t ta; /* MS timing advance */
+ } ms_l1;
+
+ /* neighbor measurement reports for up to 6 cells */
+ int num_cell;
+ struct gsm_meas_rep_cell cell[6];
+};
+
+enum meas_rep_field {
+ MEAS_REP_DL_RXLEV_FULL,
+ MEAS_REP_DL_RXLEV_SUB,
+ MEAS_REP_DL_RXQUAL_FULL,
+ MEAS_REP_DL_RXQUAL_SUB,
+ MEAS_REP_UL_RXLEV_FULL,
+ MEAS_REP_UL_RXLEV_SUB,
+ MEAS_REP_UL_RXQUAL_FULL,
+ MEAS_REP_UL_RXQUAL_SUB,
+};
+
+/* obtain an average over the last 'num' fields in the meas reps */
+int get_meas_rep_avg(const struct gsm_lchan *lchan,
+ enum meas_rep_field field, unsigned int num);
+
+/* Check if N out of M last values for FIELD are >= bd */
+int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
+ enum meas_rep_field field,
+ unsigned int n, unsigned int m, int be);
+
+unsigned int calc_initial_idx(unsigned int array_size,
+ unsigned int meas_rep_idx,
+ unsigned int num_values);
+
+#endif /* _MEAS_REP_H */
diff --git a/src/host/libosmocom/include/osmocom/msgb.h b/src/host/libosmocom/include/osmocom/msgb.h
new file mode 100644
index 00000000..d0efc90b
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/msgb.h
@@ -0,0 +1,114 @@
+#ifndef _MSGB_H
+#define _MSGB_H
+
+/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <sys/types.h>
+#include "linuxlist.h"
+
+struct bts_link;
+
+struct msgb {
+ struct llist_head list;
+
+ /* ptr to the physical E1 link to the BTS(s) */
+ struct gsm_bts_link *bts_link;
+
+ /* Part of which TRX logical channel we were received / transmitted */
+ struct gsm_bts_trx *trx;
+ struct gsm_lchan *lchan;
+
+ unsigned char *l2h;
+ unsigned char *l3h;
+ unsigned char *smsh;
+
+ u_int16_t data_len;
+ u_int16_t len;
+
+ unsigned char *head;
+ unsigned char *tail;
+ unsigned char *data;
+ unsigned char _data[0];
+};
+
+extern struct msgb *msgb_alloc(u_int16_t size, const char *name);
+extern void msgb_free(struct msgb *m);
+extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
+extern struct msgb *msgb_dequeue(struct llist_head *queue);
+extern void msgb_reset(struct msgb *m);
+
+#define msgb_l2(m) ((void *)(m->l2h))
+#define msgb_l3(m) ((void *)(m->l3h))
+#define msgb_sms(m) ((void *)(m->smsh))
+
+static inline unsigned int msgb_l2len(const struct msgb *msgb)
+{
+ return msgb->tail - (u_int8_t *)msgb_l2(msgb);
+}
+
+static inline unsigned int msgb_l3len(const struct msgb *msgb)
+{
+ return msgb->tail - (u_int8_t *)msgb_l3(msgb);
+}
+
+static inline unsigned int msgb_headlen(const struct msgb *msgb)
+{
+ return msgb->len - msgb->data_len;
+}
+static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
+{
+ unsigned char *tmp = msgb->tail;
+ msgb->tail += len;
+ msgb->len += len;
+ return tmp;
+}
+static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
+{
+ msgb->data -= len;
+ msgb->len += len;
+ return msgb->data;
+}
+static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
+{
+ msgb->len -= len;
+ return msgb->data += len;
+}
+static inline int msgb_tailroom(const struct msgb *msgb)
+{
+ return (msgb->data + msgb->data_len) - msgb->tail;
+}
+
+/* increase the headroom of an empty msgb, reducing the tailroom */
+static inline void msgb_reserve(struct msgb *msg, int len)
+{
+ msg->data += len;
+ msg->tail += len;
+}
+
+static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
+ const char *name)
+{
+ struct msgb *msg = msgb_alloc(size, name);
+ if (msg)
+ msgb_reserve(msg, headroom);
+ return msg;
+}
+
+#endif /* _MSGB_H */
diff --git a/src/host/libosmocom/include/osmocom/select.h b/src/host/libosmocom/include/osmocom/select.h
new file mode 100644
index 00000000..2d8b3ec0
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/select.h
@@ -0,0 +1,22 @@
+#ifndef _BSC_SELECT_H
+#define _BSC_SELECT_H
+
+#include "linuxlist.h"
+
+#define BSC_FD_READ 0x0001
+#define BSC_FD_WRITE 0x0002
+#define BSC_FD_EXCEPT 0x0004
+
+struct bsc_fd {
+ struct llist_head list;
+ int fd;
+ unsigned int when;
+ int (*cb)(struct bsc_fd *fd, unsigned int what);
+ void *data;
+ unsigned int priv_nr;
+};
+
+int bsc_register_fd(struct bsc_fd *fd);
+void bsc_unregister_fd(struct bsc_fd *fd);
+int bsc_select_main(int polling);
+#endif /* _BSC_SELECT_H */
diff --git a/src/host/libosmocom/include/osmocom/talloc.h b/src/host/libosmocom/include/osmocom/talloc.h
new file mode 100644
index 00000000..1c243b80
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/talloc.h
@@ -0,0 +1,192 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+/*
+ Unix SMB/CIFS implementation.
+ Samba temporary memory allocation functions
+
+ Copyright (C) Andrew Tridgell 2004-2005
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#define HAVE_VA_COPY
+
+/* this is only needed for compatibility with the old talloc */
+typedef void TALLOC_CTX;
+
+/*
+ this uses a little trick to allow __LINE__ to be stringified
+*/
+#ifndef __location__
+#define __TALLOC_STRING_LINE1__(s) #s
+#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
+#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
+#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
+#endif
+
+#ifndef TALLOC_DEPRECATED
+#define TALLOC_DEPRECATED 0
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+/* try to make talloc_set_destructor() and talloc_steal() type safe,
+ if we have a recent gcc */
+#if (__GNUC__ >= 3)
+#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
+#define talloc_set_destructor(ptr, function) \
+ do { \
+ int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \
+ _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
+ } while(0)
+/* this extremely strange macro is to avoid some braindamaged warning
+ stupidity in gcc 4.1.x */
+#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
+#else
+#define talloc_set_destructor(ptr, function) \
+ _talloc_set_destructor((ptr), (int (*)(void *))(function))
+#define _TALLOC_TYPEOF(ptr) void *
+#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
+#endif
+
+#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
+#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
+
+/* useful macros for creating type checked pointers */
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
+
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
+#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx))
+
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
+
+#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
+
+#if TALLOC_DEPRECATED
+#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
+#define talloc_p(ctx, type) talloc(ctx, type)
+#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
+#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
+#endif
+
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+
+/* The following definitions come from talloc.c */
+void *_talloc(const void *context, size_t size);
+void *talloc_pool(const void *context, size_t size);
+void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *));
+int talloc_increase_ref_count(const void *ptr);
+size_t talloc_reference_count(const void *ptr);
+void *_talloc_reference(const void *context, const void *ptr);
+int talloc_unlink(const void *context, void *ptr);
+const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void talloc_set_name_const(const void *ptr, const char *name);
+void *talloc_named(const void *context, size_t size,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+void *talloc_named_const(const void *context, size_t size, const char *name);
+const char *talloc_get_name(const void *ptr);
+void *talloc_check_name(const void *ptr, const char *name);
+void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
+void *talloc_parent(const void *ptr);
+const char *talloc_parent_name(const void *ptr);
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+int talloc_free(void *ptr);
+void talloc_free_children(void *ptr);
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+void *_talloc_steal(const void *new_ctx, const void *ptr);
+void *_talloc_move(const void *new_ctx, const void *pptr);
+size_t talloc_total_size(const void *ptr);
+size_t talloc_total_blocks(const void *ptr);
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data);
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
+void talloc_report_full(const void *ptr, FILE *f);
+void talloc_report(const void *ptr, FILE *f);
+void talloc_enable_null_tracking(void);
+void talloc_disable_null_tracking(void);
+void talloc_enable_leak_report(void);
+void talloc_enable_leak_report_full(void);
+void *_talloc_zero(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+void *talloc_autofree_context(void);
+size_t talloc_get_size(const void *ctx);
+void *talloc_find_parent_byname(const void *ctx, const char *name);
+void talloc_show_parents(const void *context, FILE *file);
+int talloc_is_parent(const void *context, const void *ptr);
+
+char *talloc_strdup(const void *t, const char *p);
+char *talloc_strdup_append(char *s, const char *a);
+char *talloc_strdup_append_buffer(char *s, const char *a);
+
+char *talloc_strndup(const void *t, const char *p, size_t n);
+char *talloc_strndup_append(char *s, const char *a, size_t n);
+char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
+
+#endif
diff --git a/src/host/libosmocom/include/osmocom/timer.h b/src/host/libosmocom/include/osmocom/timer.h
new file mode 100644
index 00000000..fee888bf
--- /dev/null
+++ b/src/host/libosmocom/include/osmocom/timer.h
@@ -0,0 +1,72 @@
+/*
+ * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef TIMER_H
+#define TIMER_H
+
+#include <sys/time.h>
+
+#include "linuxlist.h"
+
+/**
+ * Timer management:
+ * - Create a struct timer_list
+ * - Fill out timeout and use add_timer or
+ * use schedule_timer to schedule a timer in
+ * x seconds and microseconds from now...
+ * - Use del_timer to remove the timer
+ *
+ * Internally:
+ * - We hook into select.c to give a timeval of the
+ * nearest timer. On already passed timers we give
+ * it a 0 to immediately fire after the select
+ * - update_timers will call the callbacks and remove
+ * the timers.
+ *
+ */
+struct timer_list {
+ struct llist_head entry;
+ struct timeval timeout;
+ unsigned int active : 1;
+ unsigned int handled : 1;
+ unsigned int in_list : 1;
+
+ void (*cb)(void*);
+ void *data;
+};
+
+/**
+ * timer management
+ */
+void bsc_add_timer(struct timer_list *timer);
+void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds);
+void bsc_del_timer(struct timer_list *timer);
+int bsc_timer_pending(struct timer_list *timer);
+
+
+/**
+ * internal timer list management
+ */
+struct timeval *bsc_nearest_timer();
+void bsc_prepare_timers();
+int bsc_update_timers();
+int bsc_timer_check(void);
+
+#endif
diff --git a/src/host/libosmocom/src/debug.c b/src/host/libosmocom/src/debug.c
new file mode 100644
index 00000000..5dc2b225
--- /dev/null
+++ b/src/host/libosmocom/src/debug.c
@@ -0,0 +1,463 @@
+/* Debugging/Logging support code */
+/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <errno.h>
+
+#include <osmocom/debug.h>
+#include <osmocom/talloc.h>
+
+struct value_string {
+ unsigned int value;
+ const char *str;
+};
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+struct gsm_bts;
+struct gsm_subscriber;
+struct gsm_lchan;
+
+/* default categories */
+static struct debug_category default_categories[Debug_LastEntry] = {
+ [DRLL] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DCC] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DNM] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DRR] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DRSL] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMM] = { .enabled = 1, .loglevel = LOGL_INFO },
+ [DMNCC] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DSMS] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DPAG] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMEAS] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+ [DMI] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+ [DMIB] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+ [DMUX] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DINP] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DSCCP] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMSC] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DMGCP] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DHO] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DDB] = { .enabled = 1, .loglevel = LOGL_NOTICE },
+ [DREF] = { .enabled = 0, .loglevel = LOGL_NOTICE },
+};
+
+const char *get_value_string(const struct value_string *vs, u_int32_t val)
+{
+ int i;
+
+ for (i = 0;; i++) {
+ if (vs[i].value == 0 && vs[i].str == NULL)
+ break;
+ if (vs[i].value == val)
+ return vs[i].str;
+ }
+ return "unknown";
+}
+
+int get_string_value(const struct value_string *vs, const char *str)
+{
+ int i;
+
+ for (i = 0;; i++) {
+ if (vs[i].value == 0 && vs[i].str == NULL)
+ break;
+ if (!strcasecmp(vs[i].str, str))
+ return vs[i].value;
+ }
+ return -EINVAL;
+}
+
+struct debug_info {
+ const char *name;
+ const char *color;
+ const char *description;
+ int number;
+ int position;
+};
+
+struct debug_context {
+ struct gsm_lchan *lchan;
+ struct gsm_subscriber *subscr;
+ struct gsm_bts *bts;
+};
+
+static struct debug_context debug_context;
+static void *tall_dbg_ctx = NULL;
+static LLIST_HEAD(target_list);
+
+#define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \
+ { .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER },
+
+static const struct debug_info debug_info[] = {
+ DEBUG_CATEGORY(DRLL, "DRLL", "\033[1;31m", "")
+ DEBUG_CATEGORY(DCC, "DCC", "\033[1;32m", "")
+ DEBUG_CATEGORY(DMM, "DMM", "\033[1;33m", "")
+ DEBUG_CATEGORY(DRR, "DRR", "\033[1;34m", "")
+ DEBUG_CATEGORY(DRSL, "DRSL", "\033[1;35m", "")
+ DEBUG_CATEGORY(DNM, "DNM", "\033[1;36m", "")
+ DEBUG_CATEGORY(DSMS, "DSMS", "\033[1;37m", "")
+ DEBUG_CATEGORY(DPAG, "DPAG", "\033[1;38m", "")
+ DEBUG_CATEGORY(DMNCC, "DMNCC","\033[1;39m", "")
+ DEBUG_CATEGORY(DINP, "DINP", "", "")
+ DEBUG_CATEGORY(DMI, "DMI", "", "")
+ DEBUG_CATEGORY(DMIB, "DMIB", "", "")
+ DEBUG_CATEGORY(DMUX, "DMUX", "", "")
+ DEBUG_CATEGORY(DMEAS, "DMEAS", "", "")
+ DEBUG_CATEGORY(DSCCP, "DSCCP", "", "")
+ DEBUG_CATEGORY(DMSC, "DMSC", "", "")
+ DEBUG_CATEGORY(DMGCP, "DMGCP", "", "")
+ DEBUG_CATEGORY(DHO, "DHO", "", "")
+ DEBUG_CATEGORY(DDB, "DDB", "", "")
+ DEBUG_CATEGORY(DDB, "DREF", "", "")
+};
+
+static const struct value_string loglevel_strs[] = {
+ { 0, "EVERYTHING" },
+ { 1, "DEBUG" },
+ { 3, "INFO" },
+ { 5, "NOTICE" },
+ { 7, "ERROR" },
+ { 8, "FATAL" },
+ { 0, NULL },
+};
+
+int debug_parse_level(const char *lvl)
+{
+ return get_string_value(loglevel_strs, lvl);
+}
+
+int debug_parse_category(const char *category)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
+ if (!strcasecmp(debug_info[i].name+1, category))
+ return debug_info[i].number;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Parse the category mask.
+ * The format can be this: category1:category2:category3
+ * or category1,2:category2,3:...
+ */
+void debug_parse_category_mask(struct debug_target* target, const char *_mask)
+{
+ int i = 0;
+ char *mask = strdup(_mask);
+ char *category_token = NULL;
+
+ /* Disable everything to enable it afterwards */
+ for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
+ target->categories[i].enabled = 0;
+
+ category_token = strtok(mask, ":");
+ do {
+ for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
+ char* colon = strstr(category_token, ",");
+ int length = strlen(category_token);
+
+ if (colon)
+ length = colon - category_token;
+
+ if (strncasecmp(debug_info[i].name, category_token, length) == 0) {
+ int number = debug_info[i].number;
+ int level = 0;
+
+ if (colon)
+ level = atoi(colon+1);
+
+ target->categories[number].enabled = 1;
+ target->categories[number].loglevel = level;
+ }
+ }
+ } while ((category_token = strtok(NULL, ":")));
+
+ free(mask);
+}
+
+static const char* color(int subsys)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
+ if (debug_info[i].number == subsys)
+ return debug_info[i].color;
+ }
+
+ return "";
+}
+
+static void _output(struct debug_target *target, unsigned int subsys, char *file, int line,
+ int cont, const char *format, va_list ap)
+{
+ char col[30];
+ char sub[30];
+ char tim[30];
+ char buf[4096];
+ char final[4096];
+
+ /* prepare the data */
+ col[0] = '\0';
+ sub[0] = '\0';
+ tim[0] = '\0';
+ buf[0] = '\0';
+
+ /* are we using color */
+ if (target->use_color) {
+ snprintf(col, sizeof(col), "%s", color(subsys));
+ col[sizeof(col)-1] = '\0';
+ }
+ vsnprintf(buf, sizeof(buf), format, ap);
+ buf[sizeof(buf)-1] = '\0';
+
+ if (!cont) {
+ if (target->print_timestamp) {
+ char *timestr;
+ time_t tm;
+ tm = time(NULL);
+ timestr = ctime(&tm);
+ timestr[strlen(timestr)-1] = '\0';
+ snprintf(tim, sizeof(tim), "%s ", timestr);
+ tim[sizeof(tim)-1] = '\0';
+ }
+ snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line);
+ sub[sizeof(sub)-1] = '\0';
+ }
+
+ snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf);
+ final[sizeof(final)-1] = '\0';
+ target->output(target, final);
+}
+
+
+static void _debugp(unsigned int subsys, int level, char *file, int line,
+ int cont, const char *format, va_list ap)
+{
+ struct debug_target *tar;
+
+ llist_for_each_entry(tar, &target_list, entry) {
+ struct debug_category *category;
+ int output = 0;
+
+ category = &tar->categories[subsys];
+ /* subsystem is not supposed to be debugged */
+ if (!category->enabled)
+ continue;
+
+ /* Check the global log level */
+ if (tar->loglevel != 0 && level < tar->loglevel)
+ continue;
+
+ /* Check the category log level */
+ if (category->loglevel != 0 && level < category->loglevel)
+ continue;
+
+ /*
+ * Apply filters here... if that becomes messy we will need to put
+ * filters in a list and each filter will say stop, continue, output
+ */
+ if ((tar->filter_map & DEBUG_FILTER_ALL) != 0) {
+ output = 1;
+#if 0
+ } else if ((tar->filter_map & DEBUG_FILTER_IMSI) != 0
+ && debug_context.subscr && strcmp(debug_context.subscr->imsi, tar->imsi_filter) == 0) {
+ output = 1;
+#endif
+ }
+
+ if (output) {
+ /* FIXME: copying the va_list is an ugly workaround against a bug
+ * hidden somewhere in _output. If we do not copy here, the first
+ * call to _output() will corrupt the va_list contents, and any
+ * further _output() calls with the same va_list will segfault */
+ va_list bp;
+ va_copy(bp, ap);
+ _output(tar, subsys, file, line, cont, format, bp);
+ va_end(bp);
+ }
+ }
+}
+
+void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ _debugp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
+ va_end(ap);
+}
+
+void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ _debugp(subsys, level, file, line, cont, format, ap);
+ va_end(ap);
+}
+
+static char hexd_buff[4096];
+
+char *hexdump(const unsigned char *buf, int len)
+{
+ int i;
+ char *cur = hexd_buff;
+
+ hexd_buff[0] = 0;
+ for (i = 0; i < len; i++) {
+ int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
+ int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
+ if (rc <= 0)
+ break;
+ cur += rc;
+ }
+ hexd_buff[sizeof(hexd_buff)-1] = 0;
+ return hexd_buff;
+}
+
+
+
+void debug_add_target(struct debug_target *target)
+{
+ llist_add_tail(&target->entry, &target_list);
+}
+
+void debug_del_target(struct debug_target *target)
+{
+ llist_del(&target->entry);
+}
+
+void debug_reset_context(void)
+{
+ memset(&debug_context, 0, sizeof(debug_context));
+}
+
+/* currently we are not reffing these */
+void debug_set_context(int ctx, void *value)
+{
+ switch (ctx) {
+ case BSC_CTX_LCHAN:
+ debug_context.lchan = (struct gsm_lchan *) value;
+ break;
+ case BSC_CTX_SUBSCR:
+ debug_context.subscr = (struct gsm_subscriber *) value;
+ break;
+ case BSC_CTX_BTS:
+ debug_context.bts = (struct gsm_bts *) value;
+ break;
+ case BSC_CTX_SCCP:
+ break;
+ default:
+ break;
+ }
+}
+
+void debug_set_imsi_filter(struct debug_target *target, const char *imsi)
+{
+ if (imsi) {
+ target->filter_map |= DEBUG_FILTER_IMSI;
+ target->imsi_filter = talloc_strdup(target, imsi);
+ } else if (target->imsi_filter) {
+ target->filter_map &= ~DEBUG_FILTER_IMSI;
+ talloc_free(target->imsi_filter);
+ target->imsi_filter = NULL;
+ }
+}
+
+void debug_set_all_filter(struct debug_target *target, int all)
+{
+ if (all)
+ target->filter_map |= DEBUG_FILTER_ALL;
+ else
+ target->filter_map &= ~DEBUG_FILTER_ALL;
+}
+
+void debug_set_use_color(struct debug_target *target, int use_color)
+{
+ target->use_color = use_color;
+}
+
+void debug_set_print_timestamp(struct debug_target *target, int print_timestamp)
+{
+ target->print_timestamp = print_timestamp;
+}
+
+void debug_set_log_level(struct debug_target *target, int log_level)
+{
+ target->loglevel = log_level;
+}
+
+void debug_set_category_filter(struct debug_target *target, int category, int enable, int level)
+{
+ if (category >= Debug_LastEntry)
+ return;
+ target->categories[category].enabled = !!enable;
+ target->categories[category].loglevel = level;
+}
+
+static void _stderr_output(struct debug_target *target, const char *log)
+{
+ fprintf(target->tgt_stdout.out, "%s", log);
+ fflush(target->tgt_stdout.out);
+}
+
+struct debug_target *debug_target_create(void)
+{
+ struct debug_target *target;
+
+ target = talloc_zero(tall_dbg_ctx, struct debug_target);
+ if (!target)
+ return NULL;
+
+ INIT_LLIST_HEAD(&target->entry);
+ memcpy(target->categories, default_categories, sizeof(default_categories));
+ target->use_color = 1;
+ target->print_timestamp = 0;
+ target->loglevel = 0;
+ return target;
+}
+
+struct debug_target *debug_target_create_stderr(void)
+{
+ struct debug_target *target;
+
+ target = debug_target_create();
+ if (!target)
+ return NULL;
+
+ target->tgt_stdout.out = stderr;
+ target->output = _stderr_output;
+ return target;
+}
+
+void debug_init(void)
+{
+ tall_dbg_ctx = talloc_named_const(NULL, 1, "debug");
+}
diff --git a/src/host/libosmocom/src/msgb.c b/src/host/libosmocom/src/msgb.c
new file mode 100644
index 00000000..2c794125
--- /dev/null
+++ b/src/host/libosmocom/src/msgb.c
@@ -0,0 +1,97 @@
+/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <osmocom/msgb.h>
+#include <osmocom/talloc.h>
+#include <osmocom/debug.h>
+
+void *tall_msgb_ctx;
+
+struct msgb *msgb_alloc(u_int16_t size, const char *name)
+{
+ struct msgb *msg;
+
+ msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name);
+
+ if (!msg) {
+ LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n");
+ return NULL;
+ }
+
+ msg->data_len = size;
+ msg->len = 0;
+ msg->data = msg->_data;
+
+ msg->head = msg->data;
+ msg->data = msg->data;
+ /* reset tail pointer */
+ msg->tail = msg->data;
+ //msg->end = msg->tail + size;
+
+ return msg;
+}
+
+void msgb_free(struct msgb *m)
+{
+ talloc_free(m);
+}
+
+void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
+{
+ llist_add_tail(&msg->list, queue);
+}
+
+struct msgb *msgb_dequeue(struct llist_head *queue)
+{
+ struct llist_head *lh;
+
+ if (llist_empty(queue))
+ return NULL;
+
+ lh = queue->next;
+ llist_del(lh);
+
+ return llist_entry(lh, struct msgb, list);
+}
+
+void msgb_reset(struct msgb *msg)
+{
+ msg->len = 0;
+ msg->len = 0;
+ msg->data = msg->_data;
+
+ msg->head = msg->data;
+ msg->data = msg->data;
+ /* reset tail pointer */
+ msg->tail = msg->data;
+
+ /* reset pointers */
+ msg->bts_link = NULL;
+ msg->trx = NULL;
+ msg->lchan = NULL;
+ msg->l2h = NULL;
+ msg->l3h = NULL;
+ msg->smsh = NULL;
+}
diff --git a/src/host/libosmocom/src/select.c b/src/host/libosmocom/src/select.c
new file mode 100644
index 00000000..c212cc79
--- /dev/null
+++ b/src/host/libosmocom/src/select.c
@@ -0,0 +1,124 @@
+/* select filedescriptor handling, taken from:
+ * userspace logging daemon for the iptables ULOG target
+ * of the linux 2.4 netfilter subsystem.
+ *
+ * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <fcntl.h>
+#include <osmocom/select.h>
+#include <osmocom/linuxlist.h>
+#include <osmocom/timer.h>
+
+static int maxfd = 0;
+static LLIST_HEAD(bsc_fds);
+static int unregistered_count;
+
+int bsc_register_fd(struct bsc_fd *fd)
+{
+ int flags;
+
+ /* make FD nonblocking */
+ flags = fcntl(fd->fd, F_GETFL);
+ if (flags < 0)
+ return flags;
+ flags |= O_NONBLOCK;
+ flags = fcntl(fd->fd, F_SETFL, flags);
+ if (flags < 0)
+ return flags;
+
+ /* Register FD */
+ if (fd->fd > maxfd)
+ maxfd = fd->fd;
+
+ llist_add_tail(&fd->list, &bsc_fds);
+
+ return 0;
+}
+
+void bsc_unregister_fd(struct bsc_fd *fd)
+{
+ unregistered_count++;
+ llist_del(&fd->list);
+}
+
+int bsc_select_main(int polling)
+{
+ struct bsc_fd *ufd, *tmp;
+ fd_set readset, writeset, exceptset;
+ int work = 0, rc;
+ struct timeval no_time = {0, 0};
+
+ FD_ZERO(&readset);
+ FD_ZERO(&writeset);
+ FD_ZERO(&exceptset);
+
+ /* prepare read and write fdsets */
+ llist_for_each_entry(ufd, &bsc_fds, list) {
+ if (ufd->when & BSC_FD_READ)
+ FD_SET(ufd->fd, &readset);
+
+ if (ufd->when & BSC_FD_WRITE)
+ FD_SET(ufd->fd, &writeset);
+
+ if (ufd->when & BSC_FD_EXCEPT)
+ FD_SET(ufd->fd, &exceptset);
+ }
+
+ bsc_timer_check();
+
+ if (!polling)
+ bsc_prepare_timers();
+ rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
+ if (rc < 0)
+ return 0;
+
+ /* fire timers */
+ bsc_update_timers();
+
+ /* call registered callback functions */
+restart:
+ unregistered_count = 0;
+ llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
+ int flags = 0;
+
+ if (FD_ISSET(ufd->fd, &readset)) {
+ flags |= BSC_FD_READ;
+ FD_CLR(ufd->fd, &readset);
+ }
+
+ if (FD_ISSET(ufd->fd, &writeset)) {
+ flags |= BSC_FD_WRITE;
+ FD_CLR(ufd->fd, &writeset);
+ }
+
+ if (FD_ISSET(ufd->fd, &exceptset)) {
+ flags |= BSC_FD_EXCEPT;
+ FD_CLR(ufd->fd, &exceptset);
+ }
+
+ if (flags) {
+ work = 1;
+ ufd->cb(ufd, flags);
+ }
+ /* ugly, ugly hack. If more than one filedescriptors were
+ * unregistered, they might have been consecutive and
+ * llist_for_each_entry_safe() is no longer safe */
+ if (unregistered_count > 1)
+ goto restart;
+ }
+ return work;
+}
diff --git a/src/host/libosmocom/src/signal.c b/src/host/libosmocom/src/signal.c
new file mode 100644
index 00000000..d45e94e6
--- /dev/null
+++ b/src/host/libosmocom/src/signal.c
@@ -0,0 +1,83 @@
+/* Generic signalling/notification infrastructure */
+/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <osmocom/signal.h>
+#include <osmocom/talloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+void *tall_sigh_ctx;
+static LLIST_HEAD(signal_handler_list);
+
+struct signal_handler {
+ struct llist_head entry;
+ unsigned int subsys;
+ signal_cbfn *cbfn;
+ void *data;
+};
+
+
+int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
+{
+ struct signal_handler *sig_data;
+
+ sig_data = talloc(tall_sigh_ctx, struct signal_handler);
+ if (!sig_data)
+ return -ENOMEM;
+
+ memset(sig_data, 0, sizeof(*sig_data));
+
+ sig_data->subsys = subsys;
+ sig_data->data = data;
+ sig_data->cbfn = cbfn;
+
+ /* FIXME: check if we already have a handler for this subsys/cbfn/data */
+
+ llist_add_tail(&sig_data->entry, &signal_handler_list);
+
+ return 0;
+}
+
+void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
+{
+ struct signal_handler *handler;
+
+ llist_for_each_entry(handler, &signal_handler_list, entry) {
+ if (handler->cbfn == cbfn && handler->data == data
+ && subsys == handler->subsys) {
+ llist_del(&handler->entry);
+ talloc_free(handler);
+ break;
+ }
+ }
+}
+
+
+void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data)
+{
+ struct signal_handler *handler;
+
+ llist_for_each_entry(handler, &signal_handler_list, entry) {
+ if (handler->subsys != subsys)
+ continue;
+ (*handler->cbfn)(subsys, signal, handler->data, signal_data);
+ }
+}
diff --git a/src/host/libosmocom/src/talloc.c b/src/host/libosmocom/src/talloc.c
new file mode 100644
index 00000000..5b8bc274
--- /dev/null
+++ b/src/host/libosmocom/src/talloc.c
@@ -0,0 +1,1805 @@
+/*
+ Samba Unix SMB/CIFS implementation.
+
+ Samba trivial allocation library - new interface
+
+ NOTE: Please read talloc_guide.txt for full documentation
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Stefan Metzmacher 2006
+
+ ** NOTE! The following LGPL license applies to the talloc
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ inspired by http://swapped.cc/halloc/
+*/
+
+#ifdef _SAMBA_BUILD_
+#include "version.h"
+#if (SAMBA_VERSION_MAJOR<4)
+#include "includes.h"
+/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
+ * we trust ourselves... */
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef realloc
+#undef realloc
+#endif
+#define _TALLOC_SAMBA3
+#endif /* (SAMBA_VERSION_MAJOR<4) */
+#endif /* _SAMBA_BUILD_ */
+
+#ifndef _TALLOC_SAMBA3
+//#include "replace.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#define __USE_GNU
+#include <string.h>
+#undef __USE_GNU
+#include <osmocom/talloc.h>
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif /* not _TALLOC_SAMBA3 */
+
+/* use this to force every realloc to change the pointer, to stress test
+ code that might not cope */
+#define ALWAYS_REALLOC 0
+
+
+#define MAX_TALLOC_SIZE 0x10000000
+#define TALLOC_MAGIC 0xe814ec70
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
+#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */
+#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is called
+ on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* these macros gain us a few percent of speed on gcc */
+#if (__GNUC__ >= 3)
+/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
+ as its first argument */
+#ifndef likely
+#define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+#else
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif
+
+#ifdef __APPLE__
+/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */
+size_t strnlen(const char *s, size_t n)
+{
+ const char *p = (const char *)memchr(s, 0, n);
+ return(p ? p-s : n);
+}
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+ talloc_enable_leak_report_full() is called, otherwise it remains
+ NULL
+*/
+static void *null_context;
+static void *autofree_context;
+
+struct talloc_reference_handle {
+ struct talloc_reference_handle *next, *prev;
+ void *ptr;
+};
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_chunk {
+ struct talloc_chunk *next, *prev;
+ struct talloc_chunk *parent, *child;
+ struct talloc_reference_handle *refs;
+ talloc_destructor_t destructor;
+ const char *name;
+ size_t size;
+ unsigned flags;
+
+ /*
+ * "pool" has dual use:
+ *
+ * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
+ * marks the end of the currently allocated area.
+ *
+ * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
+ * is a pointer to the struct talloc_chunk of the pool that it was
+ * allocated from. This way children can quickly find the pool to chew
+ * from.
+ */
+ void *pool;
+};
+
+/* 16 byte alignment seems to keep everyone happy */
+#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
+#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+
+static void (*talloc_abort_fn)(const char *reason);
+
+void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ talloc_abort_fn = abort_fn;
+}
+
+static void talloc_abort(const char *reason)
+{
+ if (!talloc_abort_fn) {
+ TALLOC_ABORT(reason);
+ }
+
+ talloc_abort_fn(reason);
+}
+
+static void talloc_abort_double_free(void)
+{
+ talloc_abort("Bad talloc magic value - double free");
+}
+
+static void talloc_abort_unknown_value(void)
+{
+ talloc_abort("Bad talloc magic value - unknown value");
+}
+
+/* panic if we get a bad magic value */
+static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+ const char *pp = (const char *)ptr;
+ struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
+ if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
+ if (tc->flags & TALLOC_FLAG_FREE) {
+ talloc_abort_double_free();
+ } else {
+ talloc_abort_unknown_value();
+ }
+ }
+ return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+ if (!(list)) { \
+ (list) = (p); \
+ (p)->next = (p)->prev = NULL; \
+ } else { \
+ (list)->prev = (p); \
+ (p)->next = (list); \
+ (p)->prev = NULL; \
+ (list) = (p); \
+ }\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+ if ((p) == (list)) { \
+ (list) = (p)->next; \
+ if (list) (list)->prev = NULL; \
+ } else { \
+ if ((p)->prev) (p)->prev->next = (p)->next; \
+ if ((p)->next) (p)->next->prev = (p)->prev; \
+ } \
+ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+ return the parent chunk of a pointer
+*/
+static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+ while (tc->prev) tc=tc->prev;
+
+ return tc->parent;
+}
+
+void *talloc_parent(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
+}
+
+/*
+ find parents name
+*/
+const char *talloc_parent_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+ return tc? tc->name : NULL;
+}
+
+/*
+ A pool carries an in-pool object count count in the first 16 bytes.
+ bytes. This is done to support talloc_steal() to a parent outside of the
+ pool. The count includes the pool itself, so a talloc_free() on a pool will
+ only destroy the pool if the count has dropped to zero. A talloc_free() of a
+ pool member will reduce the count, and eventually also call free(3) on the
+ pool memory.
+
+ The object count is not put into "struct talloc_chunk" because it is only
+ relevant for talloc pools and the alignment to 16 bytes would increase the
+ memory footprint of each talloc chunk by those 16 bytes.
+*/
+
+#define TALLOC_POOL_HDR_SIZE 16
+
+static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
+{
+ return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
+}
+
+/*
+ Allocate from a pool
+*/
+
+static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
+ size_t size)
+{
+ struct talloc_chunk *pool_ctx = NULL;
+ size_t space_left;
+ struct talloc_chunk *result;
+ size_t chunk_size;
+
+ if (parent == NULL) {
+ return NULL;
+ }
+
+ if (parent->flags & TALLOC_FLAG_POOL) {
+ pool_ctx = parent;
+ }
+ else if (parent->flags & TALLOC_FLAG_POOLMEM) {
+ pool_ctx = (struct talloc_chunk *)parent->pool;
+ }
+
+ if (pool_ctx == NULL) {
+ return NULL;
+ }
+
+ space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
+ - ((char *)pool_ctx->pool);
+
+ /*
+ * Align size to 16 bytes
+ */
+ chunk_size = ((size + 15) & ~15);
+
+ if (space_left < chunk_size) {
+ return NULL;
+ }
+
+ result = (struct talloc_chunk *)pool_ctx->pool;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+ VALGRIND_MAKE_MEM_UNDEFINED(result, size);
+#endif
+
+ pool_ctx->pool = (void *)((char *)result + chunk_size);
+
+ result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
+ result->pool = pool_ctx;
+
+ *talloc_pool_objectcount(pool_ctx) += 1;
+
+ return result;
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+static inline void *__talloc(const void *context, size_t size)
+{
+ struct talloc_chunk *tc = NULL;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ if (context != NULL) {
+ tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
+ TC_HDR_SIZE+size);
+ }
+
+ if (tc == NULL) {
+ tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
+ if (unlikely(tc == NULL)) return NULL;
+ tc->flags = TALLOC_MAGIC;
+ tc->pool = NULL;
+ }
+
+ tc->size = size;
+ tc->destructor = NULL;
+ tc->child = NULL;
+ tc->name = NULL;
+ tc->refs = NULL;
+
+ if (likely(context)) {
+ struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
+
+ if (parent->child) {
+ parent->child->parent = NULL;
+ tc->next = parent->child;
+ tc->next->prev = tc;
+ } else {
+ tc->next = NULL;
+ }
+ tc->parent = parent;
+ tc->prev = NULL;
+ parent->child = tc;
+ } else {
+ tc->next = tc->prev = tc->parent = NULL;
+ }
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ * Create a talloc pool
+ */
+
+void *talloc_pool(const void *context, size_t size)
+{
+ void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
+ struct talloc_chunk *tc;
+
+ if (unlikely(result == NULL)) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(result);
+
+ tc->flags |= TALLOC_FLAG_POOL;
+ tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
+
+ *talloc_pool_objectcount(tc) = 1;
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+ VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
+#endif
+
+ return result;
+}
+
+/*
+ setup a destructor to be called on free of a pointer
+ the destructor should return 0 on success, or -1 on failure.
+ if the destructor fails then the free is failed, and the memory can
+ be continued to be used
+*/
+void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->destructor = destructor;
+}
+
+/*
+ increase the reference count on a piece of memory.
+*/
+int talloc_increase_ref_count(const void *ptr)
+{
+ if (unlikely(!talloc_reference(null_context, ptr))) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ helper for talloc_reference()
+
+ this is referenced by a function pointer and should not be inline
+*/
+static int talloc_reference_destructor(struct talloc_reference_handle *handle)
+{
+ struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
+ _TLIST_REMOVE(ptr_tc->refs, handle);
+ return 0;
+}
+
+/*
+ more efficient way to add a name to a pointer - the name must point to a
+ true string constant
+*/
+static inline void _talloc_set_name_const(const void *ptr, const char *name)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->name = name;
+}
+
+/*
+ internal talloc_named_const()
+*/
+static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
+{
+ void *ptr;
+
+ ptr = __talloc(context, size);
+ if (unlikely(ptr == NULL)) {
+ return NULL;
+ }
+
+ _talloc_set_name_const(ptr, name);
+
+ return ptr;
+}
+
+/*
+ make a secondary reference to a pointer, hanging off the given context.
+ the pointer remains valid until both the original caller and this given
+ context are freed.
+
+ the major use for this is when two different structures need to reference the
+ same underlying data, and you want to be able to free the two instances separately,
+ and in either order
+*/
+void *_talloc_reference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc;
+ struct talloc_reference_handle *handle;
+ if (unlikely(ptr == NULL)) return NULL;
+
+ tc = talloc_chunk_from_ptr(ptr);
+ handle = (struct talloc_reference_handle *)_talloc_named_const(context,
+ sizeof(struct talloc_reference_handle),
+ TALLOC_MAGIC_REFERENCE);
+ if (unlikely(handle == NULL)) return NULL;
+
+ /* note that we hang the destructor off the handle, not the
+ main context as that allows the caller to still setup their
+ own destructor on the context if they want to */
+ talloc_set_destructor(handle, talloc_reference_destructor);
+ handle->ptr = discard_const_p(void, ptr);
+ _TLIST_ADD(tc->refs, handle);
+ return handle->ptr;
+}
+
+
+/*
+ internal talloc_free call
+*/
+static inline int _talloc_free(void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return -1;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(tc->refs)) {
+ int is_child;
+ /* check this is a reference from a child or grantchild
+ * back to it's parent or grantparent
+ *
+ * in that case we need to remove the reference and
+ * call another instance of talloc_free() on the current
+ * pointer.
+ */
+ is_child = talloc_is_parent(tc->refs, ptr);
+ _talloc_free(tc->refs);
+ if (is_child) {
+ return _talloc_free(ptr);
+ }
+ return -1;
+ }
+
+ if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
+ /* we have a free loop - stop looping */
+ return 0;
+ }
+
+ if (unlikely(tc->destructor)) {
+ talloc_destructor_t d = tc->destructor;
+ if (d == (talloc_destructor_t)-1) {
+ return -1;
+ }
+ tc->destructor = (talloc_destructor_t)-1;
+ if (d(ptr) == -1) {
+ tc->destructor = d;
+ return -1;
+ }
+ tc->destructor = NULL;
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_talloc_free(child) == -1)) {
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ talloc_steal(new_parent, child);
+ }
+ }
+
+ tc->flags |= TALLOC_FLAG_FREE;
+
+ if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
+ struct talloc_chunk *pool;
+ unsigned int *pool_object_count;
+
+ pool = (tc->flags & TALLOC_FLAG_POOL)
+ ? tc : (struct talloc_chunk *)tc->pool;
+
+ pool_object_count = talloc_pool_objectcount(pool);
+
+ if (*pool_object_count == 0) {
+ talloc_abort("Pool object count zero!");
+ }
+
+ *pool_object_count -= 1;
+
+ if (*pool_object_count == 0) {
+ free(pool);
+ }
+ }
+ else {
+ free(tc);
+ }
+ return 0;
+}
+
+/*
+ move a lump of memory from one talloc context to another return the
+ ptr on success, or NULL if it could not be transferred.
+ passing NULL as ptr will always return NULL with no side effects.
+*/
+void *_talloc_steal(const void *new_ctx, const void *ptr)
+{
+ struct talloc_chunk *tc, *new_tc;
+
+ if (unlikely(!ptr)) {
+ return NULL;
+ }
+
+ if (unlikely(new_ctx == NULL)) {
+ new_ctx = null_context;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (unlikely(new_ctx == NULL)) {
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = tc->next = tc->prev = NULL;
+ return discard_const_p(void, ptr);
+ }
+
+ new_tc = talloc_chunk_from_ptr(new_ctx);
+
+ if (unlikely(tc == new_tc || tc->parent == new_tc)) {
+ return discard_const_p(void, ptr);
+ }
+
+ if (tc->parent) {
+ _TLIST_REMOVE(tc->parent->child, tc);
+ if (tc->parent->child) {
+ tc->parent->child->parent = tc->parent;
+ }
+ } else {
+ if (tc->prev) tc->prev->next = tc->next;
+ if (tc->next) tc->next->prev = tc->prev;
+ }
+
+ tc->parent = new_tc;
+ if (new_tc->child) new_tc->child->parent = NULL;
+ _TLIST_ADD(new_tc->child, tc);
+
+ return discard_const_p(void, ptr);
+}
+
+
+
+/*
+ remove a secondary reference to a pointer. This undo's what
+ talloc_reference() has done. The context and pointer arguments
+ must match those given to a talloc_reference()
+*/
+static inline int talloc_unreference(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+
+ if (unlikely(context == NULL)) {
+ context = null_context;
+ }
+
+ for (h=tc->refs;h;h=h->next) {
+ struct talloc_chunk *p = talloc_parent_chunk(h);
+ if (p == NULL) {
+ if (context == NULL) break;
+ } else if (TC_PTR_FROM_CHUNK(p) == context) {
+ break;
+ }
+ }
+ if (h == NULL) {
+ return -1;
+ }
+
+ return _talloc_free(h);
+}
+
+/*
+ remove a specific parent context from a pointer. This is a more
+ controlled varient of talloc_free()
+*/
+int talloc_unlink(const void *context, void *ptr)
+{
+ struct talloc_chunk *tc_p, *new_p;
+ void *new_parent;
+
+ if (ptr == NULL) {
+ return -1;
+ }
+
+ if (context == NULL) {
+ context = null_context;
+ }
+
+ if (talloc_unreference(context, ptr) == 0) {
+ return 0;
+ }
+
+ if (context == NULL) {
+ if (talloc_parent_chunk(ptr) != NULL) {
+ return -1;
+ }
+ } else {
+ if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
+ return -1;
+ }
+ }
+
+ tc_p = talloc_chunk_from_ptr(ptr);
+
+ if (tc_p->refs == NULL) {
+ return _talloc_free(ptr);
+ }
+
+ new_p = talloc_parent_chunk(tc_p->refs);
+ if (new_p) {
+ new_parent = TC_PTR_FROM_CHUNK(new_p);
+ } else {
+ new_parent = NULL;
+ }
+
+ if (talloc_unreference(new_parent, ptr) != 0) {
+ return -1;
+ }
+
+ talloc_steal(new_parent, ptr);
+
+ return 0;
+}
+
+/*
+ add a name to an existing pointer - va_list version
+*/
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+
+static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ tc->name = talloc_vasprintf(ptr, fmt, ap);
+ if (likely(tc->name)) {
+ _talloc_set_name_const(tc->name, ".name");
+ }
+ return tc->name;
+}
+
+/*
+ add a name to an existing pointer
+*/
+const char *talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+ const char *name;
+ va_list ap;
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+ return name;
+}
+
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+
+ ptr = __talloc(context, size);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ return the name of a talloc ptr, or "UNNAMED"
+*/
+const char *talloc_get_name(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
+ return ".reference";
+ }
+ if (likely(tc->name)) {
+ return tc->name;
+ }
+ return "UNNAMED";
+}
+
+
+/*
+ check if a pointer has the given name. If it does, return the pointer,
+ otherwise return NULL
+*/
+void *talloc_check_name(const void *ptr, const char *name)
+{
+ const char *pname;
+ if (unlikely(ptr == NULL)) return NULL;
+ pname = talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+ return NULL;
+}
+
+static void talloc_abort_type_missmatch(const char *location,
+ const char *name,
+ const char *expected)
+{
+ const char *reason;
+
+ reason = talloc_asprintf(NULL,
+ "%s: Type mismatch: name[%s] expected[%s]",
+ location,
+ name?name:"NULL",
+ expected);
+ if (!reason) {
+ reason = "Type mismatch";
+ }
+
+ talloc_abort(reason);
+}
+
+void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
+{
+ const char *pname;
+
+ if (unlikely(ptr == NULL)) {
+ talloc_abort_type_missmatch(location, NULL, name);
+ return NULL;
+ }
+
+ pname = talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+
+ talloc_abort_type_missmatch(location, pname, name);
+ return NULL;
+}
+
+/*
+ this is for compatibility with older versions of talloc
+*/
+void *talloc_init(const char *fmt, ...)
+{
+ va_list ap;
+ void *ptr;
+ const char *name;
+
+ /*
+ * samba3 expects talloc_report_depth_cb(NULL, ...)
+ * reports all talloc'ed memory, so we need to enable
+ * null_tracking
+ */
+ talloc_enable_null_tracking();
+
+ ptr = __talloc(NULL, 0);
+ if (unlikely(ptr == NULL)) return NULL;
+
+ va_start(ap, fmt);
+ name = talloc_set_name_v(ptr, fmt, ap);
+ va_end(ap);
+
+ if (unlikely(name == NULL)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ return ptr;
+}
+
+/*
+ this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+ should probably not be used in new code. It's in here to keep the talloc
+ code consistent across Samba 3 and 4.
+*/
+void talloc_free_children(void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (unlikely(ptr == NULL)) {
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ while (tc->child) {
+ /* we need to work out who will own an abandoned child
+ if it cannot be freed. In priority order, the first
+ choice is owner of any remaining reference to this
+ pointer, the second choice is our parent, and the
+ final choice is the null context. */
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
+ const void *new_parent = null_context;
+ if (unlikely(tc->child->refs)) {
+ struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ if (unlikely(_talloc_free(child) == -1)) {
+ if (new_parent == null_context) {
+ struct talloc_chunk *p = talloc_parent_chunk(ptr);
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
+ }
+ talloc_steal(new_parent, child);
+ }
+ }
+
+ if ((tc->flags & TALLOC_FLAG_POOL)
+ && (*talloc_pool_objectcount(tc) == 1)) {
+ tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
+ VALGRIND_MAKE_MEM_NOACCESS(
+ tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
+#endif
+ }
+}
+
+/*
+ Allocate a bit of memory as a child of an existing pointer
+*/
+void *_talloc(const void *context, size_t size)
+{
+ return __talloc(context, size);
+}
+
+/*
+ externally callable talloc_set_name_const()
+*/
+void talloc_set_name_const(const void *ptr, const char *name)
+{
+ _talloc_set_name_const(ptr, name);
+}
+
+/*
+ create a named talloc pointer. Any talloc pointer can be named, and
+ talloc_named() operates just like talloc() except that it allows you
+ to name the pointer.
+*/
+void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+ return _talloc_named_const(context, size, name);
+}
+
+/*
+ free a talloc pointer. This also frees all child pointers of this
+ pointer recursively
+
+ return 0 if the memory is actually freed, otherwise -1. The memory
+ will not be freed if the ref_count is > 1 or the destructor (if
+ any) returns non-zero
+*/
+int talloc_free(void *ptr)
+{
+ return _talloc_free(ptr);
+}
+
+
+
+/*
+ A talloc version of realloc. The context argument is only used if
+ ptr is NULL
+*/
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
+{
+ struct talloc_chunk *tc;
+ void *new_ptr;
+ bool malloced = false;
+
+ /* size zero is equivalent to free() */
+ if (unlikely(size == 0)) {
+ _talloc_free(ptr);
+ return NULL;
+ }
+
+ if (unlikely(size >= MAX_TALLOC_SIZE)) {
+ return NULL;
+ }
+
+ /* realloc(NULL) is equivalent to malloc() */
+ if (ptr == NULL) {
+ return _talloc_named_const(context, size, name);
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ /* don't allow realloc on referenced pointers */
+ if (unlikely(tc->refs)) {
+ return NULL;
+ }
+
+ /* don't let anybody try to realloc a talloc_pool */
+ if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
+ return NULL;
+ }
+
+ /* don't shrink if we have less than 1k to gain */
+ if ((size < tc->size) && ((tc->size - size) < 1024)) {
+ tc->size = size;
+ return ptr;
+ }
+
+ /* by resetting magic we catch users of the old memory */
+ tc->flags |= TALLOC_FLAG_FREE;
+
+#if ALWAYS_REALLOC
+ new_ptr = malloc(size + TC_HDR_SIZE);
+ if (new_ptr) {
+ memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
+ free(tc);
+ }
+#else
+ if (tc->flags & TALLOC_FLAG_POOLMEM) {
+
+ new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
+ *talloc_pool_objectcount((struct talloc_chunk *)
+ (tc->pool)) -= 1;
+
+ if (new_ptr == NULL) {
+ new_ptr = malloc(TC_HDR_SIZE+size);
+ malloced = true;
+ }
+
+ if (new_ptr) {
+ memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
+ }
+ }
+ else {
+ new_ptr = realloc(tc, size + TC_HDR_SIZE);
+ }
+#endif
+ if (unlikely(!new_ptr)) {
+ tc->flags &= ~TALLOC_FLAG_FREE;
+ return NULL;
+ }
+
+ tc = (struct talloc_chunk *)new_ptr;
+ tc->flags &= ~TALLOC_FLAG_FREE;
+ if (malloced) {
+ tc->flags &= ~TALLOC_FLAG_POOLMEM;
+ }
+ if (tc->parent) {
+ tc->parent->child = tc;
+ }
+ if (tc->child) {
+ tc->child->parent = tc;
+ }
+
+ if (tc->prev) {
+ tc->prev->next = tc;
+ }
+ if (tc->next) {
+ tc->next->prev = tc;
+ }
+
+ tc->size = size;
+ _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
+
+ return TC_PTR_FROM_CHUNK(tc);
+}
+
+/*
+ a wrapper around talloc_steal() for situations where you are moving a pointer
+ between two structures, and want the old pointer to be set to NULL
+*/
+void *_talloc_move(const void *new_ctx, const void *_pptr)
+{
+ const void **pptr = discard_const_p(const void *,_pptr);
+ void *ret = _talloc_steal(new_ctx, *pptr);
+ (*pptr) = NULL;
+ return ret;
+}
+
+/*
+ return the total size of a talloc pool (subtree)
+*/
+size_t talloc_total_size(const void *ptr)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ total = tc->size;
+ for (c=tc->child;c;c=c->next) {
+ total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the total number of blocks in a talloc pool (subtree)
+*/
+size_t talloc_total_blocks(const void *ptr)
+{
+ size_t total = 0;
+ struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ total++;
+ for (c=tc->child;c;c=c->next) {
+ total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
+ }
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
+ return total;
+}
+
+/*
+ return the number of external references to a pointer
+*/
+size_t talloc_reference_count(const void *ptr)
+{
+ struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+ struct talloc_reference_handle *h;
+ size_t ret = 0;
+
+ for (h=tc->refs;h;h=h->next) {
+ ret++;
+ }
+ return ret;
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
+ void (*callback)(const void *ptr,
+ int depth, int max_depth,
+ int is_ref,
+ void *private_data),
+ void *private_data)
+{
+ struct talloc_chunk *c, *tc;
+
+ if (ptr == NULL) {
+ ptr = null_context;
+ }
+ if (ptr == NULL) return;
+
+ tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return;
+ }
+
+ callback(ptr, depth, max_depth, 0, private_data);
+
+ if (max_depth >= 0 && depth >= max_depth) {
+ return;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+ for (c=tc->child;c;c=c->next) {
+ if (c->name == TALLOC_MAGIC_REFERENCE) {
+ struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
+ callback(h->ptr, depth + 1, max_depth, 1, private_data);
+ } else {
+ talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
+ }
+ }
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+}
+
+static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
+{
+ const char *name = talloc_get_name(ptr);
+ FILE *f = (FILE *)_f;
+
+ if (is_ref) {
+ fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
+ return;
+ }
+
+ if (depth == 0) {
+ fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
+ (max_depth < 0 ? "full " :""), name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr));
+ return;
+ }
+
+ fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
+ depth*4, "",
+ name,
+ (unsigned long)talloc_total_size(ptr),
+ (unsigned long)talloc_total_blocks(ptr),
+ (int)talloc_reference_count(ptr), ptr);
+
+#if 0
+ fprintf(f, "content: ");
+ if (talloc_total_size(ptr)) {
+ int tot = talloc_total_size(ptr);
+ int i;
+
+ for (i = 0; i < tot; i++) {
+ if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
+ fprintf(f, "%c", ((char *)ptr)[i]);
+ } else {
+ fprintf(f, "~%02x", ((char *)ptr)[i]);
+ }
+ }
+ }
+ fprintf(f, "\n");
+#endif
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
+{
+ talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
+ fflush(f);
+}
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_full(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, -1, f);
+}
+
+/*
+ report on memory usage by all children of a pointer
+*/
+void talloc_report(const void *ptr, FILE *f)
+{
+ talloc_report_depth_file(ptr, 0, 1, f);
+}
+
+/*
+ report on any memory hanging off the null context
+*/
+static void talloc_report_null(void)
+{
+ if (talloc_total_size(null_context) != 0) {
+ talloc_report(null_context, stderr);
+ }
+}
+
+/*
+ report on any memory hanging off the null context
+*/
+static void talloc_report_null_full(void)
+{
+ if (talloc_total_size(null_context) != 0) {
+ talloc_report_full(null_context, stderr);
+ }
+}
+
+/*
+ enable tracking of the NULL context
+*/
+void talloc_enable_null_tracking(void)
+{
+ if (null_context == NULL) {
+ null_context = _talloc_named_const(NULL, 0, "null_context");
+ }
+}
+
+/*
+ disable tracking of the NULL context
+*/
+void talloc_disable_null_tracking(void)
+{
+ _talloc_free(null_context);
+ null_context = NULL;
+}
+
+/*
+ enable leak reporting on exit
+*/
+void talloc_enable_leak_report(void)
+{
+ talloc_enable_null_tracking();
+ atexit(talloc_report_null);
+}
+
+/*
+ enable full leak reporting on exit
+*/
+void talloc_enable_leak_report_full(void)
+{
+ talloc_enable_null_tracking();
+ atexit(talloc_report_null_full);
+}
+
+/*
+ talloc and zero memory.
+*/
+void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+ void *p = _talloc_named_const(ctx, size, name);
+
+ if (p) {
+ memset(p, '\0', size);
+ }
+
+ return p;
+}
+
+/*
+ memdup with a talloc.
+*/
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+ void *newp = _talloc_named_const(t, size, name);
+
+ if (likely(newp)) {
+ memcpy(newp, p, size);
+ }
+
+ return newp;
+}
+
+static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
+{
+ char *ret;
+
+ ret = (char *)__talloc(t, len + 1);
+ if (unlikely(!ret)) return NULL;
+
+ memcpy(ret, p, len);
+ ret[len] = 0;
+
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+/*
+ strdup with a talloc
+*/
+char *talloc_strdup(const void *t, const char *p)
+{
+ if (unlikely(!p)) return NULL;
+ return __talloc_strlendup(t, p, strlen(p));
+}
+
+/*
+ strndup with a talloc
+*/
+char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+ if (unlikely(!p)) return NULL;
+ return __talloc_strlendup(t, p, strnlen(p, n));
+}
+
+static inline char *__talloc_strlendup_append(char *s, size_t slen,
+ const char *a, size_t alen)
+{
+ char *ret;
+
+ ret = talloc_realloc(NULL, s, char, slen + alen + 1);
+ if (unlikely(!ret)) return NULL;
+
+ /* append the string and the trailing \0 */
+ memcpy(&ret[slen], a, alen);
+ ret[slen+alen] = 0;
+
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+/*
+ * Appends at the end of the string.
+ */
+char *talloc_strdup_append(char *s, const char *a)
+{
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+char *talloc_strdup_append_buffer(char *s, const char *a)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_strlendup_append(s, slen, a, strlen(a));
+}
+
+/*
+ * Appends at the end of the string.
+ */
+char *talloc_strndup_append(char *s, const char *a, size_t n)
+{
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
+}
+
+/*
+ * Appends at the end of the talloc'ed buffer,
+ * not the end of the string.
+ */
+char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_strdup(NULL, a);
+ }
+
+ if (unlikely(!a)) {
+ return s;
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
+}
+
+#ifndef HAVE_VA_COPY
+#ifdef HAVE___VA_COPY
+#define va_copy(dest, src) __va_copy(dest, src)
+#else
+#define va_copy(dest, src) (dest) = (src)
+#endif
+#endif
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+ int len;
+ char *ret;
+ va_list ap2;
+ char c;
+
+ /* this call looks strange, but it makes it work on older solaris boxes */
+ va_copy(ap2, ap);
+ len = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+ if (unlikely(len < 0)) {
+ return NULL;
+ }
+
+ ret = (char *)__talloc(t, len+1);
+ if (unlikely(!ret)) return NULL;
+
+ va_copy(ap2, ap);
+ vsnprintf(ret, len+1, fmt, ap2);
+ va_end(ap2);
+
+ _talloc_set_name_const(ret, ret);
+ return ret;
+}
+
+
+/*
+ Perform string formatting, and return a pointer to newly allocated
+ memory holding the result, inside a memory pool.
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+ const char *fmt, va_list ap)
+ PRINTF_ATTRIBUTE(3,0);
+
+static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
+ const char *fmt, va_list ap)
+{
+ ssize_t alen;
+ va_list ap2;
+ char c;
+
+ va_copy(ap2, ap);
+ alen = vsnprintf(&c, 1, fmt, ap2);
+ va_end(ap2);
+
+ if (alen <= 0) {
+ /* Either the vsnprintf failed or the format resulted in
+ * no characters being formatted. In the former case, we
+ * ought to return NULL, in the latter we ought to return
+ * the original string. Most current callers of this
+ * function expect it to never return NULL.
+ */
+ return s;
+ }
+
+ s = talloc_realloc(NULL, s, char, slen + alen + 1);
+ if (!s) return NULL;
+
+ va_copy(ap2, ap);
+ vsnprintf(s + slen, alen + 1, fmt, ap2);
+ va_end(ap2);
+
+ _talloc_set_name_const(s, s);
+ return s;
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Good for gradually
+ * accumulating output into a string buffer. Appends at the end
+ * of the string.
+ **/
+char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+ if (unlikely(!s)) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
+}
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved. Always appends at the
+ * end of the talloc'ed buffer, not the end of the string.
+ **/
+char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
+{
+ size_t slen;
+
+ if (unlikely(!s)) {
+ return talloc_vasprintf(NULL, fmt, ap);
+ }
+
+ slen = talloc_get_size(s);
+ if (likely(slen > 0)) {
+ slen--;
+ }
+
+ return __talloc_vaslenprintf_append(s, slen, fmt, ap);
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a string buffer.
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+/*
+ Realloc @p s to append the formatted result of @p fmt and return @p
+ s, which may have moved. Good for gradually accumulating output
+ into a buffer.
+ */
+char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = talloc_vasprintf_append_buffer(s, fmt, ap);
+ va_end(ap);
+ return s;
+}
+
+/*
+ alloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+ alloc an zero array, checking for integer overflow in the array size
+*/
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_zero(ctx, el_size * count, name);
+}
+
+/*
+ realloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
+{
+ if (count >= MAX_TALLOC_SIZE/el_size) {
+ return NULL;
+ }
+ return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+ a function version of talloc_realloc(), so it can be passed as a function pointer
+ to libraries that want a realloc function (a realloc function encapsulates
+ all the basic capabilities of an allocation library, which is why this is useful)
+*/
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+ return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static int talloc_autofree_destructor(void *ptr)
+{
+ autofree_context = NULL;
+ return 0;
+}
+
+static void talloc_autofree(void)
+{
+ _talloc_free(autofree_context);
+}
+
+/*
+ return a context which will be auto-freed on exit
+ this is useful for reducing the noise in leak reports
+*/
+void *talloc_autofree_context(void)
+{
+ if (autofree_context == NULL) {
+ autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
+ talloc_set_destructor(autofree_context, talloc_autofree_destructor);
+ atexit(talloc_autofree);
+ }
+ return autofree_context;
+}
+
+size_t talloc_get_size(const void *context)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL)
+ return 0;
+
+ tc = talloc_chunk_from_ptr(context);
+
+ return tc->size;
+}
+
+/*
+ find a parent of this context that has the given name, if any
+*/
+void *talloc_find_parent_byname(const void *context, const char *name)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (tc->name && strcmp(tc->name, name) == 0) {
+ return TC_PTR_FROM_CHUNK(tc);
+ }
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return NULL;
+}
+
+/*
+ show the parentage of a context
+*/
+void talloc_show_parents(const void *context, FILE *file)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ fprintf(file, "talloc no parents for NULL\n");
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
+ while (tc) {
+ fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ fflush(file);
+}
+
+/*
+ return 1 if ptr is a parent of context
+*/
+int talloc_is_parent(const void *context, const void *ptr)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
+ while (tc && tc->prev) tc = tc->prev;
+ if (tc) {
+ tc = tc->parent;
+ }
+ }
+ return 0;
+}
diff --git a/src/host/libosmocom/src/timer.c b/src/host/libosmocom/src/timer.c
new file mode 100644
index 00000000..acb4d923
--- /dev/null
+++ b/src/host/libosmocom/src/timer.c
@@ -0,0 +1,185 @@
+/*
+ * (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <osmocom/timer.h>
+
+static LLIST_HEAD(timer_list);
+static struct timeval s_nearest_time;
+static struct timeval s_select_time;
+
+#define MICRO_SECONDS 1000000LL
+
+#define TIME_SMALLER(left, right) \
+ (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
+
+void bsc_add_timer(struct timer_list *timer)
+{
+ struct timer_list *list_timer;
+
+ /* TODO: Optimize and remember the closest item... */
+ timer->active = 1;
+
+ /* this might be called from within update_timers */
+ llist_for_each_entry(list_timer, &timer_list, entry)
+ if (timer == list_timer)
+ return;
+
+ timer->in_list = 1;
+ llist_add(&timer->entry, &timer_list);
+}
+
+void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
+{
+ struct timeval current_time;
+
+ gettimeofday(&current_time, NULL);
+ unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
+ currentTime += seconds * MICRO_SECONDS + microseconds;
+ timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
+ timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
+ bsc_add_timer(timer);
+}
+
+void bsc_del_timer(struct timer_list *timer)
+{
+ if (timer->in_list) {
+ timer->active = 0;
+ timer->in_list = 0;
+ llist_del(&timer->entry);
+ }
+}
+
+int bsc_timer_pending(struct timer_list *timer)
+{
+ return timer->active;
+}
+
+/*
+ * if we have a nearest time return the delta between the current
+ * time and the time of the nearest timer.
+ * If the nearest timer timed out return NULL and then we will
+ * dispatch everything after the select
+ */
+struct timeval *bsc_nearest_timer()
+{
+ struct timeval current_time;
+
+ if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
+ return NULL;
+
+ if (gettimeofday(&current_time, NULL) == -1)
+ return NULL;
+
+ unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
+ unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
+
+ if (nearestTime < currentTime) {
+ s_select_time.tv_sec = 0;
+ s_select_time.tv_usec = 0;
+ } else {
+ s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
+ s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
+ }
+
+ return &s_select_time;
+}
+
+/*
+ * Find the nearest time and update s_nearest_time
+ */
+void bsc_prepare_timers()
+{
+ struct timer_list *timer, *nearest_timer = NULL;
+ llist_for_each_entry(timer, &timer_list, entry) {
+ if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
+ nearest_timer = timer;
+ }
+ }
+
+ if (nearest_timer) {
+ s_nearest_time = nearest_timer->timeout;
+ } else {
+ memset(&s_nearest_time, 0, sizeof(struct timeval));
+ }
+}
+
+/*
+ * fire all timers... and remove them
+ */
+int bsc_update_timers()
+{
+ struct timeval current_time;
+ struct timer_list *timer, *tmp;
+ int work = 0;
+
+ gettimeofday(&current_time, NULL);
+
+ /*
+ * The callbacks might mess with our list and in this case
+ * even llist_for_each_entry_safe is not safe to use. To allow
+ * del_timer, add_timer, schedule_timer to be called from within
+ * the callback we jump through some loops.
+ *
+ * First we set the handled flag of each active timer to zero,
+ * then we iterate over the list and execute the callbacks. As the
+ * list might have been changed (specially the next) from within
+ * the callback we have to start over again. Once every callback
+ * is dispatched we will remove the non-active from the list.
+ *
+ * TODO: If this is a performance issue we can poison a global
+ * variable in add_timer and del_timer and only then restart.
+ */
+ llist_for_each_entry(timer, &timer_list, entry) {
+ timer->handled = 0;
+ }
+
+restart:
+ llist_for_each_entry(timer, &timer_list, entry) {
+ if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
+ timer->handled = 1;
+ timer->active = 0;
+ (*timer->cb)(timer->data);
+ work = 1;
+ goto restart;
+ }
+ }
+
+ llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
+ timer->handled = 0;
+ if (!timer->active) {
+ bsc_del_timer(timer);
+ }
+ }
+
+ return work;
+}
+
+int bsc_timer_check(void)
+{
+ struct timer_list *timer;
+ int i = 0;
+
+ llist_for_each_entry(timer, &timer_list, entry) {
+ i++;
+ }
+ return i;
+}
diff --git a/src/host/osmocon/.gitignore b/src/host/osmocon/.gitignore
new file mode 100644
index 00000000..a9966b12
--- /dev/null
+++ b/src/host/osmocon/.gitignore
@@ -0,0 +1,9 @@
+*.o
+osmocon
+*.id*
+*.nam
+*.til
+*.dump
+*.bin
+*.log
+version.h
diff --git a/src/host/osmocon/Makefile b/src/host/osmocon/Makefile
new file mode 100644
index 00000000..9cb11d2d
--- /dev/null
+++ b/src/host/osmocon/Makefile
@@ -0,0 +1,19 @@
+all: osmocon
+
+OSMOCOM_SRC=../libosmocom/src/select.c ../libosmocom/src/timer.c \
+ ../libosmocom/src/msgb.c ../libosmocom/src/talloc.c \
+ ../libosmocom/src/debug.c
+SERCOMM_SRC=../../target/hello_world/comm/sercomm.c
+INCLUDES=-I../libosmocom/include -I../../target/hello_world/include/comm
+
+.PHONY: version.h
+version.h:
+ @echo -n \#define VERSION \"git- > version.h
+ @git log --oneline -n1 osmocon.c|cut -d ' ' -f 1 |tr -d '\n' >> version.h
+ @echo \" >> version.h
+
+osmocon: version.h $(OSMOCOM_SRC) $(SERCOMM_SRC)
+ $(CC) $(CFLAGS) -DHOST_BUILD $(INCLUDES) -o $@ $(OSMOCOM_SRC) $(SERCOMM_SRC) osmocon.c
+
+clean:
+ @rm -f osmocon version.h
diff --git a/src/host/osmocon/memdump_convert.pl b/src/host/osmocon/memdump_convert.pl
new file mode 100755
index 00000000..3d18a0b3
--- /dev/null
+++ b/src/host/osmocon/memdump_convert.pl
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+my $num_line = 0;
+my $num_hex = 0;
+my $oldaddr;
+
+while (my $line = <STDIN>) {
+ chomp($line);
+ $num_line++;
+ my (@hex) = $line =~ /(\w{8}): (\w{8}) (\w{8}) (\w{8}) (\w{8}) (\w{8}) (\w{8}) (\w{8}) (\w{8})/;
+ my $addr = hex(shift @hex);
+ if ($addr != 0 && $addr != $oldaddr + 0x20) {
+ printf(STDERR "gap of %u between 0x%08x and 0x%08x\n%s\n",
+ $addr - $oldaddr, $addr, $oldaddr, $line);
+ }
+ foreach my $h (@hex) {
+ $num_hex++;
+ # poor mans endian conversion
+ my ($a, $b, $c, $d) = $h =~/(\w\w)(\w\w)(\w\w)(\w\w)/;
+ my $h_reorder = $d . $c . $b . $a;
+ # convert into actual binary number
+ my $tmp = pack('H8', $h_reorder);
+ syswrite(STDOUT, $tmp, 4);
+ }
+ $oldaddr = $addr;
+}
+
+printf(STDERR "num lines/num hex: %u/%u\n", $num_line, $num_hex);
+
diff --git a/src/host/osmocon/osmocon.c b/src/host/osmocon/osmocon.c
new file mode 100644
index 00000000..094dbeb2
--- /dev/null
+++ b/src/host/osmocon/osmocon.c
@@ -0,0 +1,660 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <sercomm.h>
+
+#include <osmocom/linuxlist.h>
+#include <osmocom/select.h>
+#include <osmocom/talloc.h>
+
+#include "version.h"
+
+#define MODEM_BAUDRATE B115200
+#define MAX_DNLOAD_SIZE 0xFFFF
+#define MAX_HDR_SIZE 128
+
+enum dnload_state {
+ WAITING_PROMPT1,
+ WAITING_PROMPT2,
+ DOWNLOADING,
+};
+
+enum dnload_mode {
+ MODE_C123,
+ MODE_C123xor,
+ MODE_C155,
+};
+
+struct dnload {
+ enum dnload_state state;
+ enum dnload_mode mode;
+ struct bsc_fd serial_fd;
+ char *filename;
+
+ int print_hdlc;
+
+ /* data to be downloaded */
+ uint8_t *data;
+ int data_len;
+
+ uint8_t *write_ptr;
+
+ /* sockaddr in */
+ struct bsc_fd socket;
+};
+
+/**
+ * a connection of the layer2
+ */
+struct layer2_connection {
+ struct llist_head entry;
+ struct bsc_fd fd;
+};
+
+static LLIST_HEAD(connections);
+static struct dnload dnload;
+
+static const uint8_t phone_prompt1[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x01, 0x40 };
+static const uint8_t dnload_cmd[] = { 0x1b, 0xf6, 0x02, 0x00, 0x52, 0x01, 0x53 };
+static const uint8_t phone_prompt2[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x02, 0x43 };
+static const uint8_t phone_ack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
+static const uint8_t phone_nack_magic[]= { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x57 };
+static const uint8_t phone_nack[] = { 0x1b, 0xf6, 0x02, 0x00, 0x45, 0x53, 0x16 };
+static const uint8_t ftmtool[] = { "ftmtool" };
+
+/* The C123 has a hard-coded check inside the ramloder that requires the following
+ * bytes to be always the first four bytes of the image */
+static const uint8_t data_hdr_c123[] = { 0xee, 0x4c, 0x9f, 0x63 };
+
+/* The C155 doesn't have some strange restriction on what the first four bytes have
+ * to be, but it starts the ramloader in THUMB mode. We use the following four bytes
+ * to switch back to ARM mode:
+ 800100: 4778 bx pc
+ 800102: 46c0 nop ; (mov r8, r8)
+ */
+static const uint8_t data_hdr_c155[] = { 0x78, 0x47, 0xc0, 0x46 };
+
+static const uint8_t dummy_data[] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde };
+
+static int serial_init(const char *serial_dev)
+{
+ struct termios options;
+ int fd, v24;
+
+ fd = open(serial_dev, O_RDWR | O_NOCTTY | O_NDELAY);
+ if (fd < 0)
+ return fd;
+
+ fcntl(fd, F_SETFL, 0);
+
+ /* Configure serial interface */
+ tcgetattr(fd, &options);
+
+ cfsetispeed(&options, MODEM_BAUDRATE);
+ cfsetospeed(&options, MODEM_BAUDRATE);
+
+ /* local read */
+ options.c_cflag &= ~PARENB;
+ options.c_cflag &= ~CSTOPB;
+ options.c_cflag &= ~CSIZE;
+ options.c_cflag |= CS8;
+
+ /* hardware flow control off */
+ options.c_cflag &= ~CRTSCTS;
+
+ /* software flow control off */
+ options.c_iflag &= ~(IXON | IXOFF | IXANY);
+
+ /* we want raw i/o */
+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
+ options.c_oflag &= ~(ONLCR);
+
+ options.c_cc[VMIN] = 1;
+ options.c_cc[VTIME] = 0;
+ options.c_cc[VINTR] = 0;
+ options.c_cc[VQUIT] = 0;
+ options.c_cc[VSTART] = 0;
+ options.c_cc[VSTOP] = 0;
+ options.c_cc[VSUSP] = 0;
+
+ tcsetattr(fd, TCSANOW, &options);
+
+ /* set ready to read/write */
+ v24 = TIOCM_DTR | TIOCM_RTS;
+ ioctl(fd, TIOCMBIS, &v24);
+
+ return fd;
+}
+
+/* Read the to-be-downloaded file, prepend header and length, append XOR sum */
+int read_file(const char *filename)
+{
+ int fd, rc, i;
+ struct stat st;
+ const uint8_t *hdr;
+ int hdr_len = 0;
+ uint8_t *file_data;
+ uint16_t tot_len;
+ uint8_t nibble;
+ uint8_t running_xor = 0x02;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror("opening file");
+ exit(1);
+ }
+
+ rc = fstat(fd, &st);
+ if (st.st_size > MAX_DNLOAD_SIZE) {
+ fprintf(stderr, "The maximum file size is 64kBytes (%u bytes)\n",
+ MAX_DNLOAD_SIZE);
+ return -EFBIG;
+ }
+
+ if (dnload.data) {
+ free(dnload.data);
+ dnload.data = NULL;
+ }
+
+ dnload.data = malloc(MAX_HDR_SIZE + st.st_size);
+ if (!dnload.data) {
+ close(fd);
+ fprintf(stderr, "No memory\n");
+ return -ENOMEM;
+ }
+
+ /* copy in the header, if any */
+ switch (dnload.mode) {
+ case MODE_C155:
+ hdr = data_hdr_c155;
+ hdr_len = sizeof(data_hdr_c155);
+ break;
+ case MODE_C123:
+ case MODE_C123xor:
+ hdr = data_hdr_c123;
+ hdr_len = sizeof(data_hdr_c123);
+ break;
+ default:
+ break;
+ }
+
+ if (hdr && hdr_len)
+ memcpy(dnload.data, hdr, hdr_len);
+
+ /* 2 bytes for length + header */
+ file_data = dnload.data + 2 + hdr_len;
+
+ /* write the length, keep running XOR */
+ tot_len = hdr_len + st.st_size;
+ nibble = tot_len >> 8;
+ dnload.data[0] = nibble;
+ running_xor ^= nibble;
+ nibble = tot_len & 0xff;
+ dnload.data[1] = nibble;
+ running_xor ^= nibble;
+
+ if (hdr_len && hdr) {
+ memcpy(dnload.data+2, hdr, hdr_len);
+
+ for (i = 0; i < hdr_len; i++)
+ running_xor ^= hdr[i];
+ }
+
+ rc = read(fd, file_data, st.st_size);
+ if (rc < 0) {
+ perror("error reading file\n");
+ free(dnload.data);
+ dnload.data = NULL;
+ close(fd);
+ return -EIO;
+ }
+ if (rc < st.st_size) {
+ free(dnload.data);
+ dnload.data = NULL;
+ close(fd);
+ fprintf(stderr, "Short read of file (%d < %d)\n",
+ rc, (int)st.st_size);
+ return -EIO;
+ }
+
+ close(fd);
+
+ dnload.data_len = (file_data+st.st_size) - dnload.data;
+
+ /* calculate XOR sum */
+ for (i = 0; i < st.st_size; i++)
+ running_xor ^= file_data[i];
+
+ dnload.data[dnload.data_len++] = running_xor;
+
+ /* initialize write pointer to start of data */
+ dnload.write_ptr = dnload.data;
+
+ printf("read_file(%s): file_size=%u, hdr_len=%u, dnload_len=%u\n",
+ filename, (int)st.st_size, hdr_len, dnload.data_len);
+
+ return 0;
+}
+
+static void hexdump(const uint8_t *data, unsigned int len)
+{
+ const uint8_t *bufptr = data;
+ int n;
+
+ for (n=0; bufptr, n < len; n++, bufptr++)
+ printf("%02x ", *bufptr);
+ printf("\n");
+}
+
+#define WRITE_BLOCK 4096
+
+static int handle_write(void)
+{
+ int bytes_left, write_len, rc;
+
+ printf("handle_write(): ");
+ if (dnload.write_ptr == dnload.data) {
+ /* no bytes have been transferred yet */
+ if (dnload.mode == MODE_C155 ||
+ dnload.mode == MODE_C123xor) {
+ uint8_t xor_init = 0x02;
+ write(dnload.serial_fd.fd, &xor_init, 1);
+ } else
+ usleep(1);
+ } else if (dnload.write_ptr >= dnload.data + dnload.data_len) {
+ printf("finished\n");
+ dnload.write_ptr = dnload.data;
+ return 1;
+ }
+
+ /* try to write a maximum of WRITE_BLOCK bytes */
+ bytes_left = (dnload.data + dnload.data_len) - dnload.write_ptr;
+ write_len = WRITE_BLOCK;
+ if (bytes_left < WRITE_BLOCK)
+ write_len = bytes_left;
+
+ rc = write(dnload.serial_fd.fd, dnload.write_ptr, write_len);
+ if (rc < 0) {
+ perror("Error during write");
+ return rc;
+ }
+
+ dnload.write_ptr += rc;
+
+ printf("%u bytes (%tu/%u)\n", rc, dnload.write_ptr - dnload.data, dnload.data_len);
+
+ return 0;
+}
+
+static uint8_t buffer[sizeof(phone_prompt1)];
+static uint8_t *bufptr = buffer;
+
+static void hdlc_send_to_phone(uint8_t dlci, uint8_t *data, int len)
+{
+ struct msgb *msg;
+ uint8_t c, *dest;
+
+ if (len > 512) {
+ fprintf(stderr, "Too much data to send. %u\n", len);
+ return;
+ }
+
+ /* push the message into the stack */
+ msg = sercomm_alloc_msgb(512);
+ if (!msg) {
+ fprintf(stderr, "Failed to create data for the frame.\n");
+ return;
+ }
+
+ /* copy the data */
+ dest = msgb_put(msg, len);
+ memcpy(dest, data, len);
+
+ sercomm_sendmsg(dlci, msg);
+
+ /* drain the queue: TODO: do this through the select */
+ while (sercomm_drv_pull(&c) != 0)
+ if (write(dnload.serial_fd.fd, &c, 1) != 1)
+ perror("short write");
+}
+
+static void hdlc_console_cb(uint8_t dlci, struct msgb *msg)
+{
+ write(1, msg->data, msg->len);
+ msgb_free(msg);
+}
+
+static void hdlc_l1a_cb(uint8_t dlci, struct msgb *msg)
+{
+ struct layer2_connection *con;
+ u_int16_t *len;
+
+ len = (u_int16_t *) msgb_push(msg, 2);
+ *len = htons(msg->len - sizeof(*len));
+
+ llist_for_each_entry(con, &connections, entry) {
+ if (write(con->fd.fd, msg->data, msg->len) != msg->len) {
+ fprintf(stderr, "Failed to write msg to the socket..\n");
+ continue;
+ }
+ }
+
+ msgb_free(msg);
+}
+
+static void print_hdlc(uint8_t *buffer, int length)
+{
+ int i;
+
+ for (i = 0; i < length; ++i)
+ if (sercomm_drv_rx_char(buffer[i]) == 0)
+ printf("Dropping sample '%c'\n", buffer[i]);
+}
+
+static int handle_read(void)
+{
+ int rc, nbytes, buf_left;
+
+ buf_left = sizeof(buffer) - (bufptr - buffer);
+ if (buf_left <= 0) {
+ memmove(buffer, buffer+1, sizeof(buffer)-1);
+ bufptr -= 1;
+ buf_left = 1;
+ }
+
+ nbytes = read(dnload.serial_fd.fd, bufptr, buf_left);
+ if (nbytes <= 0)
+ return nbytes;
+
+ if (!dnload.print_hdlc) {
+ printf("got %i bytes from modem, ", nbytes);
+ printf("data looks like: ");
+ hexdump(bufptr, nbytes);
+ } else {
+ print_hdlc(bufptr, nbytes);
+ }
+
+ if (!memcmp(buffer, phone_prompt1, sizeof(phone_prompt1))) {
+ printf("Received PROMPT1 from phone, responding with CMD\n");
+ dnload.print_hdlc = 0;
+ dnload.state = WAITING_PROMPT2;
+ rc = write(dnload.serial_fd.fd, dnload_cmd, sizeof(dnload_cmd));
+
+ /* re-read file */
+ rc = read_file(dnload.filename);
+ if (rc < 0) {
+ fprintf(stderr, "read_file(%s) failed with %d\n", dnload.filename, rc);
+ exit(1);
+ }
+ } else if (!memcmp(buffer, phone_prompt2, sizeof(phone_prompt2))) {
+ printf("Received PROMPT2 from phone, starting download\n");
+ dnload.serial_fd.when = BSC_FD_READ | BSC_FD_WRITE;
+ dnload.state = DOWNLOADING;
+ } else if (!memcmp(buffer, phone_ack, sizeof(phone_ack))) {
+ printf("Received DOWNLOAD ACK from phone, your code is running now!\n");
+ dnload.serial_fd.when = BSC_FD_READ;
+ dnload.state = WAITING_PROMPT1;
+ dnload.write_ptr = dnload.data;
+ dnload.print_hdlc = 1;
+ } else if (!memcmp(buffer, phone_nack, sizeof(phone_nack))) {
+ printf("Received DOWNLOAD NACK from phone, something went wrong :(\n");
+ dnload.serial_fd.when = BSC_FD_READ;
+ dnload.state = WAITING_PROMPT1;
+ dnload.write_ptr = dnload.data;
+ } else if (!memcmp(buffer, phone_nack_magic, sizeof(phone_nack_magic))) {
+ printf("Received MAGIC NACK from phone, you need to have \"1003\" at 0x803ce0\n");
+ dnload.serial_fd.when = BSC_FD_READ;
+ dnload.state = WAITING_PROMPT1;
+ dnload.write_ptr = dnload.data;
+ } else if (!memcmp(buffer, ftmtool, sizeof(ftmtool))) {
+ printf("Received FTMTOOL from phone, ramolader has aborted\n");
+ dnload.serial_fd.when = BSC_FD_READ;
+ dnload.state = WAITING_PROMPT1;
+ dnload.write_ptr = dnload.data;
+ }
+ bufptr += nbytes;
+
+ return nbytes;
+}
+
+static int serial_read(struct bsc_fd *fd, unsigned int flags)
+{
+ int rc;
+
+ if (flags & BSC_FD_READ) {
+ rc = handle_read();
+ if (rc == 0)
+ exit(2);
+ }
+
+ if (flags & BSC_FD_WRITE) {
+ rc = handle_write();
+ if (rc == 1)
+ dnload.state = WAITING_PROMPT1;
+ }
+}
+
+static int parse_mode(const char *arg)
+{
+ if (!strcasecmp(arg, "c123") ||
+ !strcasecmp(arg, "c140"))
+ return MODE_C123;
+ else if (!strcasecmp(arg, "c123xor"))
+ return MODE_C123xor;
+ else if (!strcasecmp(arg, "c155"))
+ return MODE_C155;
+
+ return -1;
+}
+
+
+static int usage(const char *name)
+{
+ printf("\nUsage: %s [ -v | -h ] [ -p /dev/ttyXXXX ] [ -s /tmp/osmocom_l2 ] ][ -m {c123,c123xor,c155} ] file.bin\n", name);
+ printf("\t* Open serial port /dev/ttyXXXX (connected to your phone)\n"
+ "\t* Perform handshaking with the ramloader in the phone\n"
+ "\t* Download file.bin to the attached phone (base address 0x00800100)\n");
+ exit(2);
+}
+
+static int version(const char *name)
+{
+ printf("\n%s version %s\n", name, VERSION);
+ exit(2);
+}
+
+static int un_layer2_read(struct bsc_fd *fd, unsigned int flags)
+{
+ int rc;
+ u_int16_t length = 0xffff;
+ char buf[4096];
+ struct layer2_connection *con;
+
+
+ rc = read(fd->fd, &length, sizeof(length));
+ if (rc <= 0 || ntohs(length) > 512) {
+ fprintf(stderr, "Unexpected result from socket. rc: %d len: %d\n",
+ rc, ntohs(length));
+ goto close;
+ }
+
+ rc = read(fd->fd, buf, ntohs(length));
+ if (rc != ntohs(length)) {
+ fprintf(stderr, "Could not read data.\n");
+ goto close;
+ }
+
+ hdlc_send_to_phone(SC_DLCI_L1A_L23, buf, ntohs(length));
+
+ return 0;
+close:
+ con = (struct layer2_connection *) fd->data;
+
+ close(fd->fd);
+ bsc_unregister_fd(fd);
+ llist_del(&con->entry);
+ talloc_free(con);
+ return -1;
+}
+
+/* accept a new connection */
+static int un_layer2_accept(struct bsc_fd *fd, unsigned int flags)
+{
+ struct layer2_connection *con;
+ struct sockaddr_un un_addr;
+ socklen_t len;
+ int rc;
+
+ len = sizeof(un_addr);
+ rc = accept(fd->fd, (struct sockaddr *) &un_addr, &len);
+ if (rc < 0) {
+ fprintf(stderr, "Failed to accept a new connection.\n");
+ return -1;
+ }
+
+ con = talloc_zero(NULL, struct layer2_connection);
+ if (!con) {
+ fprintf(stderr, "Failed to create layer2 connection.\n");
+ return -1;
+ }
+
+ con->fd.fd = rc;
+ con->fd.when = BSC_FD_READ;
+ con->fd.cb = un_layer2_read;
+ con->fd.data = con;
+ if (bsc_register_fd(&con->fd) != 0) {
+ fprintf(stderr, "Failed to register the fd.\n");
+ return -1;
+ }
+
+ llist_add(&con->entry, &connections);
+}
+
+/*
+ * Create a server socket for the layer2 stack
+ */
+static int register_af_unix(const char *un_path)
+{
+ struct sockaddr_un local;
+ int rc;
+
+ dnload.socket.fd = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if (dnload.socket.fd < 0) {
+ fprintf(stderr, "Failed to create Unix Domain Socket.\n");
+ return -1;
+ }
+
+ local.sun_family = AF_UNIX;
+ strncpy(local.sun_path, un_path, sizeof(local.sun_path));
+ local.sun_path[sizeof(local.sun_path) - 1] = '\0';
+ unlink(local.sun_path);
+ rc = bind(dnload.socket.fd, (struct sockaddr *) &local,
+ sizeof(local.sun_family) + strlen(local.sun_path));
+ if (rc != 0) {
+ fprintf(stderr, "Failed to bind the unix domain socket. '%s'\n",
+ local.sun_path);
+ return -1;
+ }
+
+ if (listen(dnload.socket.fd, 0) != 0) {
+ fprintf(stderr, "Failed to listen.\n");
+ return -1;
+ }
+
+ dnload.socket.when = BSC_FD_READ;
+ dnload.socket.cb = un_layer2_accept;
+
+ if (bsc_register_fd(&dnload.socket) != 0) {
+ fprintf(stderr, "Failed to register the bfd.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int opt, flags;
+ char *serial_dev = "/dev/ttyUSB1";
+ char *un_path = "/tmp/osmocom_l2";
+
+ dnload.mode = MODE_C123;
+
+ while ((opt = getopt(argc, argv, "hp:m:s:v")) != -1) {
+ switch (opt) {
+ case 'p':
+ serial_dev = optarg;
+ break;
+ case 'm':
+ dnload.mode = parse_mode(optarg);
+ if (dnload.mode < 0)
+ usage(argv[0]);
+ break;
+ case 's':
+ un_path = optarg;
+ break;
+ case 'v':
+ version(argv[0]);
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (argc <= optind) {
+ fprintf(stderr, "You have to specify the filename\n");
+ usage(argv[0]);
+ }
+
+ dnload.filename = argv[optind];
+
+ dnload.serial_fd.fd = serial_init(serial_dev);
+ if (dnload.serial_fd.fd < 0) {
+ fprintf(stderr, "Cannot open serial device %s\n", serial_dev);
+ exit(1);
+ }
+
+ if (bsc_register_fd(&dnload.serial_fd) != 0) {
+ fprintf(stderr, "Failed to register the serial.\n");
+ exit(1);
+ }
+
+ /* Set serial socket to non-blocking mode of operation */
+ flags = fcntl(dnload.serial_fd.fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(dnload.serial_fd.fd, F_SETFL, flags);
+
+ dnload.serial_fd.when = BSC_FD_READ;
+ dnload.serial_fd.cb = serial_read;
+
+ /* unix domain socket handling */
+ if (register_af_unix(un_path) != 0)
+ exit(1);
+
+
+ /* initialize the HDLC layer */
+ sercomm_init();
+ sercomm_register_rx_cb(SC_DLCI_CONSOLE, hdlc_console_cb);
+ sercomm_register_rx_cb(SC_DLCI_L1A_L23, hdlc_l1a_cb);
+ while (1)
+ bsc_select_main(0);
+
+ close(dnload.serial_fd.fd);
+
+ exit(0);
+}
diff --git a/src/host/rita_pll/rita_pll.pl b/src/host/rita_pll/rita_pll.pl
new file mode 100755
index 00000000..7de1aec4
--- /dev/null
+++ b/src/host/rita_pll/rita_pll.pl
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+
+sub pll_rx($$$$$) {
+ my ($a, $b, $p, $r, $l) = @_;
+
+ return (($b*$p+$a)/($r*$l))*26;
+}
+
+sub pll_rx_low_band($$) {
+ my ($a, $b) = @_;
+ my $p = 64; my $r = 65; my $l = 4;
+ return pll_rx($a, $b, $p, $r, $l);
+}
+
+sub pll_rx_high_band($$) {
+ my ($a, $b) = @_;
+ my $p = 64; my $r = 65; my $l = 2;
+ return pll_rx($a, $b, $p, $r, $l);
+}
+
+sub pll_tx_gsm850_1($$) {
+ my ($a, $b) = @_;
+ my $p = 64; my $r = 55; my $l = 4; my $m = 26;
+
+ my $left = ((1/$l) - (1/$m));
+ my $right = (($b*$p+$a)/$r);
+
+ return $left * $right * 26;
+}
+
+sub pll_tx_gsm850_2($$) {
+ my ($a, $b) = @_;
+ my $p = 64; my $r = 30; my $l = 4; my $m = 52;
+
+ my $left = ((1/$l) - (1/$m));
+ my $right = (($b*$p+$a)/$r);
+
+ return $left * $right * 26;
+}
+
+sub pll_tx_gsm900($$) {
+ my ($a, $b) = @_;
+ my $p = 64; my $r = 35; my $l = 4; my $m = 52;
+
+ my $left = ((1/$l) + (1/$m));
+ my $right = (($b*$p+$a)/$r);
+
+ return $left * $right * 26;
+}
+
+sub pll_tx_high($$) {
+ my ($a, $b) = @_;
+ my $p = 64; my $r = 70; my $l = 2; my $m = 26;
+
+ my $left = ((1/$l) + (1/$m));
+ my $right = (($b*$p+$a)/$r);
+
+ return $left * $right * 26;
+}
+
+sub hr() {
+ printf("======================================================================\n");
+}
+
+printf("PLL Rx Low Band:\n");
+for (my $b = 135; $b <= 150; $b++) {
+ for (my $a = 0; $a <= 62; $a++) {
+ printf("Fout=%4.2f (A=%03u, B=%03u)\n", pll_rx_low_band($a, $b), $a, $b);
+ }
+}
+
+hr();
+printf("PLL Rx High Band:\n");
+for (my $b = 141; $b <= 155; $b++) {
+ for (my $a = 0; $a <= 62; $a++) {
+ printf("Fout=%4.2f (A=%03u, B=%03u)\n", pll_rx_high_band($a, $b), $a, $b);
+ }
+}
+
+hr();
+printf("PLL Tx GSM850_1\n");
+for (my $b = 128; $b <= 130; $b++) {
+ for (my $a = 0; $a <= 62; $a++) {
+ printf("Fout=%4.2f (A=%03u, B=%03u)\n", pll_tx_gsm850_1($a, $b), $a, $b);
+ }
+}
+
+hr();
+printf("PLL Tx GSM850_2\n");
+for (my $b = 65; $b <= 66; $b++) {
+ for (my $a = 0; $a <= 63; $a++) {
+ printf("Fout=%4.2f (A=%03u, B=%03u)\n", pll_tx_gsm850_2($a, $b), $a, $b);
+ }
+}
+
+hr();
+printf("PLL Tx GSM900\n");
+for (my $b = 68; $b <= 71; $b++) {
+ for (my $a = 0; $a <= 63; $a++) {
+ printf("Fout=%4.2f (A=%03u, B=%03u)\n", pll_tx_gsm900($a, $b), $a, $b);
+ }
+}
+
+hr();
+printf("PLL Tx GSM1800/1900\n");
+for (my $b = 133; $b <= 149; $b++) {
+ for (my $a = 0; $a <= 63; $a++) {
+ printf("Fout=%4.2f (A=%03u, B=%03u)\n", pll_tx_high($a, $b), $a, $b);
+ }
+}
+
diff --git a/src/host/rita_pll/rita_pll.txt b/src/host/rita_pll/rita_pll.txt
new file mode 100644
index 00000000..cac2cac2
--- /dev/null
+++ b/src/host/rita_pll/rita_pll.txt
@@ -0,0 +1,3625 @@
+PLL Rx Low Band:
+Fout=864.00 (A=000, B=135)
+Fout=864.10 (A=001, B=135)
+Fout=864.20 (A=002, B=135)
+Fout=864.30 (A=003, B=135)
+Fout=864.40 (A=004, B=135)
+Fout=864.50 (A=005, B=135)
+Fout=864.60 (A=006, B=135)
+Fout=864.70 (A=007, B=135)
+Fout=864.80 (A=008, B=135)
+Fout=864.90 (A=009, B=135)
+Fout=865.00 (A=010, B=135)
+Fout=865.10 (A=011, B=135)
+Fout=865.20 (A=012, B=135)
+Fout=865.30 (A=013, B=135)
+Fout=865.40 (A=014, B=135)
+Fout=865.50 (A=015, B=135)
+Fout=865.60 (A=016, B=135)
+Fout=865.70 (A=017, B=135)
+Fout=865.80 (A=018, B=135)
+Fout=865.90 (A=019, B=135)
+Fout=866.00 (A=020, B=135)
+Fout=866.10 (A=021, B=135)
+Fout=866.20 (A=022, B=135)
+Fout=866.30 (A=023, B=135)
+Fout=866.40 (A=024, B=135)
+Fout=866.50 (A=025, B=135)
+Fout=866.60 (A=026, B=135)
+Fout=866.70 (A=027, B=135)
+Fout=866.80 (A=028, B=135)
+Fout=866.90 (A=029, B=135)
+Fout=867.00 (A=030, B=135)
+Fout=867.10 (A=031, B=135)
+Fout=867.20 (A=032, B=135)
+Fout=867.30 (A=033, B=135)
+Fout=867.40 (A=034, B=135)
+Fout=867.50 (A=035, B=135)
+Fout=867.60 (A=036, B=135)
+Fout=867.70 (A=037, B=135)
+Fout=867.80 (A=038, B=135)
+Fout=867.90 (A=039, B=135)
+Fout=868.00 (A=040, B=135)
+Fout=868.10 (A=041, B=135)
+Fout=868.20 (A=042, B=135)
+Fout=868.30 (A=043, B=135)
+Fout=868.40 (A=044, B=135)
+Fout=868.50 (A=045, B=135)
+Fout=868.60 (A=046, B=135)
+Fout=868.70 (A=047, B=135)
+Fout=868.80 (A=048, B=135)
+Fout=868.90 (A=049, B=135)
+Fout=869.00 (A=050, B=135)
+Fout=869.10 (A=051, B=135)
+Fout=869.20 (A=052, B=135)
+Fout=869.30 (A=053, B=135)
+Fout=869.40 (A=054, B=135)
+Fout=869.50 (A=055, B=135)
+Fout=869.60 (A=056, B=135)
+Fout=869.70 (A=057, B=135)
+Fout=869.80 (A=058, B=135)
+Fout=869.90 (A=059, B=135)
+Fout=870.00 (A=060, B=135)
+Fout=870.10 (A=061, B=135)
+Fout=870.20 (A=062, B=135)
+Fout=870.40 (A=000, B=136)
+Fout=870.50 (A=001, B=136)
+Fout=870.60 (A=002, B=136)
+Fout=870.70 (A=003, B=136)
+Fout=870.80 (A=004, B=136)
+Fout=870.90 (A=005, B=136)
+Fout=871.00 (A=006, B=136)
+Fout=871.10 (A=007, B=136)
+Fout=871.20 (A=008, B=136)
+Fout=871.30 (A=009, B=136)
+Fout=871.40 (A=010, B=136)
+Fout=871.50 (A=011, B=136)
+Fout=871.60 (A=012, B=136)
+Fout=871.70 (A=013, B=136)
+Fout=871.80 (A=014, B=136)
+Fout=871.90 (A=015, B=136)
+Fout=872.00 (A=016, B=136)
+Fout=872.10 (A=017, B=136)
+Fout=872.20 (A=018, B=136)
+Fout=872.30 (A=019, B=136)
+Fout=872.40 (A=020, B=136)
+Fout=872.50 (A=021, B=136)
+Fout=872.60 (A=022, B=136)
+Fout=872.70 (A=023, B=136)
+Fout=872.80 (A=024, B=136)
+Fout=872.90 (A=025, B=136)
+Fout=873.00 (A=026, B=136)
+Fout=873.10 (A=027, B=136)
+Fout=873.20 (A=028, B=136)
+Fout=873.30 (A=029, B=136)
+Fout=873.40 (A=030, B=136)
+Fout=873.50 (A=031, B=136)
+Fout=873.60 (A=032, B=136)
+Fout=873.70 (A=033, B=136)
+Fout=873.80 (A=034, B=136)
+Fout=873.90 (A=035, B=136)
+Fout=874.00 (A=036, B=136)
+Fout=874.10 (A=037, B=136)
+Fout=874.20 (A=038, B=136)
+Fout=874.30 (A=039, B=136)
+Fout=874.40 (A=040, B=136)
+Fout=874.50 (A=041, B=136)
+Fout=874.60 (A=042, B=136)
+Fout=874.70 (A=043, B=136)
+Fout=874.80 (A=044, B=136)
+Fout=874.90 (A=045, B=136)
+Fout=875.00 (A=046, B=136)
+Fout=875.10 (A=047, B=136)
+Fout=875.20 (A=048, B=136)
+Fout=875.30 (A=049, B=136)
+Fout=875.40 (A=050, B=136)
+Fout=875.50 (A=051, B=136)
+Fout=875.60 (A=052, B=136)
+Fout=875.70 (A=053, B=136)
+Fout=875.80 (A=054, B=136)
+Fout=875.90 (A=055, B=136)
+Fout=876.00 (A=056, B=136)
+Fout=876.10 (A=057, B=136)
+Fout=876.20 (A=058, B=136)
+Fout=876.30 (A=059, B=136)
+Fout=876.40 (A=060, B=136)
+Fout=876.50 (A=061, B=136)
+Fout=876.60 (A=062, B=136)
+Fout=876.80 (A=000, B=137)
+Fout=876.90 (A=001, B=137)
+Fout=877.00 (A=002, B=137)
+Fout=877.10 (A=003, B=137)
+Fout=877.20 (A=004, B=137)
+Fout=877.30 (A=005, B=137)
+Fout=877.40 (A=006, B=137)
+Fout=877.50 (A=007, B=137)
+Fout=877.60 (A=008, B=137)
+Fout=877.70 (A=009, B=137)
+Fout=877.80 (A=010, B=137)
+Fout=877.90 (A=011, B=137)
+Fout=878.00 (A=012, B=137)
+Fout=878.10 (A=013, B=137)
+Fout=878.20 (A=014, B=137)
+Fout=878.30 (A=015, B=137)
+Fout=878.40 (A=016, B=137)
+Fout=878.50 (A=017, B=137)
+Fout=878.60 (A=018, B=137)
+Fout=878.70 (A=019, B=137)
+Fout=878.80 (A=020, B=137)
+Fout=878.90 (A=021, B=137)
+Fout=879.00 (A=022, B=137)
+Fout=879.10 (A=023, B=137)
+Fout=879.20 (A=024, B=137)
+Fout=879.30 (A=025, B=137)
+Fout=879.40 (A=026, B=137)
+Fout=879.50 (A=027, B=137)
+Fout=879.60 (A=028, B=137)
+Fout=879.70 (A=029, B=137)
+Fout=879.80 (A=030, B=137)
+Fout=879.90 (A=031, B=137)
+Fout=880.00 (A=032, B=137)
+Fout=880.10 (A=033, B=137)
+Fout=880.20 (A=034, B=137)
+Fout=880.30 (A=035, B=137)
+Fout=880.40 (A=036, B=137)
+Fout=880.50 (A=037, B=137)
+Fout=880.60 (A=038, B=137)
+Fout=880.70 (A=039, B=137)
+Fout=880.80 (A=040, B=137)
+Fout=880.90 (A=041, B=137)
+Fout=881.00 (A=042, B=137)
+Fout=881.10 (A=043, B=137)
+Fout=881.20 (A=044, B=137)
+Fout=881.30 (A=045, B=137)
+Fout=881.40 (A=046, B=137)
+Fout=881.50 (A=047, B=137)
+Fout=881.60 (A=048, B=137)
+Fout=881.70 (A=049, B=137)
+Fout=881.80 (A=050, B=137)
+Fout=881.90 (A=051, B=137)
+Fout=882.00 (A=052, B=137)
+Fout=882.10 (A=053, B=137)
+Fout=882.20 (A=054, B=137)
+Fout=882.30 (A=055, B=137)
+Fout=882.40 (A=056, B=137)
+Fout=882.50 (A=057, B=137)
+Fout=882.60 (A=058, B=137)
+Fout=882.70 (A=059, B=137)
+Fout=882.80 (A=060, B=137)
+Fout=882.90 (A=061, B=137)
+Fout=883.00 (A=062, B=137)
+Fout=883.20 (A=000, B=138)
+Fout=883.30 (A=001, B=138)
+Fout=883.40 (A=002, B=138)
+Fout=883.50 (A=003, B=138)
+Fout=883.60 (A=004, B=138)
+Fout=883.70 (A=005, B=138)
+Fout=883.80 (A=006, B=138)
+Fout=883.90 (A=007, B=138)
+Fout=884.00 (A=008, B=138)
+Fout=884.10 (A=009, B=138)
+Fout=884.20 (A=010, B=138)
+Fout=884.30 (A=011, B=138)
+Fout=884.40 (A=012, B=138)
+Fout=884.50 (A=013, B=138)
+Fout=884.60 (A=014, B=138)
+Fout=884.70 (A=015, B=138)
+Fout=884.80 (A=016, B=138)
+Fout=884.90 (A=017, B=138)
+Fout=885.00 (A=018, B=138)
+Fout=885.10 (A=019, B=138)
+Fout=885.20 (A=020, B=138)
+Fout=885.30 (A=021, B=138)
+Fout=885.40 (A=022, B=138)
+Fout=885.50 (A=023, B=138)
+Fout=885.60 (A=024, B=138)
+Fout=885.70 (A=025, B=138)
+Fout=885.80 (A=026, B=138)
+Fout=885.90 (A=027, B=138)
+Fout=886.00 (A=028, B=138)
+Fout=886.10 (A=029, B=138)
+Fout=886.20 (A=030, B=138)
+Fout=886.30 (A=031, B=138)
+Fout=886.40 (A=032, B=138)
+Fout=886.50 (A=033, B=138)
+Fout=886.60 (A=034, B=138)
+Fout=886.70 (A=035, B=138)
+Fout=886.80 (A=036, B=138)
+Fout=886.90 (A=037, B=138)
+Fout=887.00 (A=038, B=138)
+Fout=887.10 (A=039, B=138)
+Fout=887.20 (A=040, B=138)
+Fout=887.30 (A=041, B=138)
+Fout=887.40 (A=042, B=138)
+Fout=887.50 (A=043, B=138)
+Fout=887.60 (A=044, B=138)
+Fout=887.70 (A=045, B=138)
+Fout=887.80 (A=046, B=138)
+Fout=887.90 (A=047, B=138)
+Fout=888.00 (A=048, B=138)
+Fout=888.10 (A=049, B=138)
+Fout=888.20 (A=050, B=138)
+Fout=888.30 (A=051, B=138)
+Fout=888.40 (A=052, B=138)
+Fout=888.50 (A=053, B=138)
+Fout=888.60 (A=054, B=138)
+Fout=888.70 (A=055, B=138)
+Fout=888.80 (A=056, B=138)
+Fout=888.90 (A=057, B=138)
+Fout=889.00 (A=058, B=138)
+Fout=889.10 (A=059, B=138)
+Fout=889.20 (A=060, B=138)
+Fout=889.30 (A=061, B=138)
+Fout=889.40 (A=062, B=138)
+Fout=889.60 (A=000, B=139)
+Fout=889.70 (A=001, B=139)
+Fout=889.80 (A=002, B=139)
+Fout=889.90 (A=003, B=139)
+Fout=890.00 (A=004, B=139)
+Fout=890.10 (A=005, B=139)
+Fout=890.20 (A=006, B=139)
+Fout=890.30 (A=007, B=139)
+Fout=890.40 (A=008, B=139)
+Fout=890.50 (A=009, B=139)
+Fout=890.60 (A=010, B=139)
+Fout=890.70 (A=011, B=139)
+Fout=890.80 (A=012, B=139)
+Fout=890.90 (A=013, B=139)
+Fout=891.00 (A=014, B=139)
+Fout=891.10 (A=015, B=139)
+Fout=891.20 (A=016, B=139)
+Fout=891.30 (A=017, B=139)
+Fout=891.40 (A=018, B=139)
+Fout=891.50 (A=019, B=139)
+Fout=891.60 (A=020, B=139)
+Fout=891.70 (A=021, B=139)
+Fout=891.80 (A=022, B=139)
+Fout=891.90 (A=023, B=139)
+Fout=892.00 (A=024, B=139)
+Fout=892.10 (A=025, B=139)
+Fout=892.20 (A=026, B=139)
+Fout=892.30 (A=027, B=139)
+Fout=892.40 (A=028, B=139)
+Fout=892.50 (A=029, B=139)
+Fout=892.60 (A=030, B=139)
+Fout=892.70 (A=031, B=139)
+Fout=892.80 (A=032, B=139)
+Fout=892.90 (A=033, B=139)
+Fout=893.00 (A=034, B=139)
+Fout=893.10 (A=035, B=139)
+Fout=893.20 (A=036, B=139)
+Fout=893.30 (A=037, B=139)
+Fout=893.40 (A=038, B=139)
+Fout=893.50 (A=039, B=139)
+Fout=893.60 (A=040, B=139)
+Fout=893.70 (A=041, B=139)
+Fout=893.80 (A=042, B=139)
+Fout=893.90 (A=043, B=139)
+Fout=894.00 (A=044, B=139)
+Fout=894.10 (A=045, B=139)
+Fout=894.20 (A=046, B=139)
+Fout=894.30 (A=047, B=139)
+Fout=894.40 (A=048, B=139)
+Fout=894.50 (A=049, B=139)
+Fout=894.60 (A=050, B=139)
+Fout=894.70 (A=051, B=139)
+Fout=894.80 (A=052, B=139)
+Fout=894.90 (A=053, B=139)
+Fout=895.00 (A=054, B=139)
+Fout=895.10 (A=055, B=139)
+Fout=895.20 (A=056, B=139)
+Fout=895.30 (A=057, B=139)
+Fout=895.40 (A=058, B=139)
+Fout=895.50 (A=059, B=139)
+Fout=895.60 (A=060, B=139)
+Fout=895.70 (A=061, B=139)
+Fout=895.80 (A=062, B=139)
+Fout=896.00 (A=000, B=140)
+Fout=896.10 (A=001, B=140)
+Fout=896.20 (A=002, B=140)
+Fout=896.30 (A=003, B=140)
+Fout=896.40 (A=004, B=140)
+Fout=896.50 (A=005, B=140)
+Fout=896.60 (A=006, B=140)
+Fout=896.70 (A=007, B=140)
+Fout=896.80 (A=008, B=140)
+Fout=896.90 (A=009, B=140)
+Fout=897.00 (A=010, B=140)
+Fout=897.10 (A=011, B=140)
+Fout=897.20 (A=012, B=140)
+Fout=897.30 (A=013, B=140)
+Fout=897.40 (A=014, B=140)
+Fout=897.50 (A=015, B=140)
+Fout=897.60 (A=016, B=140)
+Fout=897.70 (A=017, B=140)
+Fout=897.80 (A=018, B=140)
+Fout=897.90 (A=019, B=140)
+Fout=898.00 (A=020, B=140)
+Fout=898.10 (A=021, B=140)
+Fout=898.20 (A=022, B=140)
+Fout=898.30 (A=023, B=140)
+Fout=898.40 (A=024, B=140)
+Fout=898.50 (A=025, B=140)
+Fout=898.60 (A=026, B=140)
+Fout=898.70 (A=027, B=140)
+Fout=898.80 (A=028, B=140)
+Fout=898.90 (A=029, B=140)
+Fout=899.00 (A=030, B=140)
+Fout=899.10 (A=031, B=140)
+Fout=899.20 (A=032, B=140)
+Fout=899.30 (A=033, B=140)
+Fout=899.40 (A=034, B=140)
+Fout=899.50 (A=035, B=140)
+Fout=899.60 (A=036, B=140)
+Fout=899.70 (A=037, B=140)
+Fout=899.80 (A=038, B=140)
+Fout=899.90 (A=039, B=140)
+Fout=900.00 (A=040, B=140)
+Fout=900.10 (A=041, B=140)
+Fout=900.20 (A=042, B=140)
+Fout=900.30 (A=043, B=140)
+Fout=900.40 (A=044, B=140)
+Fout=900.50 (A=045, B=140)
+Fout=900.60 (A=046, B=140)
+Fout=900.70 (A=047, B=140)
+Fout=900.80 (A=048, B=140)
+Fout=900.90 (A=049, B=140)
+Fout=901.00 (A=050, B=140)
+Fout=901.10 (A=051, B=140)
+Fout=901.20 (A=052, B=140)
+Fout=901.30 (A=053, B=140)
+Fout=901.40 (A=054, B=140)
+Fout=901.50 (A=055, B=140)
+Fout=901.60 (A=056, B=140)
+Fout=901.70 (A=057, B=140)
+Fout=901.80 (A=058, B=140)
+Fout=901.90 (A=059, B=140)
+Fout=902.00 (A=060, B=140)
+Fout=902.10 (A=061, B=140)
+Fout=902.20 (A=062, B=140)
+Fout=902.40 (A=000, B=141)
+Fout=902.50 (A=001, B=141)
+Fout=902.60 (A=002, B=141)
+Fout=902.70 (A=003, B=141)
+Fout=902.80 (A=004, B=141)
+Fout=902.90 (A=005, B=141)
+Fout=903.00 (A=006, B=141)
+Fout=903.10 (A=007, B=141)
+Fout=903.20 (A=008, B=141)
+Fout=903.30 (A=009, B=141)
+Fout=903.40 (A=010, B=141)
+Fout=903.50 (A=011, B=141)
+Fout=903.60 (A=012, B=141)
+Fout=903.70 (A=013, B=141)
+Fout=903.80 (A=014, B=141)
+Fout=903.90 (A=015, B=141)
+Fout=904.00 (A=016, B=141)
+Fout=904.10 (A=017, B=141)
+Fout=904.20 (A=018, B=141)
+Fout=904.30 (A=019, B=141)
+Fout=904.40 (A=020, B=141)
+Fout=904.50 (A=021, B=141)
+Fout=904.60 (A=022, B=141)
+Fout=904.70 (A=023, B=141)
+Fout=904.80 (A=024, B=141)
+Fout=904.90 (A=025, B=141)
+Fout=905.00 (A=026, B=141)
+Fout=905.10 (A=027, B=141)
+Fout=905.20 (A=028, B=141)
+Fout=905.30 (A=029, B=141)
+Fout=905.40 (A=030, B=141)
+Fout=905.50 (A=031, B=141)
+Fout=905.60 (A=032, B=141)
+Fout=905.70 (A=033, B=141)
+Fout=905.80 (A=034, B=141)
+Fout=905.90 (A=035, B=141)
+Fout=906.00 (A=036, B=141)
+Fout=906.10 (A=037, B=141)
+Fout=906.20 (A=038, B=141)
+Fout=906.30 (A=039, B=141)
+Fout=906.40 (A=040, B=141)
+Fout=906.50 (A=041, B=141)
+Fout=906.60 (A=042, B=141)
+Fout=906.70 (A=043, B=141)
+Fout=906.80 (A=044, B=141)
+Fout=906.90 (A=045, B=141)
+Fout=907.00 (A=046, B=141)
+Fout=907.10 (A=047, B=141)
+Fout=907.20 (A=048, B=141)
+Fout=907.30 (A=049, B=141)
+Fout=907.40 (A=050, B=141)
+Fout=907.50 (A=051, B=141)
+Fout=907.60 (A=052, B=141)
+Fout=907.70 (A=053, B=141)
+Fout=907.80 (A=054, B=141)
+Fout=907.90 (A=055, B=141)
+Fout=908.00 (A=056, B=141)
+Fout=908.10 (A=057, B=141)
+Fout=908.20 (A=058, B=141)
+Fout=908.30 (A=059, B=141)
+Fout=908.40 (A=060, B=141)
+Fout=908.50 (A=061, B=141)
+Fout=908.60 (A=062, B=141)
+Fout=908.80 (A=000, B=142)
+Fout=908.90 (A=001, B=142)
+Fout=909.00 (A=002, B=142)
+Fout=909.10 (A=003, B=142)
+Fout=909.20 (A=004, B=142)
+Fout=909.30 (A=005, B=142)
+Fout=909.40 (A=006, B=142)
+Fout=909.50 (A=007, B=142)
+Fout=909.60 (A=008, B=142)
+Fout=909.70 (A=009, B=142)
+Fout=909.80 (A=010, B=142)
+Fout=909.90 (A=011, B=142)
+Fout=910.00 (A=012, B=142)
+Fout=910.10 (A=013, B=142)
+Fout=910.20 (A=014, B=142)
+Fout=910.30 (A=015, B=142)
+Fout=910.40 (A=016, B=142)
+Fout=910.50 (A=017, B=142)
+Fout=910.60 (A=018, B=142)
+Fout=910.70 (A=019, B=142)
+Fout=910.80 (A=020, B=142)
+Fout=910.90 (A=021, B=142)
+Fout=911.00 (A=022, B=142)
+Fout=911.10 (A=023, B=142)
+Fout=911.20 (A=024, B=142)
+Fout=911.30 (A=025, B=142)
+Fout=911.40 (A=026, B=142)
+Fout=911.50 (A=027, B=142)
+Fout=911.60 (A=028, B=142)
+Fout=911.70 (A=029, B=142)
+Fout=911.80 (A=030, B=142)
+Fout=911.90 (A=031, B=142)
+Fout=912.00 (A=032, B=142)
+Fout=912.10 (A=033, B=142)
+Fout=912.20 (A=034, B=142)
+Fout=912.30 (A=035, B=142)
+Fout=912.40 (A=036, B=142)
+Fout=912.50 (A=037, B=142)
+Fout=912.60 (A=038, B=142)
+Fout=912.70 (A=039, B=142)
+Fout=912.80 (A=040, B=142)
+Fout=912.90 (A=041, B=142)
+Fout=913.00 (A=042, B=142)
+Fout=913.10 (A=043, B=142)
+Fout=913.20 (A=044, B=142)
+Fout=913.30 (A=045, B=142)
+Fout=913.40 (A=046, B=142)
+Fout=913.50 (A=047, B=142)
+Fout=913.60 (A=048, B=142)
+Fout=913.70 (A=049, B=142)
+Fout=913.80 (A=050, B=142)
+Fout=913.90 (A=051, B=142)
+Fout=914.00 (A=052, B=142)
+Fout=914.10 (A=053, B=142)
+Fout=914.20 (A=054, B=142)
+Fout=914.30 (A=055, B=142)
+Fout=914.40 (A=056, B=142)
+Fout=914.50 (A=057, B=142)
+Fout=914.60 (A=058, B=142)
+Fout=914.70 (A=059, B=142)
+Fout=914.80 (A=060, B=142)
+Fout=914.90 (A=061, B=142)
+Fout=915.00 (A=062, B=142)
+Fout=915.20 (A=000, B=143)
+Fout=915.30 (A=001, B=143)
+Fout=915.40 (A=002, B=143)
+Fout=915.50 (A=003, B=143)
+Fout=915.60 (A=004, B=143)
+Fout=915.70 (A=005, B=143)
+Fout=915.80 (A=006, B=143)
+Fout=915.90 (A=007, B=143)
+Fout=916.00 (A=008, B=143)
+Fout=916.10 (A=009, B=143)
+Fout=916.20 (A=010, B=143)
+Fout=916.30 (A=011, B=143)
+Fout=916.40 (A=012, B=143)
+Fout=916.50 (A=013, B=143)
+Fout=916.60 (A=014, B=143)
+Fout=916.70 (A=015, B=143)
+Fout=916.80 (A=016, B=143)
+Fout=916.90 (A=017, B=143)
+Fout=917.00 (A=018, B=143)
+Fout=917.10 (A=019, B=143)
+Fout=917.20 (A=020, B=143)
+Fout=917.30 (A=021, B=143)
+Fout=917.40 (A=022, B=143)
+Fout=917.50 (A=023, B=143)
+Fout=917.60 (A=024, B=143)
+Fout=917.70 (A=025, B=143)
+Fout=917.80 (A=026, B=143)
+Fout=917.90 (A=027, B=143)
+Fout=918.00 (A=028, B=143)
+Fout=918.10 (A=029, B=143)
+Fout=918.20 (A=030, B=143)
+Fout=918.30 (A=031, B=143)
+Fout=918.40 (A=032, B=143)
+Fout=918.50 (A=033, B=143)
+Fout=918.60 (A=034, B=143)
+Fout=918.70 (A=035, B=143)
+Fout=918.80 (A=036, B=143)
+Fout=918.90 (A=037, B=143)
+Fout=919.00 (A=038, B=143)
+Fout=919.10 (A=039, B=143)
+Fout=919.20 (A=040, B=143)
+Fout=919.30 (A=041, B=143)
+Fout=919.40 (A=042, B=143)
+Fout=919.50 (A=043, B=143)
+Fout=919.60 (A=044, B=143)
+Fout=919.70 (A=045, B=143)
+Fout=919.80 (A=046, B=143)
+Fout=919.90 (A=047, B=143)
+Fout=920.00 (A=048, B=143)
+Fout=920.10 (A=049, B=143)
+Fout=920.20 (A=050, B=143)
+Fout=920.30 (A=051, B=143)
+Fout=920.40 (A=052, B=143)
+Fout=920.50 (A=053, B=143)
+Fout=920.60 (A=054, B=143)
+Fout=920.70 (A=055, B=143)
+Fout=920.80 (A=056, B=143)
+Fout=920.90 (A=057, B=143)
+Fout=921.00 (A=058, B=143)
+Fout=921.10 (A=059, B=143)
+Fout=921.20 (A=060, B=143)
+Fout=921.30 (A=061, B=143)
+Fout=921.40 (A=062, B=143)
+Fout=921.60 (A=000, B=144)
+Fout=921.70 (A=001, B=144)
+Fout=921.80 (A=002, B=144)
+Fout=921.90 (A=003, B=144)
+Fout=922.00 (A=004, B=144)
+Fout=922.10 (A=005, B=144)
+Fout=922.20 (A=006, B=144)
+Fout=922.30 (A=007, B=144)
+Fout=922.40 (A=008, B=144)
+Fout=922.50 (A=009, B=144)
+Fout=922.60 (A=010, B=144)
+Fout=922.70 (A=011, B=144)
+Fout=922.80 (A=012, B=144)
+Fout=922.90 (A=013, B=144)
+Fout=923.00 (A=014, B=144)
+Fout=923.10 (A=015, B=144)
+Fout=923.20 (A=016, B=144)
+Fout=923.30 (A=017, B=144)
+Fout=923.40 (A=018, B=144)
+Fout=923.50 (A=019, B=144)
+Fout=923.60 (A=020, B=144)
+Fout=923.70 (A=021, B=144)
+Fout=923.80 (A=022, B=144)
+Fout=923.90 (A=023, B=144)
+Fout=924.00 (A=024, B=144)
+Fout=924.10 (A=025, B=144)
+Fout=924.20 (A=026, B=144)
+Fout=924.30 (A=027, B=144)
+Fout=924.40 (A=028, B=144)
+Fout=924.50 (A=029, B=144)
+Fout=924.60 (A=030, B=144)
+Fout=924.70 (A=031, B=144)
+Fout=924.80 (A=032, B=144)
+Fout=924.90 (A=033, B=144)
+Fout=925.00 (A=034, B=144)
+Fout=925.10 (A=035, B=144)
+Fout=925.20 (A=036, B=144)
+Fout=925.30 (A=037, B=144)
+Fout=925.40 (A=038, B=144)
+Fout=925.50 (A=039, B=144)
+Fout=925.60 (A=040, B=144)
+Fout=925.70 (A=041, B=144)
+Fout=925.80 (A=042, B=144)
+Fout=925.90 (A=043, B=144)
+Fout=926.00 (A=044, B=144)
+Fout=926.10 (A=045, B=144)
+Fout=926.20 (A=046, B=144)
+Fout=926.30 (A=047, B=144)
+Fout=926.40 (A=048, B=144)
+Fout=926.50 (A=049, B=144)
+Fout=926.60 (A=050, B=144)
+Fout=926.70 (A=051, B=144)
+Fout=926.80 (A=052, B=144)
+Fout=926.90 (A=053, B=144)
+Fout=927.00 (A=054, B=144)
+Fout=927.10 (A=055, B=144)
+Fout=927.20 (A=056, B=144)
+Fout=927.30 (A=057, B=144)
+Fout=927.40 (A=058, B=144)
+Fout=927.50 (A=059, B=144)
+Fout=927.60 (A=060, B=144)
+Fout=927.70 (A=061, B=144)
+Fout=927.80 (A=062, B=144)
+Fout=928.00 (A=000, B=145)
+Fout=928.10 (A=001, B=145)
+Fout=928.20 (A=002, B=145)
+Fout=928.30 (A=003, B=145)
+Fout=928.40 (A=004, B=145)
+Fout=928.50 (A=005, B=145)
+Fout=928.60 (A=006, B=145)
+Fout=928.70 (A=007, B=145)
+Fout=928.80 (A=008, B=145)
+Fout=928.90 (A=009, B=145)
+Fout=929.00 (A=010, B=145)
+Fout=929.10 (A=011, B=145)
+Fout=929.20 (A=012, B=145)
+Fout=929.30 (A=013, B=145)
+Fout=929.40 (A=014, B=145)
+Fout=929.50 (A=015, B=145)
+Fout=929.60 (A=016, B=145)
+Fout=929.70 (A=017, B=145)
+Fout=929.80 (A=018, B=145)
+Fout=929.90 (A=019, B=145)
+Fout=930.00 (A=020, B=145)
+Fout=930.10 (A=021, B=145)
+Fout=930.20 (A=022, B=145)
+Fout=930.30 (A=023, B=145)
+Fout=930.40 (A=024, B=145)
+Fout=930.50 (A=025, B=145)
+Fout=930.60 (A=026, B=145)
+Fout=930.70 (A=027, B=145)
+Fout=930.80 (A=028, B=145)
+Fout=930.90 (A=029, B=145)
+Fout=931.00 (A=030, B=145)
+Fout=931.10 (A=031, B=145)
+Fout=931.20 (A=032, B=145)
+Fout=931.30 (A=033, B=145)
+Fout=931.40 (A=034, B=145)
+Fout=931.50 (A=035, B=145)
+Fout=931.60 (A=036, B=145)
+Fout=931.70 (A=037, B=145)
+Fout=931.80 (A=038, B=145)
+Fout=931.90 (A=039, B=145)
+Fout=932.00 (A=040, B=145)
+Fout=932.10 (A=041, B=145)
+Fout=932.20 (A=042, B=145)
+Fout=932.30 (A=043, B=145)
+Fout=932.40 (A=044, B=145)
+Fout=932.50 (A=045, B=145)
+Fout=932.60 (A=046, B=145)
+Fout=932.70 (A=047, B=145)
+Fout=932.80 (A=048, B=145)
+Fout=932.90 (A=049, B=145)
+Fout=933.00 (A=050, B=145)
+Fout=933.10 (A=051, B=145)
+Fout=933.20 (A=052, B=145)
+Fout=933.30 (A=053, B=145)
+Fout=933.40 (A=054, B=145)
+Fout=933.50 (A=055, B=145)
+Fout=933.60 (A=056, B=145)
+Fout=933.70 (A=057, B=145)
+Fout=933.80 (A=058, B=145)
+Fout=933.90 (A=059, B=145)
+Fout=934.00 (A=060, B=145)
+Fout=934.10 (A=061, B=145)
+Fout=934.20 (A=062, B=145)
+Fout=934.40 (A=000, B=146)
+Fout=934.50 (A=001, B=146)
+Fout=934.60 (A=002, B=146)
+Fout=934.70 (A=003, B=146)
+Fout=934.80 (A=004, B=146)
+Fout=934.90 (A=005, B=146)
+Fout=935.00 (A=006, B=146)
+Fout=935.10 (A=007, B=146)
+Fout=935.20 (A=008, B=146)
+Fout=935.30 (A=009, B=146)
+Fout=935.40 (A=010, B=146)
+Fout=935.50 (A=011, B=146)
+Fout=935.60 (A=012, B=146)
+Fout=935.70 (A=013, B=146)
+Fout=935.80 (A=014, B=146)
+Fout=935.90 (A=015, B=146)
+Fout=936.00 (A=016, B=146)
+Fout=936.10 (A=017, B=146)
+Fout=936.20 (A=018, B=146)
+Fout=936.30 (A=019, B=146)
+Fout=936.40 (A=020, B=146)
+Fout=936.50 (A=021, B=146)
+Fout=936.60 (A=022, B=146)
+Fout=936.70 (A=023, B=146)
+Fout=936.80 (A=024, B=146)
+Fout=936.90 (A=025, B=146)
+Fout=937.00 (A=026, B=146)
+Fout=937.10 (A=027, B=146)
+Fout=937.20 (A=028, B=146)
+Fout=937.30 (A=029, B=146)
+Fout=937.40 (A=030, B=146)
+Fout=937.50 (A=031, B=146)
+Fout=937.60 (A=032, B=146)
+Fout=937.70 (A=033, B=146)
+Fout=937.80 (A=034, B=146)
+Fout=937.90 (A=035, B=146)
+Fout=938.00 (A=036, B=146)
+Fout=938.10 (A=037, B=146)
+Fout=938.20 (A=038, B=146)
+Fout=938.30 (A=039, B=146)
+Fout=938.40 (A=040, B=146)
+Fout=938.50 (A=041, B=146)
+Fout=938.60 (A=042, B=146)
+Fout=938.70 (A=043, B=146)
+Fout=938.80 (A=044, B=146)
+Fout=938.90 (A=045, B=146)
+Fout=939.00 (A=046, B=146)
+Fout=939.10 (A=047, B=146)
+Fout=939.20 (A=048, B=146)
+Fout=939.30 (A=049, B=146)
+Fout=939.40 (A=050, B=146)
+Fout=939.50 (A=051, B=146)
+Fout=939.60 (A=052, B=146)
+Fout=939.70 (A=053, B=146)
+Fout=939.80 (A=054, B=146)
+Fout=939.90 (A=055, B=146)
+Fout=940.00 (A=056, B=146)
+Fout=940.10 (A=057, B=146)
+Fout=940.20 (A=058, B=146)
+Fout=940.30 (A=059, B=146)
+Fout=940.40 (A=060, B=146)
+Fout=940.50 (A=061, B=146)
+Fout=940.60 (A=062, B=146)
+Fout=940.80 (A=000, B=147)
+Fout=940.90 (A=001, B=147)
+Fout=941.00 (A=002, B=147)
+Fout=941.10 (A=003, B=147)
+Fout=941.20 (A=004, B=147)
+Fout=941.30 (A=005, B=147)
+Fout=941.40 (A=006, B=147)
+Fout=941.50 (A=007, B=147)
+Fout=941.60 (A=008, B=147)
+Fout=941.70 (A=009, B=147)
+Fout=941.80 (A=010, B=147)
+Fout=941.90 (A=011, B=147)
+Fout=942.00 (A=012, B=147)
+Fout=942.10 (A=013, B=147)
+Fout=942.20 (A=014, B=147)
+Fout=942.30 (A=015, B=147)
+Fout=942.40 (A=016, B=147)
+Fout=942.50 (A=017, B=147)
+Fout=942.60 (A=018, B=147)
+Fout=942.70 (A=019, B=147)
+Fout=942.80 (A=020, B=147)
+Fout=942.90 (A=021, B=147)
+Fout=943.00 (A=022, B=147)
+Fout=943.10 (A=023, B=147)
+Fout=943.20 (A=024, B=147)
+Fout=943.30 (A=025, B=147)
+Fout=943.40 (A=026, B=147)
+Fout=943.50 (A=027, B=147)
+Fout=943.60 (A=028, B=147)
+Fout=943.70 (A=029, B=147)
+Fout=943.80 (A=030, B=147)
+Fout=943.90 (A=031, B=147)
+Fout=944.00 (A=032, B=147)
+Fout=944.10 (A=033, B=147)
+Fout=944.20 (A=034, B=147)
+Fout=944.30 (A=035, B=147)
+Fout=944.40 (A=036, B=147)
+Fout=944.50 (A=037, B=147)
+Fout=944.60 (A=038, B=147)
+Fout=944.70 (A=039, B=147)
+Fout=944.80 (A=040, B=147)
+Fout=944.90 (A=041, B=147)
+Fout=945.00 (A=042, B=147)
+Fout=945.10 (A=043, B=147)
+Fout=945.20 (A=044, B=147)
+Fout=945.30 (A=045, B=147)
+Fout=945.40 (A=046, B=147)
+Fout=945.50 (A=047, B=147)
+Fout=945.60 (A=048, B=147)
+Fout=945.70 (A=049, B=147)
+Fout=945.80 (A=050, B=147)
+Fout=945.90 (A=051, B=147)
+Fout=946.00 (A=052, B=147)
+Fout=946.10 (A=053, B=147)
+Fout=946.20 (A=054, B=147)
+Fout=946.30 (A=055, B=147)
+Fout=946.40 (A=056, B=147)
+Fout=946.50 (A=057, B=147)
+Fout=946.60 (A=058, B=147)
+Fout=946.70 (A=059, B=147)
+Fout=946.80 (A=060, B=147)
+Fout=946.90 (A=061, B=147)
+Fout=947.00 (A=062, B=147)
+Fout=947.20 (A=000, B=148)
+Fout=947.30 (A=001, B=148)
+Fout=947.40 (A=002, B=148)
+Fout=947.50 (A=003, B=148)
+Fout=947.60 (A=004, B=148)
+Fout=947.70 (A=005, B=148)
+Fout=947.80 (A=006, B=148)
+Fout=947.90 (A=007, B=148)
+Fout=948.00 (A=008, B=148)
+Fout=948.10 (A=009, B=148)
+Fout=948.20 (A=010, B=148)
+Fout=948.30 (A=011, B=148)
+Fout=948.40 (A=012, B=148)
+Fout=948.50 (A=013, B=148)
+Fout=948.60 (A=014, B=148)
+Fout=948.70 (A=015, B=148)
+Fout=948.80 (A=016, B=148)
+Fout=948.90 (A=017, B=148)
+Fout=949.00 (A=018, B=148)
+Fout=949.10 (A=019, B=148)
+Fout=949.20 (A=020, B=148)
+Fout=949.30 (A=021, B=148)
+Fout=949.40 (A=022, B=148)
+Fout=949.50 (A=023, B=148)
+Fout=949.60 (A=024, B=148)
+Fout=949.70 (A=025, B=148)
+Fout=949.80 (A=026, B=148)
+Fout=949.90 (A=027, B=148)
+Fout=950.00 (A=028, B=148)
+Fout=950.10 (A=029, B=148)
+Fout=950.20 (A=030, B=148)
+Fout=950.30 (A=031, B=148)
+Fout=950.40 (A=032, B=148)
+Fout=950.50 (A=033, B=148)
+Fout=950.60 (A=034, B=148)
+Fout=950.70 (A=035, B=148)
+Fout=950.80 (A=036, B=148)
+Fout=950.90 (A=037, B=148)
+Fout=951.00 (A=038, B=148)
+Fout=951.10 (A=039, B=148)
+Fout=951.20 (A=040, B=148)
+Fout=951.30 (A=041, B=148)
+Fout=951.40 (A=042, B=148)
+Fout=951.50 (A=043, B=148)
+Fout=951.60 (A=044, B=148)
+Fout=951.70 (A=045, B=148)
+Fout=951.80 (A=046, B=148)
+Fout=951.90 (A=047, B=148)
+Fout=952.00 (A=048, B=148)
+Fout=952.10 (A=049, B=148)
+Fout=952.20 (A=050, B=148)
+Fout=952.30 (A=051, B=148)
+Fout=952.40 (A=052, B=148)
+Fout=952.50 (A=053, B=148)
+Fout=952.60 (A=054, B=148)
+Fout=952.70 (A=055, B=148)
+Fout=952.80 (A=056, B=148)
+Fout=952.90 (A=057, B=148)
+Fout=953.00 (A=058, B=148)
+Fout=953.10 (A=059, B=148)
+Fout=953.20 (A=060, B=148)
+Fout=953.30 (A=061, B=148)
+Fout=953.40 (A=062, B=148)
+Fout=953.60 (A=000, B=149)
+Fout=953.70 (A=001, B=149)
+Fout=953.80 (A=002, B=149)
+Fout=953.90 (A=003, B=149)
+Fout=954.00 (A=004, B=149)
+Fout=954.10 (A=005, B=149)
+Fout=954.20 (A=006, B=149)
+Fout=954.30 (A=007, B=149)
+Fout=954.40 (A=008, B=149)
+Fout=954.50 (A=009, B=149)
+Fout=954.60 (A=010, B=149)
+Fout=954.70 (A=011, B=149)
+Fout=954.80 (A=012, B=149)
+Fout=954.90 (A=013, B=149)
+Fout=955.00 (A=014, B=149)
+Fout=955.10 (A=015, B=149)
+Fout=955.20 (A=016, B=149)
+Fout=955.30 (A=017, B=149)
+Fout=955.40 (A=018, B=149)
+Fout=955.50 (A=019, B=149)
+Fout=955.60 (A=020, B=149)
+Fout=955.70 (A=021, B=149)
+Fout=955.80 (A=022, B=149)
+Fout=955.90 (A=023, B=149)
+Fout=956.00 (A=024, B=149)
+Fout=956.10 (A=025, B=149)
+Fout=956.20 (A=026, B=149)
+Fout=956.30 (A=027, B=149)
+Fout=956.40 (A=028, B=149)
+Fout=956.50 (A=029, B=149)
+Fout=956.60 (A=030, B=149)
+Fout=956.70 (A=031, B=149)
+Fout=956.80 (A=032, B=149)
+Fout=956.90 (A=033, B=149)
+Fout=957.00 (A=034, B=149)
+Fout=957.10 (A=035, B=149)
+Fout=957.20 (A=036, B=149)
+Fout=957.30 (A=037, B=149)
+Fout=957.40 (A=038, B=149)
+Fout=957.50 (A=039, B=149)
+Fout=957.60 (A=040, B=149)
+Fout=957.70 (A=041, B=149)
+Fout=957.80 (A=042, B=149)
+Fout=957.90 (A=043, B=149)
+Fout=958.00 (A=044, B=149)
+Fout=958.10 (A=045, B=149)
+Fout=958.20 (A=046, B=149)
+Fout=958.30 (A=047, B=149)
+Fout=958.40 (A=048, B=149)
+Fout=958.50 (A=049, B=149)
+Fout=958.60 (A=050, B=149)
+Fout=958.70 (A=051, B=149)
+Fout=958.80 (A=052, B=149)
+Fout=958.90 (A=053, B=149)
+Fout=959.00 (A=054, B=149)
+Fout=959.10 (A=055, B=149)
+Fout=959.20 (A=056, B=149)
+Fout=959.30 (A=057, B=149)
+Fout=959.40 (A=058, B=149)
+Fout=959.50 (A=059, B=149)
+Fout=959.60 (A=060, B=149)
+Fout=959.70 (A=061, B=149)
+Fout=959.80 (A=062, B=149)
+Fout=960.00 (A=000, B=150)
+Fout=960.10 (A=001, B=150)
+Fout=960.20 (A=002, B=150)
+Fout=960.30 (A=003, B=150)
+Fout=960.40 (A=004, B=150)
+Fout=960.50 (A=005, B=150)
+Fout=960.60 (A=006, B=150)
+Fout=960.70 (A=007, B=150)
+Fout=960.80 (A=008, B=150)
+Fout=960.90 (A=009, B=150)
+Fout=961.00 (A=010, B=150)
+Fout=961.10 (A=011, B=150)
+Fout=961.20 (A=012, B=150)
+Fout=961.30 (A=013, B=150)
+Fout=961.40 (A=014, B=150)
+Fout=961.50 (A=015, B=150)
+Fout=961.60 (A=016, B=150)
+Fout=961.70 (A=017, B=150)
+Fout=961.80 (A=018, B=150)
+Fout=961.90 (A=019, B=150)
+Fout=962.00 (A=020, B=150)
+Fout=962.10 (A=021, B=150)
+Fout=962.20 (A=022, B=150)
+Fout=962.30 (A=023, B=150)
+Fout=962.40 (A=024, B=150)
+Fout=962.50 (A=025, B=150)
+Fout=962.60 (A=026, B=150)
+Fout=962.70 (A=027, B=150)
+Fout=962.80 (A=028, B=150)
+Fout=962.90 (A=029, B=150)
+Fout=963.00 (A=030, B=150)
+Fout=963.10 (A=031, B=150)
+Fout=963.20 (A=032, B=150)
+Fout=963.30 (A=033, B=150)
+Fout=963.40 (A=034, B=150)
+Fout=963.50 (A=035, B=150)
+Fout=963.60 (A=036, B=150)
+Fout=963.70 (A=037, B=150)
+Fout=963.80 (A=038, B=150)
+Fout=963.90 (A=039, B=150)
+Fout=964.00 (A=040, B=150)
+Fout=964.10 (A=041, B=150)
+Fout=964.20 (A=042, B=150)
+Fout=964.30 (A=043, B=150)
+Fout=964.40 (A=044, B=150)
+Fout=964.50 (A=045, B=150)
+Fout=964.60 (A=046, B=150)
+Fout=964.70 (A=047, B=150)
+Fout=964.80 (A=048, B=150)
+Fout=964.90 (A=049, B=150)
+Fout=965.00 (A=050, B=150)
+Fout=965.10 (A=051, B=150)
+Fout=965.20 (A=052, B=150)
+Fout=965.30 (A=053, B=150)
+Fout=965.40 (A=054, B=150)
+Fout=965.50 (A=055, B=150)
+Fout=965.60 (A=056, B=150)
+Fout=965.70 (A=057, B=150)
+Fout=965.80 (A=058, B=150)
+Fout=965.90 (A=059, B=150)
+Fout=966.00 (A=060, B=150)
+Fout=966.10 (A=061, B=150)
+Fout=966.20 (A=062, B=150)
+======================================================================
+PLL Rx High Band:
+Fout=1804.80 (A=000, B=141)
+Fout=1805.00 (A=001, B=141)
+Fout=1805.20 (A=002, B=141)
+Fout=1805.40 (A=003, B=141)
+Fout=1805.60 (A=004, B=141)
+Fout=1805.80 (A=005, B=141)
+Fout=1806.00 (A=006, B=141)
+Fout=1806.20 (A=007, B=141)
+Fout=1806.40 (A=008, B=141)
+Fout=1806.60 (A=009, B=141)
+Fout=1806.80 (A=010, B=141)
+Fout=1807.00 (A=011, B=141)
+Fout=1807.20 (A=012, B=141)
+Fout=1807.40 (A=013, B=141)
+Fout=1807.60 (A=014, B=141)
+Fout=1807.80 (A=015, B=141)
+Fout=1808.00 (A=016, B=141)
+Fout=1808.20 (A=017, B=141)
+Fout=1808.40 (A=018, B=141)
+Fout=1808.60 (A=019, B=141)
+Fout=1808.80 (A=020, B=141)
+Fout=1809.00 (A=021, B=141)
+Fout=1809.20 (A=022, B=141)
+Fout=1809.40 (A=023, B=141)
+Fout=1809.60 (A=024, B=141)
+Fout=1809.80 (A=025, B=141)
+Fout=1810.00 (A=026, B=141)
+Fout=1810.20 (A=027, B=141)
+Fout=1810.40 (A=028, B=141)
+Fout=1810.60 (A=029, B=141)
+Fout=1810.80 (A=030, B=141)
+Fout=1811.00 (A=031, B=141)
+Fout=1811.20 (A=032, B=141)
+Fout=1811.40 (A=033, B=141)
+Fout=1811.60 (A=034, B=141)
+Fout=1811.80 (A=035, B=141)
+Fout=1812.00 (A=036, B=141)
+Fout=1812.20 (A=037, B=141)
+Fout=1812.40 (A=038, B=141)
+Fout=1812.60 (A=039, B=141)
+Fout=1812.80 (A=040, B=141)
+Fout=1813.00 (A=041, B=141)
+Fout=1813.20 (A=042, B=141)
+Fout=1813.40 (A=043, B=141)
+Fout=1813.60 (A=044, B=141)
+Fout=1813.80 (A=045, B=141)
+Fout=1814.00 (A=046, B=141)
+Fout=1814.20 (A=047, B=141)
+Fout=1814.40 (A=048, B=141)
+Fout=1814.60 (A=049, B=141)
+Fout=1814.80 (A=050, B=141)
+Fout=1815.00 (A=051, B=141)
+Fout=1815.20 (A=052, B=141)
+Fout=1815.40 (A=053, B=141)
+Fout=1815.60 (A=054, B=141)
+Fout=1815.80 (A=055, B=141)
+Fout=1816.00 (A=056, B=141)
+Fout=1816.20 (A=057, B=141)
+Fout=1816.40 (A=058, B=141)
+Fout=1816.60 (A=059, B=141)
+Fout=1816.80 (A=060, B=141)
+Fout=1817.00 (A=061, B=141)
+Fout=1817.20 (A=062, B=141)
+Fout=1817.60 (A=000, B=142)
+Fout=1817.80 (A=001, B=142)
+Fout=1818.00 (A=002, B=142)
+Fout=1818.20 (A=003, B=142)
+Fout=1818.40 (A=004, B=142)
+Fout=1818.60 (A=005, B=142)
+Fout=1818.80 (A=006, B=142)
+Fout=1819.00 (A=007, B=142)
+Fout=1819.20 (A=008, B=142)
+Fout=1819.40 (A=009, B=142)
+Fout=1819.60 (A=010, B=142)
+Fout=1819.80 (A=011, B=142)
+Fout=1820.00 (A=012, B=142)
+Fout=1820.20 (A=013, B=142)
+Fout=1820.40 (A=014, B=142)
+Fout=1820.60 (A=015, B=142)
+Fout=1820.80 (A=016, B=142)
+Fout=1821.00 (A=017, B=142)
+Fout=1821.20 (A=018, B=142)
+Fout=1821.40 (A=019, B=142)
+Fout=1821.60 (A=020, B=142)
+Fout=1821.80 (A=021, B=142)
+Fout=1822.00 (A=022, B=142)
+Fout=1822.20 (A=023, B=142)
+Fout=1822.40 (A=024, B=142)
+Fout=1822.60 (A=025, B=142)
+Fout=1822.80 (A=026, B=142)
+Fout=1823.00 (A=027, B=142)
+Fout=1823.20 (A=028, B=142)
+Fout=1823.40 (A=029, B=142)
+Fout=1823.60 (A=030, B=142)
+Fout=1823.80 (A=031, B=142)
+Fout=1824.00 (A=032, B=142)
+Fout=1824.20 (A=033, B=142)
+Fout=1824.40 (A=034, B=142)
+Fout=1824.60 (A=035, B=142)
+Fout=1824.80 (A=036, B=142)
+Fout=1825.00 (A=037, B=142)
+Fout=1825.20 (A=038, B=142)
+Fout=1825.40 (A=039, B=142)
+Fout=1825.60 (A=040, B=142)
+Fout=1825.80 (A=041, B=142)
+Fout=1826.00 (A=042, B=142)
+Fout=1826.20 (A=043, B=142)
+Fout=1826.40 (A=044, B=142)
+Fout=1826.60 (A=045, B=142)
+Fout=1826.80 (A=046, B=142)
+Fout=1827.00 (A=047, B=142)
+Fout=1827.20 (A=048, B=142)
+Fout=1827.40 (A=049, B=142)
+Fout=1827.60 (A=050, B=142)
+Fout=1827.80 (A=051, B=142)
+Fout=1828.00 (A=052, B=142)
+Fout=1828.20 (A=053, B=142)
+Fout=1828.40 (A=054, B=142)
+Fout=1828.60 (A=055, B=142)
+Fout=1828.80 (A=056, B=142)
+Fout=1829.00 (A=057, B=142)
+Fout=1829.20 (A=058, B=142)
+Fout=1829.40 (A=059, B=142)
+Fout=1829.60 (A=060, B=142)
+Fout=1829.80 (A=061, B=142)
+Fout=1830.00 (A=062, B=142)
+Fout=1830.40 (A=000, B=143)
+Fout=1830.60 (A=001, B=143)
+Fout=1830.80 (A=002, B=143)
+Fout=1831.00 (A=003, B=143)
+Fout=1831.20 (A=004, B=143)
+Fout=1831.40 (A=005, B=143)
+Fout=1831.60 (A=006, B=143)
+Fout=1831.80 (A=007, B=143)
+Fout=1832.00 (A=008, B=143)
+Fout=1832.20 (A=009, B=143)
+Fout=1832.40 (A=010, B=143)
+Fout=1832.60 (A=011, B=143)
+Fout=1832.80 (A=012, B=143)
+Fout=1833.00 (A=013, B=143)
+Fout=1833.20 (A=014, B=143)
+Fout=1833.40 (A=015, B=143)
+Fout=1833.60 (A=016, B=143)
+Fout=1833.80 (A=017, B=143)
+Fout=1834.00 (A=018, B=143)
+Fout=1834.20 (A=019, B=143)
+Fout=1834.40 (A=020, B=143)
+Fout=1834.60 (A=021, B=143)
+Fout=1834.80 (A=022, B=143)
+Fout=1835.00 (A=023, B=143)
+Fout=1835.20 (A=024, B=143)
+Fout=1835.40 (A=025, B=143)
+Fout=1835.60 (A=026, B=143)
+Fout=1835.80 (A=027, B=143)
+Fout=1836.00 (A=028, B=143)
+Fout=1836.20 (A=029, B=143)
+Fout=1836.40 (A=030, B=143)
+Fout=1836.60 (A=031, B=143)
+Fout=1836.80 (A=032, B=143)
+Fout=1837.00 (A=033, B=143)
+Fout=1837.20 (A=034, B=143)
+Fout=1837.40 (A=035, B=143)
+Fout=1837.60 (A=036, B=143)
+Fout=1837.80 (A=037, B=143)
+Fout=1838.00 (A=038, B=143)
+Fout=1838.20 (A=039, B=143)
+Fout=1838.40 (A=040, B=143)
+Fout=1838.60 (A=041, B=143)
+Fout=1838.80 (A=042, B=143)
+Fout=1839.00 (A=043, B=143)
+Fout=1839.20 (A=044, B=143)
+Fout=1839.40 (A=045, B=143)
+Fout=1839.60 (A=046, B=143)
+Fout=1839.80 (A=047, B=143)
+Fout=1840.00 (A=048, B=143)
+Fout=1840.20 (A=049, B=143)
+Fout=1840.40 (A=050, B=143)
+Fout=1840.60 (A=051, B=143)
+Fout=1840.80 (A=052, B=143)
+Fout=1841.00 (A=053, B=143)
+Fout=1841.20 (A=054, B=143)
+Fout=1841.40 (A=055, B=143)
+Fout=1841.60 (A=056, B=143)
+Fout=1841.80 (A=057, B=143)
+Fout=1842.00 (A=058, B=143)
+Fout=1842.20 (A=059, B=143)
+Fout=1842.40 (A=060, B=143)
+Fout=1842.60 (A=061, B=143)
+Fout=1842.80 (A=062, B=143)
+Fout=1843.20 (A=000, B=144)
+Fout=1843.40 (A=001, B=144)
+Fout=1843.60 (A=002, B=144)
+Fout=1843.80 (A=003, B=144)
+Fout=1844.00 (A=004, B=144)
+Fout=1844.20 (A=005, B=144)
+Fout=1844.40 (A=006, B=144)
+Fout=1844.60 (A=007, B=144)
+Fout=1844.80 (A=008, B=144)
+Fout=1845.00 (A=009, B=144)
+Fout=1845.20 (A=010, B=144)
+Fout=1845.40 (A=011, B=144)
+Fout=1845.60 (A=012, B=144)
+Fout=1845.80 (A=013, B=144)
+Fout=1846.00 (A=014, B=144)
+Fout=1846.20 (A=015, B=144)
+Fout=1846.40 (A=016, B=144)
+Fout=1846.60 (A=017, B=144)
+Fout=1846.80 (A=018, B=144)
+Fout=1847.00 (A=019, B=144)
+Fout=1847.20 (A=020, B=144)
+Fout=1847.40 (A=021, B=144)
+Fout=1847.60 (A=022, B=144)
+Fout=1847.80 (A=023, B=144)
+Fout=1848.00 (A=024, B=144)
+Fout=1848.20 (A=025, B=144)
+Fout=1848.40 (A=026, B=144)
+Fout=1848.60 (A=027, B=144)
+Fout=1848.80 (A=028, B=144)
+Fout=1849.00 (A=029, B=144)
+Fout=1849.20 (A=030, B=144)
+Fout=1849.40 (A=031, B=144)
+Fout=1849.60 (A=032, B=144)
+Fout=1849.80 (A=033, B=144)
+Fout=1850.00 (A=034, B=144)
+Fout=1850.20 (A=035, B=144)
+Fout=1850.40 (A=036, B=144)
+Fout=1850.60 (A=037, B=144)
+Fout=1850.80 (A=038, B=144)
+Fout=1851.00 (A=039, B=144)
+Fout=1851.20 (A=040, B=144)
+Fout=1851.40 (A=041, B=144)
+Fout=1851.60 (A=042, B=144)
+Fout=1851.80 (A=043, B=144)
+Fout=1852.00 (A=044, B=144)
+Fout=1852.20 (A=045, B=144)
+Fout=1852.40 (A=046, B=144)
+Fout=1852.60 (A=047, B=144)
+Fout=1852.80 (A=048, B=144)
+Fout=1853.00 (A=049, B=144)
+Fout=1853.20 (A=050, B=144)
+Fout=1853.40 (A=051, B=144)
+Fout=1853.60 (A=052, B=144)
+Fout=1853.80 (A=053, B=144)
+Fout=1854.00 (A=054, B=144)
+Fout=1854.20 (A=055, B=144)
+Fout=1854.40 (A=056, B=144)
+Fout=1854.60 (A=057, B=144)
+Fout=1854.80 (A=058, B=144)
+Fout=1855.00 (A=059, B=144)
+Fout=1855.20 (A=060, B=144)
+Fout=1855.40 (A=061, B=144)
+Fout=1855.60 (A=062, B=144)
+Fout=1856.00 (A=000, B=145)
+Fout=1856.20 (A=001, B=145)
+Fout=1856.40 (A=002, B=145)
+Fout=1856.60 (A=003, B=145)
+Fout=1856.80 (A=004, B=145)
+Fout=1857.00 (A=005, B=145)
+Fout=1857.20 (A=006, B=145)
+Fout=1857.40 (A=007, B=145)
+Fout=1857.60 (A=008, B=145)
+Fout=1857.80 (A=009, B=145)
+Fout=1858.00 (A=010, B=145)
+Fout=1858.20 (A=011, B=145)
+Fout=1858.40 (A=012, B=145)
+Fout=1858.60 (A=013, B=145)
+Fout=1858.80 (A=014, B=145)
+Fout=1859.00 (A=015, B=145)
+Fout=1859.20 (A=016, B=145)
+Fout=1859.40 (A=017, B=145)
+Fout=1859.60 (A=018, B=145)
+Fout=1859.80 (A=019, B=145)
+Fout=1860.00 (A=020, B=145)
+Fout=1860.20 (A=021, B=145)
+Fout=1860.40 (A=022, B=145)
+Fout=1860.60 (A=023, B=145)
+Fout=1860.80 (A=024, B=145)
+Fout=1861.00 (A=025, B=145)
+Fout=1861.20 (A=026, B=145)
+Fout=1861.40 (A=027, B=145)
+Fout=1861.60 (A=028, B=145)
+Fout=1861.80 (A=029, B=145)
+Fout=1862.00 (A=030, B=145)
+Fout=1862.20 (A=031, B=145)
+Fout=1862.40 (A=032, B=145)
+Fout=1862.60 (A=033, B=145)
+Fout=1862.80 (A=034, B=145)
+Fout=1863.00 (A=035, B=145)
+Fout=1863.20 (A=036, B=145)
+Fout=1863.40 (A=037, B=145)
+Fout=1863.60 (A=038, B=145)
+Fout=1863.80 (A=039, B=145)
+Fout=1864.00 (A=040, B=145)
+Fout=1864.20 (A=041, B=145)
+Fout=1864.40 (A=042, B=145)
+Fout=1864.60 (A=043, B=145)
+Fout=1864.80 (A=044, B=145)
+Fout=1865.00 (A=045, B=145)
+Fout=1865.20 (A=046, B=145)
+Fout=1865.40 (A=047, B=145)
+Fout=1865.60 (A=048, B=145)
+Fout=1865.80 (A=049, B=145)
+Fout=1866.00 (A=050, B=145)
+Fout=1866.20 (A=051, B=145)
+Fout=1866.40 (A=052, B=145)
+Fout=1866.60 (A=053, B=145)
+Fout=1866.80 (A=054, B=145)
+Fout=1867.00 (A=055, B=145)
+Fout=1867.20 (A=056, B=145)
+Fout=1867.40 (A=057, B=145)
+Fout=1867.60 (A=058, B=145)
+Fout=1867.80 (A=059, B=145)
+Fout=1868.00 (A=060, B=145)
+Fout=1868.20 (A=061, B=145)
+Fout=1868.40 (A=062, B=145)
+Fout=1868.80 (A=000, B=146)
+Fout=1869.00 (A=001, B=146)
+Fout=1869.20 (A=002, B=146)
+Fout=1869.40 (A=003, B=146)
+Fout=1869.60 (A=004, B=146)
+Fout=1869.80 (A=005, B=146)
+Fout=1870.00 (A=006, B=146)
+Fout=1870.20 (A=007, B=146)
+Fout=1870.40 (A=008, B=146)
+Fout=1870.60 (A=009, B=146)
+Fout=1870.80 (A=010, B=146)
+Fout=1871.00 (A=011, B=146)
+Fout=1871.20 (A=012, B=146)
+Fout=1871.40 (A=013, B=146)
+Fout=1871.60 (A=014, B=146)
+Fout=1871.80 (A=015, B=146)
+Fout=1872.00 (A=016, B=146)
+Fout=1872.20 (A=017, B=146)
+Fout=1872.40 (A=018, B=146)
+Fout=1872.60 (A=019, B=146)
+Fout=1872.80 (A=020, B=146)
+Fout=1873.00 (A=021, B=146)
+Fout=1873.20 (A=022, B=146)
+Fout=1873.40 (A=023, B=146)
+Fout=1873.60 (A=024, B=146)
+Fout=1873.80 (A=025, B=146)
+Fout=1874.00 (A=026, B=146)
+Fout=1874.20 (A=027, B=146)
+Fout=1874.40 (A=028, B=146)
+Fout=1874.60 (A=029, B=146)
+Fout=1874.80 (A=030, B=146)
+Fout=1875.00 (A=031, B=146)
+Fout=1875.20 (A=032, B=146)
+Fout=1875.40 (A=033, B=146)
+Fout=1875.60 (A=034, B=146)
+Fout=1875.80 (A=035, B=146)
+Fout=1876.00 (A=036, B=146)
+Fout=1876.20 (A=037, B=146)
+Fout=1876.40 (A=038, B=146)
+Fout=1876.60 (A=039, B=146)
+Fout=1876.80 (A=040, B=146)
+Fout=1877.00 (A=041, B=146)
+Fout=1877.20 (A=042, B=146)
+Fout=1877.40 (A=043, B=146)
+Fout=1877.60 (A=044, B=146)
+Fout=1877.80 (A=045, B=146)
+Fout=1878.00 (A=046, B=146)
+Fout=1878.20 (A=047, B=146)
+Fout=1878.40 (A=048, B=146)
+Fout=1878.60 (A=049, B=146)
+Fout=1878.80 (A=050, B=146)
+Fout=1879.00 (A=051, B=146)
+Fout=1879.20 (A=052, B=146)
+Fout=1879.40 (A=053, B=146)
+Fout=1879.60 (A=054, B=146)
+Fout=1879.80 (A=055, B=146)
+Fout=1880.00 (A=056, B=146)
+Fout=1880.20 (A=057, B=146)
+Fout=1880.40 (A=058, B=146)
+Fout=1880.60 (A=059, B=146)
+Fout=1880.80 (A=060, B=146)
+Fout=1881.00 (A=061, B=146)
+Fout=1881.20 (A=062, B=146)
+Fout=1881.60 (A=000, B=147)
+Fout=1881.80 (A=001, B=147)
+Fout=1882.00 (A=002, B=147)
+Fout=1882.20 (A=003, B=147)
+Fout=1882.40 (A=004, B=147)
+Fout=1882.60 (A=005, B=147)
+Fout=1882.80 (A=006, B=147)
+Fout=1883.00 (A=007, B=147)
+Fout=1883.20 (A=008, B=147)
+Fout=1883.40 (A=009, B=147)
+Fout=1883.60 (A=010, B=147)
+Fout=1883.80 (A=011, B=147)
+Fout=1884.00 (A=012, B=147)
+Fout=1884.20 (A=013, B=147)
+Fout=1884.40 (A=014, B=147)
+Fout=1884.60 (A=015, B=147)
+Fout=1884.80 (A=016, B=147)
+Fout=1885.00 (A=017, B=147)
+Fout=1885.20 (A=018, B=147)
+Fout=1885.40 (A=019, B=147)
+Fout=1885.60 (A=020, B=147)
+Fout=1885.80 (A=021, B=147)
+Fout=1886.00 (A=022, B=147)
+Fout=1886.20 (A=023, B=147)
+Fout=1886.40 (A=024, B=147)
+Fout=1886.60 (A=025, B=147)
+Fout=1886.80 (A=026, B=147)
+Fout=1887.00 (A=027, B=147)
+Fout=1887.20 (A=028, B=147)
+Fout=1887.40 (A=029, B=147)
+Fout=1887.60 (A=030, B=147)
+Fout=1887.80 (A=031, B=147)
+Fout=1888.00 (A=032, B=147)
+Fout=1888.20 (A=033, B=147)
+Fout=1888.40 (A=034, B=147)
+Fout=1888.60 (A=035, B=147)
+Fout=1888.80 (A=036, B=147)
+Fout=1889.00 (A=037, B=147)
+Fout=1889.20 (A=038, B=147)
+Fout=1889.40 (A=039, B=147)
+Fout=1889.60 (A=040, B=147)
+Fout=1889.80 (A=041, B=147)
+Fout=1890.00 (A=042, B=147)
+Fout=1890.20 (A=043, B=147)
+Fout=1890.40 (A=044, B=147)
+Fout=1890.60 (A=045, B=147)
+Fout=1890.80 (A=046, B=147)
+Fout=1891.00 (A=047, B=147)
+Fout=1891.20 (A=048, B=147)
+Fout=1891.40 (A=049, B=147)
+Fout=1891.60 (A=050, B=147)
+Fout=1891.80 (A=051, B=147)
+Fout=1892.00 (A=052, B=147)
+Fout=1892.20 (A=053, B=147)
+Fout=1892.40 (A=054, B=147)
+Fout=1892.60 (A=055, B=147)
+Fout=1892.80 (A=056, B=147)
+Fout=1893.00 (A=057, B=147)
+Fout=1893.20 (A=058, B=147)
+Fout=1893.40 (A=059, B=147)
+Fout=1893.60 (A=060, B=147)
+Fout=1893.80 (A=061, B=147)
+Fout=1894.00 (A=062, B=147)
+Fout=1894.40 (A=000, B=148)
+Fout=1894.60 (A=001, B=148)
+Fout=1894.80 (A=002, B=148)
+Fout=1895.00 (A=003, B=148)
+Fout=1895.20 (A=004, B=148)
+Fout=1895.40 (A=005, B=148)
+Fout=1895.60 (A=006, B=148)
+Fout=1895.80 (A=007, B=148)
+Fout=1896.00 (A=008, B=148)
+Fout=1896.20 (A=009, B=148)
+Fout=1896.40 (A=010, B=148)
+Fout=1896.60 (A=011, B=148)
+Fout=1896.80 (A=012, B=148)
+Fout=1897.00 (A=013, B=148)
+Fout=1897.20 (A=014, B=148)
+Fout=1897.40 (A=015, B=148)
+Fout=1897.60 (A=016, B=148)
+Fout=1897.80 (A=017, B=148)
+Fout=1898.00 (A=018, B=148)
+Fout=1898.20 (A=019, B=148)
+Fout=1898.40 (A=020, B=148)
+Fout=1898.60 (A=021, B=148)
+Fout=1898.80 (A=022, B=148)
+Fout=1899.00 (A=023, B=148)
+Fout=1899.20 (A=024, B=148)
+Fout=1899.40 (A=025, B=148)
+Fout=1899.60 (A=026, B=148)
+Fout=1899.80 (A=027, B=148)
+Fout=1900.00 (A=028, B=148)
+Fout=1900.20 (A=029, B=148)
+Fout=1900.40 (A=030, B=148)
+Fout=1900.60 (A=031, B=148)
+Fout=1900.80 (A=032, B=148)
+Fout=1901.00 (A=033, B=148)
+Fout=1901.20 (A=034, B=148)
+Fout=1901.40 (A=035, B=148)
+Fout=1901.60 (A=036, B=148)
+Fout=1901.80 (A=037, B=148)
+Fout=1902.00 (A=038, B=148)
+Fout=1902.20 (A=039, B=148)
+Fout=1902.40 (A=040, B=148)
+Fout=1902.60 (A=041, B=148)
+Fout=1902.80 (A=042, B=148)
+Fout=1903.00 (A=043, B=148)
+Fout=1903.20 (A=044, B=148)
+Fout=1903.40 (A=045, B=148)
+Fout=1903.60 (A=046, B=148)
+Fout=1903.80 (A=047, B=148)
+Fout=1904.00 (A=048, B=148)
+Fout=1904.20 (A=049, B=148)
+Fout=1904.40 (A=050, B=148)
+Fout=1904.60 (A=051, B=148)
+Fout=1904.80 (A=052, B=148)
+Fout=1905.00 (A=053, B=148)
+Fout=1905.20 (A=054, B=148)
+Fout=1905.40 (A=055, B=148)
+Fout=1905.60 (A=056, B=148)
+Fout=1905.80 (A=057, B=148)
+Fout=1906.00 (A=058, B=148)
+Fout=1906.20 (A=059, B=148)
+Fout=1906.40 (A=060, B=148)
+Fout=1906.60 (A=061, B=148)
+Fout=1906.80 (A=062, B=148)
+Fout=1907.20 (A=000, B=149)
+Fout=1907.40 (A=001, B=149)
+Fout=1907.60 (A=002, B=149)
+Fout=1907.80 (A=003, B=149)
+Fout=1908.00 (A=004, B=149)
+Fout=1908.20 (A=005, B=149)
+Fout=1908.40 (A=006, B=149)
+Fout=1908.60 (A=007, B=149)
+Fout=1908.80 (A=008, B=149)
+Fout=1909.00 (A=009, B=149)
+Fout=1909.20 (A=010, B=149)
+Fout=1909.40 (A=011, B=149)
+Fout=1909.60 (A=012, B=149)
+Fout=1909.80 (A=013, B=149)
+Fout=1910.00 (A=014, B=149)
+Fout=1910.20 (A=015, B=149)
+Fout=1910.40 (A=016, B=149)
+Fout=1910.60 (A=017, B=149)
+Fout=1910.80 (A=018, B=149)
+Fout=1911.00 (A=019, B=149)
+Fout=1911.20 (A=020, B=149)
+Fout=1911.40 (A=021, B=149)
+Fout=1911.60 (A=022, B=149)
+Fout=1911.80 (A=023, B=149)
+Fout=1912.00 (A=024, B=149)
+Fout=1912.20 (A=025, B=149)
+Fout=1912.40 (A=026, B=149)
+Fout=1912.60 (A=027, B=149)
+Fout=1912.80 (A=028, B=149)
+Fout=1913.00 (A=029, B=149)
+Fout=1913.20 (A=030, B=149)
+Fout=1913.40 (A=031, B=149)
+Fout=1913.60 (A=032, B=149)
+Fout=1913.80 (A=033, B=149)
+Fout=1914.00 (A=034, B=149)
+Fout=1914.20 (A=035, B=149)
+Fout=1914.40 (A=036, B=149)
+Fout=1914.60 (A=037, B=149)
+Fout=1914.80 (A=038, B=149)
+Fout=1915.00 (A=039, B=149)
+Fout=1915.20 (A=040, B=149)
+Fout=1915.40 (A=041, B=149)
+Fout=1915.60 (A=042, B=149)
+Fout=1915.80 (A=043, B=149)
+Fout=1916.00 (A=044, B=149)
+Fout=1916.20 (A=045, B=149)
+Fout=1916.40 (A=046, B=149)
+Fout=1916.60 (A=047, B=149)
+Fout=1916.80 (A=048, B=149)
+Fout=1917.00 (A=049, B=149)
+Fout=1917.20 (A=050, B=149)
+Fout=1917.40 (A=051, B=149)
+Fout=1917.60 (A=052, B=149)
+Fout=1917.80 (A=053, B=149)
+Fout=1918.00 (A=054, B=149)
+Fout=1918.20 (A=055, B=149)
+Fout=1918.40 (A=056, B=149)
+Fout=1918.60 (A=057, B=149)
+Fout=1918.80 (A=058, B=149)
+Fout=1919.00 (A=059, B=149)
+Fout=1919.20 (A=060, B=149)
+Fout=1919.40 (A=061, B=149)
+Fout=1919.60 (A=062, B=149)
+Fout=1920.00 (A=000, B=150)
+Fout=1920.20 (A=001, B=150)
+Fout=1920.40 (A=002, B=150)
+Fout=1920.60 (A=003, B=150)
+Fout=1920.80 (A=004, B=150)
+Fout=1921.00 (A=005, B=150)
+Fout=1921.20 (A=006, B=150)
+Fout=1921.40 (A=007, B=150)
+Fout=1921.60 (A=008, B=150)
+Fout=1921.80 (A=009, B=150)
+Fout=1922.00 (A=010, B=150)
+Fout=1922.20 (A=011, B=150)
+Fout=1922.40 (A=012, B=150)
+Fout=1922.60 (A=013, B=150)
+Fout=1922.80 (A=014, B=150)
+Fout=1923.00 (A=015, B=150)
+Fout=1923.20 (A=016, B=150)
+Fout=1923.40 (A=017, B=150)
+Fout=1923.60 (A=018, B=150)
+Fout=1923.80 (A=019, B=150)
+Fout=1924.00 (A=020, B=150)
+Fout=1924.20 (A=021, B=150)
+Fout=1924.40 (A=022, B=150)
+Fout=1924.60 (A=023, B=150)
+Fout=1924.80 (A=024, B=150)
+Fout=1925.00 (A=025, B=150)
+Fout=1925.20 (A=026, B=150)
+Fout=1925.40 (A=027, B=150)
+Fout=1925.60 (A=028, B=150)
+Fout=1925.80 (A=029, B=150)
+Fout=1926.00 (A=030, B=150)
+Fout=1926.20 (A=031, B=150)
+Fout=1926.40 (A=032, B=150)
+Fout=1926.60 (A=033, B=150)
+Fout=1926.80 (A=034, B=150)
+Fout=1927.00 (A=035, B=150)
+Fout=1927.20 (A=036, B=150)
+Fout=1927.40 (A=037, B=150)
+Fout=1927.60 (A=038, B=150)
+Fout=1927.80 (A=039, B=150)
+Fout=1928.00 (A=040, B=150)
+Fout=1928.20 (A=041, B=150)
+Fout=1928.40 (A=042, B=150)
+Fout=1928.60 (A=043, B=150)
+Fout=1928.80 (A=044, B=150)
+Fout=1929.00 (A=045, B=150)
+Fout=1929.20 (A=046, B=150)
+Fout=1929.40 (A=047, B=150)
+Fout=1929.60 (A=048, B=150)
+Fout=1929.80 (A=049, B=150)
+Fout=1930.00 (A=050, B=150)
+Fout=1930.20 (A=051, B=150)
+Fout=1930.40 (A=052, B=150)
+Fout=1930.60 (A=053, B=150)
+Fout=1930.80 (A=054, B=150)
+Fout=1931.00 (A=055, B=150)
+Fout=1931.20 (A=056, B=150)
+Fout=1931.40 (A=057, B=150)
+Fout=1931.60 (A=058, B=150)
+Fout=1931.80 (A=059, B=150)
+Fout=1932.00 (A=060, B=150)
+Fout=1932.20 (A=061, B=150)
+Fout=1932.40 (A=062, B=150)
+Fout=1932.80 (A=000, B=151)
+Fout=1933.00 (A=001, B=151)
+Fout=1933.20 (A=002, B=151)
+Fout=1933.40 (A=003, B=151)
+Fout=1933.60 (A=004, B=151)
+Fout=1933.80 (A=005, B=151)
+Fout=1934.00 (A=006, B=151)
+Fout=1934.20 (A=007, B=151)
+Fout=1934.40 (A=008, B=151)
+Fout=1934.60 (A=009, B=151)
+Fout=1934.80 (A=010, B=151)
+Fout=1935.00 (A=011, B=151)
+Fout=1935.20 (A=012, B=151)
+Fout=1935.40 (A=013, B=151)
+Fout=1935.60 (A=014, B=151)
+Fout=1935.80 (A=015, B=151)
+Fout=1936.00 (A=016, B=151)
+Fout=1936.20 (A=017, B=151)
+Fout=1936.40 (A=018, B=151)
+Fout=1936.60 (A=019, B=151)
+Fout=1936.80 (A=020, B=151)
+Fout=1937.00 (A=021, B=151)
+Fout=1937.20 (A=022, B=151)
+Fout=1937.40 (A=023, B=151)
+Fout=1937.60 (A=024, B=151)
+Fout=1937.80 (A=025, B=151)
+Fout=1938.00 (A=026, B=151)
+Fout=1938.20 (A=027, B=151)
+Fout=1938.40 (A=028, B=151)
+Fout=1938.60 (A=029, B=151)
+Fout=1938.80 (A=030, B=151)
+Fout=1939.00 (A=031, B=151)
+Fout=1939.20 (A=032, B=151)
+Fout=1939.40 (A=033, B=151)
+Fout=1939.60 (A=034, B=151)
+Fout=1939.80 (A=035, B=151)
+Fout=1940.00 (A=036, B=151)
+Fout=1940.20 (A=037, B=151)
+Fout=1940.40 (A=038, B=151)
+Fout=1940.60 (A=039, B=151)
+Fout=1940.80 (A=040, B=151)
+Fout=1941.00 (A=041, B=151)
+Fout=1941.20 (A=042, B=151)
+Fout=1941.40 (A=043, B=151)
+Fout=1941.60 (A=044, B=151)
+Fout=1941.80 (A=045, B=151)
+Fout=1942.00 (A=046, B=151)
+Fout=1942.20 (A=047, B=151)
+Fout=1942.40 (A=048, B=151)
+Fout=1942.60 (A=049, B=151)
+Fout=1942.80 (A=050, B=151)
+Fout=1943.00 (A=051, B=151)
+Fout=1943.20 (A=052, B=151)
+Fout=1943.40 (A=053, B=151)
+Fout=1943.60 (A=054, B=151)
+Fout=1943.80 (A=055, B=151)
+Fout=1944.00 (A=056, B=151)
+Fout=1944.20 (A=057, B=151)
+Fout=1944.40 (A=058, B=151)
+Fout=1944.60 (A=059, B=151)
+Fout=1944.80 (A=060, B=151)
+Fout=1945.00 (A=061, B=151)
+Fout=1945.20 (A=062, B=151)
+Fout=1945.60 (A=000, B=152)
+Fout=1945.80 (A=001, B=152)
+Fout=1946.00 (A=002, B=152)
+Fout=1946.20 (A=003, B=152)
+Fout=1946.40 (A=004, B=152)
+Fout=1946.60 (A=005, B=152)
+Fout=1946.80 (A=006, B=152)
+Fout=1947.00 (A=007, B=152)
+Fout=1947.20 (A=008, B=152)
+Fout=1947.40 (A=009, B=152)
+Fout=1947.60 (A=010, B=152)
+Fout=1947.80 (A=011, B=152)
+Fout=1948.00 (A=012, B=152)
+Fout=1948.20 (A=013, B=152)
+Fout=1948.40 (A=014, B=152)
+Fout=1948.60 (A=015, B=152)
+Fout=1948.80 (A=016, B=152)
+Fout=1949.00 (A=017, B=152)
+Fout=1949.20 (A=018, B=152)
+Fout=1949.40 (A=019, B=152)
+Fout=1949.60 (A=020, B=152)
+Fout=1949.80 (A=021, B=152)
+Fout=1950.00 (A=022, B=152)
+Fout=1950.20 (A=023, B=152)
+Fout=1950.40 (A=024, B=152)
+Fout=1950.60 (A=025, B=152)
+Fout=1950.80 (A=026, B=152)
+Fout=1951.00 (A=027, B=152)
+Fout=1951.20 (A=028, B=152)
+Fout=1951.40 (A=029, B=152)
+Fout=1951.60 (A=030, B=152)
+Fout=1951.80 (A=031, B=152)
+Fout=1952.00 (A=032, B=152)
+Fout=1952.20 (A=033, B=152)
+Fout=1952.40 (A=034, B=152)
+Fout=1952.60 (A=035, B=152)
+Fout=1952.80 (A=036, B=152)
+Fout=1953.00 (A=037, B=152)
+Fout=1953.20 (A=038, B=152)
+Fout=1953.40 (A=039, B=152)
+Fout=1953.60 (A=040, B=152)
+Fout=1953.80 (A=041, B=152)
+Fout=1954.00 (A=042, B=152)
+Fout=1954.20 (A=043, B=152)
+Fout=1954.40 (A=044, B=152)
+Fout=1954.60 (A=045, B=152)
+Fout=1954.80 (A=046, B=152)
+Fout=1955.00 (A=047, B=152)
+Fout=1955.20 (A=048, B=152)
+Fout=1955.40 (A=049, B=152)
+Fout=1955.60 (A=050, B=152)
+Fout=1955.80 (A=051, B=152)
+Fout=1956.00 (A=052, B=152)
+Fout=1956.20 (A=053, B=152)
+Fout=1956.40 (A=054, B=152)
+Fout=1956.60 (A=055, B=152)
+Fout=1956.80 (A=056, B=152)
+Fout=1957.00 (A=057, B=152)
+Fout=1957.20 (A=058, B=152)
+Fout=1957.40 (A=059, B=152)
+Fout=1957.60 (A=060, B=152)
+Fout=1957.80 (A=061, B=152)
+Fout=1958.00 (A=062, B=152)
+Fout=1958.40 (A=000, B=153)
+Fout=1958.60 (A=001, B=153)
+Fout=1958.80 (A=002, B=153)
+Fout=1959.00 (A=003, B=153)
+Fout=1959.20 (A=004, B=153)
+Fout=1959.40 (A=005, B=153)
+Fout=1959.60 (A=006, B=153)
+Fout=1959.80 (A=007, B=153)
+Fout=1960.00 (A=008, B=153)
+Fout=1960.20 (A=009, B=153)
+Fout=1960.40 (A=010, B=153)
+Fout=1960.60 (A=011, B=153)
+Fout=1960.80 (A=012, B=153)
+Fout=1961.00 (A=013, B=153)
+Fout=1961.20 (A=014, B=153)
+Fout=1961.40 (A=015, B=153)
+Fout=1961.60 (A=016, B=153)
+Fout=1961.80 (A=017, B=153)
+Fout=1962.00 (A=018, B=153)
+Fout=1962.20 (A=019, B=153)
+Fout=1962.40 (A=020, B=153)
+Fout=1962.60 (A=021, B=153)
+Fout=1962.80 (A=022, B=153)
+Fout=1963.00 (A=023, B=153)
+Fout=1963.20 (A=024, B=153)
+Fout=1963.40 (A=025, B=153)
+Fout=1963.60 (A=026, B=153)
+Fout=1963.80 (A=027, B=153)
+Fout=1964.00 (A=028, B=153)
+Fout=1964.20 (A=029, B=153)
+Fout=1964.40 (A=030, B=153)
+Fout=1964.60 (A=031, B=153)
+Fout=1964.80 (A=032, B=153)
+Fout=1965.00 (A=033, B=153)
+Fout=1965.20 (A=034, B=153)
+Fout=1965.40 (A=035, B=153)
+Fout=1965.60 (A=036, B=153)
+Fout=1965.80 (A=037, B=153)
+Fout=1966.00 (A=038, B=153)
+Fout=1966.20 (A=039, B=153)
+Fout=1966.40 (A=040, B=153)
+Fout=1966.60 (A=041, B=153)
+Fout=1966.80 (A=042, B=153)
+Fout=1967.00 (A=043, B=153)
+Fout=1967.20 (A=044, B=153)
+Fout=1967.40 (A=045, B=153)
+Fout=1967.60 (A=046, B=153)
+Fout=1967.80 (A=047, B=153)
+Fout=1968.00 (A=048, B=153)
+Fout=1968.20 (A=049, B=153)
+Fout=1968.40 (A=050, B=153)
+Fout=1968.60 (A=051, B=153)
+Fout=1968.80 (A=052, B=153)
+Fout=1969.00 (A=053, B=153)
+Fout=1969.20 (A=054, B=153)
+Fout=1969.40 (A=055, B=153)
+Fout=1969.60 (A=056, B=153)
+Fout=1969.80 (A=057, B=153)
+Fout=1970.00 (A=058, B=153)
+Fout=1970.20 (A=059, B=153)
+Fout=1970.40 (A=060, B=153)
+Fout=1970.60 (A=061, B=153)
+Fout=1970.80 (A=062, B=153)
+Fout=1971.20 (A=000, B=154)
+Fout=1971.40 (A=001, B=154)
+Fout=1971.60 (A=002, B=154)
+Fout=1971.80 (A=003, B=154)
+Fout=1972.00 (A=004, B=154)
+Fout=1972.20 (A=005, B=154)
+Fout=1972.40 (A=006, B=154)
+Fout=1972.60 (A=007, B=154)
+Fout=1972.80 (A=008, B=154)
+Fout=1973.00 (A=009, B=154)
+Fout=1973.20 (A=010, B=154)
+Fout=1973.40 (A=011, B=154)
+Fout=1973.60 (A=012, B=154)
+Fout=1973.80 (A=013, B=154)
+Fout=1974.00 (A=014, B=154)
+Fout=1974.20 (A=015, B=154)
+Fout=1974.40 (A=016, B=154)
+Fout=1974.60 (A=017, B=154)
+Fout=1974.80 (A=018, B=154)
+Fout=1975.00 (A=019, B=154)
+Fout=1975.20 (A=020, B=154)
+Fout=1975.40 (A=021, B=154)
+Fout=1975.60 (A=022, B=154)
+Fout=1975.80 (A=023, B=154)
+Fout=1976.00 (A=024, B=154)
+Fout=1976.20 (A=025, B=154)
+Fout=1976.40 (A=026, B=154)
+Fout=1976.60 (A=027, B=154)
+Fout=1976.80 (A=028, B=154)
+Fout=1977.00 (A=029, B=154)
+Fout=1977.20 (A=030, B=154)
+Fout=1977.40 (A=031, B=154)
+Fout=1977.60 (A=032, B=154)
+Fout=1977.80 (A=033, B=154)
+Fout=1978.00 (A=034, B=154)
+Fout=1978.20 (A=035, B=154)
+Fout=1978.40 (A=036, B=154)
+Fout=1978.60 (A=037, B=154)
+Fout=1978.80 (A=038, B=154)
+Fout=1979.00 (A=039, B=154)
+Fout=1979.20 (A=040, B=154)
+Fout=1979.40 (A=041, B=154)
+Fout=1979.60 (A=042, B=154)
+Fout=1979.80 (A=043, B=154)
+Fout=1980.00 (A=044, B=154)
+Fout=1980.20 (A=045, B=154)
+Fout=1980.40 (A=046, B=154)
+Fout=1980.60 (A=047, B=154)
+Fout=1980.80 (A=048, B=154)
+Fout=1981.00 (A=049, B=154)
+Fout=1981.20 (A=050, B=154)
+Fout=1981.40 (A=051, B=154)
+Fout=1981.60 (A=052, B=154)
+Fout=1981.80 (A=053, B=154)
+Fout=1982.00 (A=054, B=154)
+Fout=1982.20 (A=055, B=154)
+Fout=1982.40 (A=056, B=154)
+Fout=1982.60 (A=057, B=154)
+Fout=1982.80 (A=058, B=154)
+Fout=1983.00 (A=059, B=154)
+Fout=1983.20 (A=060, B=154)
+Fout=1983.40 (A=061, B=154)
+Fout=1983.60 (A=062, B=154)
+Fout=1984.00 (A=000, B=155)
+Fout=1984.20 (A=001, B=155)
+Fout=1984.40 (A=002, B=155)
+Fout=1984.60 (A=003, B=155)
+Fout=1984.80 (A=004, B=155)
+Fout=1985.00 (A=005, B=155)
+Fout=1985.20 (A=006, B=155)
+Fout=1985.40 (A=007, B=155)
+Fout=1985.60 (A=008, B=155)
+Fout=1985.80 (A=009, B=155)
+Fout=1986.00 (A=010, B=155)
+Fout=1986.20 (A=011, B=155)
+Fout=1986.40 (A=012, B=155)
+Fout=1986.60 (A=013, B=155)
+Fout=1986.80 (A=014, B=155)
+Fout=1987.00 (A=015, B=155)
+Fout=1987.20 (A=016, B=155)
+Fout=1987.40 (A=017, B=155)
+Fout=1987.60 (A=018, B=155)
+Fout=1987.80 (A=019, B=155)
+Fout=1988.00 (A=020, B=155)
+Fout=1988.20 (A=021, B=155)
+Fout=1988.40 (A=022, B=155)
+Fout=1988.60 (A=023, B=155)
+Fout=1988.80 (A=024, B=155)
+Fout=1989.00 (A=025, B=155)
+Fout=1989.20 (A=026, B=155)
+Fout=1989.40 (A=027, B=155)
+Fout=1989.60 (A=028, B=155)
+Fout=1989.80 (A=029, B=155)
+Fout=1990.00 (A=030, B=155)
+Fout=1990.20 (A=031, B=155)
+Fout=1990.40 (A=032, B=155)
+Fout=1990.60 (A=033, B=155)
+Fout=1990.80 (A=034, B=155)
+Fout=1991.00 (A=035, B=155)
+Fout=1991.20 (A=036, B=155)
+Fout=1991.40 (A=037, B=155)
+Fout=1991.60 (A=038, B=155)
+Fout=1991.80 (A=039, B=155)
+Fout=1992.00 (A=040, B=155)
+Fout=1992.20 (A=041, B=155)
+Fout=1992.40 (A=042, B=155)
+Fout=1992.60 (A=043, B=155)
+Fout=1992.80 (A=044, B=155)
+Fout=1993.00 (A=045, B=155)
+Fout=1993.20 (A=046, B=155)
+Fout=1993.40 (A=047, B=155)
+Fout=1993.60 (A=048, B=155)
+Fout=1993.80 (A=049, B=155)
+Fout=1994.00 (A=050, B=155)
+Fout=1994.20 (A=051, B=155)
+Fout=1994.40 (A=052, B=155)
+Fout=1994.60 (A=053, B=155)
+Fout=1994.80 (A=054, B=155)
+Fout=1995.00 (A=055, B=155)
+Fout=1995.20 (A=056, B=155)
+Fout=1995.40 (A=057, B=155)
+Fout=1995.60 (A=058, B=155)
+Fout=1995.80 (A=059, B=155)
+Fout=1996.00 (A=060, B=155)
+Fout=1996.20 (A=061, B=155)
+Fout=1996.40 (A=062, B=155)
+======================================================================
+PLL Tx GSM850_1
+Fout=819.20 (A=000, B=128)
+Fout=819.30 (A=001, B=128)
+Fout=819.40 (A=002, B=128)
+Fout=819.50 (A=003, B=128)
+Fout=819.60 (A=004, B=128)
+Fout=819.70 (A=005, B=128)
+Fout=819.80 (A=006, B=128)
+Fout=819.90 (A=007, B=128)
+Fout=820.00 (A=008, B=128)
+Fout=820.10 (A=009, B=128)
+Fout=820.20 (A=010, B=128)
+Fout=820.30 (A=011, B=128)
+Fout=820.40 (A=012, B=128)
+Fout=820.50 (A=013, B=128)
+Fout=820.60 (A=014, B=128)
+Fout=820.70 (A=015, B=128)
+Fout=820.80 (A=016, B=128)
+Fout=820.90 (A=017, B=128)
+Fout=821.00 (A=018, B=128)
+Fout=821.10 (A=019, B=128)
+Fout=821.20 (A=020, B=128)
+Fout=821.30 (A=021, B=128)
+Fout=821.40 (A=022, B=128)
+Fout=821.50 (A=023, B=128)
+Fout=821.60 (A=024, B=128)
+Fout=821.70 (A=025, B=128)
+Fout=821.80 (A=026, B=128)
+Fout=821.90 (A=027, B=128)
+Fout=822.00 (A=028, B=128)
+Fout=822.10 (A=029, B=128)
+Fout=822.20 (A=030, B=128)
+Fout=822.30 (A=031, B=128)
+Fout=822.40 (A=032, B=128)
+Fout=822.50 (A=033, B=128)
+Fout=822.60 (A=034, B=128)
+Fout=822.70 (A=035, B=128)
+Fout=822.80 (A=036, B=128)
+Fout=822.90 (A=037, B=128)
+Fout=823.00 (A=038, B=128)
+Fout=823.10 (A=039, B=128)
+Fout=823.20 (A=040, B=128)
+Fout=823.30 (A=041, B=128)
+Fout=823.40 (A=042, B=128)
+Fout=823.50 (A=043, B=128)
+Fout=823.60 (A=044, B=128)
+Fout=823.70 (A=045, B=128)
+Fout=823.80 (A=046, B=128)
+Fout=823.90 (A=047, B=128)
+Fout=824.00 (A=048, B=128)
+Fout=824.10 (A=049, B=128)
+Fout=824.20 (A=050, B=128)
+Fout=824.30 (A=051, B=128)
+Fout=824.40 (A=052, B=128)
+Fout=824.50 (A=053, B=128)
+Fout=824.60 (A=054, B=128)
+Fout=824.70 (A=055, B=128)
+Fout=824.80 (A=056, B=128)
+Fout=824.90 (A=057, B=128)
+Fout=825.00 (A=058, B=128)
+Fout=825.10 (A=059, B=128)
+Fout=825.20 (A=060, B=128)
+Fout=825.30 (A=061, B=128)
+Fout=825.40 (A=062, B=128)
+Fout=825.60 (A=000, B=129)
+Fout=825.70 (A=001, B=129)
+Fout=825.80 (A=002, B=129)
+Fout=825.90 (A=003, B=129)
+Fout=826.00 (A=004, B=129)
+Fout=826.10 (A=005, B=129)
+Fout=826.20 (A=006, B=129)
+Fout=826.30 (A=007, B=129)
+Fout=826.40 (A=008, B=129)
+Fout=826.50 (A=009, B=129)
+Fout=826.60 (A=010, B=129)
+Fout=826.70 (A=011, B=129)
+Fout=826.80 (A=012, B=129)
+Fout=826.90 (A=013, B=129)
+Fout=827.00 (A=014, B=129)
+Fout=827.10 (A=015, B=129)
+Fout=827.20 (A=016, B=129)
+Fout=827.30 (A=017, B=129)
+Fout=827.40 (A=018, B=129)
+Fout=827.50 (A=019, B=129)
+Fout=827.60 (A=020, B=129)
+Fout=827.70 (A=021, B=129)
+Fout=827.80 (A=022, B=129)
+Fout=827.90 (A=023, B=129)
+Fout=828.00 (A=024, B=129)
+Fout=828.10 (A=025, B=129)
+Fout=828.20 (A=026, B=129)
+Fout=828.30 (A=027, B=129)
+Fout=828.40 (A=028, B=129)
+Fout=828.50 (A=029, B=129)
+Fout=828.60 (A=030, B=129)
+Fout=828.70 (A=031, B=129)
+Fout=828.80 (A=032, B=129)
+Fout=828.90 (A=033, B=129)
+Fout=829.00 (A=034, B=129)
+Fout=829.10 (A=035, B=129)
+Fout=829.20 (A=036, B=129)
+Fout=829.30 (A=037, B=129)
+Fout=829.40 (A=038, B=129)
+Fout=829.50 (A=039, B=129)
+Fout=829.60 (A=040, B=129)
+Fout=829.70 (A=041, B=129)
+Fout=829.80 (A=042, B=129)
+Fout=829.90 (A=043, B=129)
+Fout=830.00 (A=044, B=129)
+Fout=830.10 (A=045, B=129)
+Fout=830.20 (A=046, B=129)
+Fout=830.30 (A=047, B=129)
+Fout=830.40 (A=048, B=129)
+Fout=830.50 (A=049, B=129)
+Fout=830.60 (A=050, B=129)
+Fout=830.70 (A=051, B=129)
+Fout=830.80 (A=052, B=129)
+Fout=830.90 (A=053, B=129)
+Fout=831.00 (A=054, B=129)
+Fout=831.10 (A=055, B=129)
+Fout=831.20 (A=056, B=129)
+Fout=831.30 (A=057, B=129)
+Fout=831.40 (A=058, B=129)
+Fout=831.50 (A=059, B=129)
+Fout=831.60 (A=060, B=129)
+Fout=831.70 (A=061, B=129)
+Fout=831.80 (A=062, B=129)
+Fout=832.00 (A=000, B=130)
+Fout=832.10 (A=001, B=130)
+Fout=832.20 (A=002, B=130)
+Fout=832.30 (A=003, B=130)
+Fout=832.40 (A=004, B=130)
+Fout=832.50 (A=005, B=130)
+Fout=832.60 (A=006, B=130)
+Fout=832.70 (A=007, B=130)
+Fout=832.80 (A=008, B=130)
+Fout=832.90 (A=009, B=130)
+Fout=833.00 (A=010, B=130)
+Fout=833.10 (A=011, B=130)
+Fout=833.20 (A=012, B=130)
+Fout=833.30 (A=013, B=130)
+Fout=833.40 (A=014, B=130)
+Fout=833.50 (A=015, B=130)
+Fout=833.60 (A=016, B=130)
+Fout=833.70 (A=017, B=130)
+Fout=833.80 (A=018, B=130)
+Fout=833.90 (A=019, B=130)
+Fout=834.00 (A=020, B=130)
+Fout=834.10 (A=021, B=130)
+Fout=834.20 (A=022, B=130)
+Fout=834.30 (A=023, B=130)
+Fout=834.40 (A=024, B=130)
+Fout=834.50 (A=025, B=130)
+Fout=834.60 (A=026, B=130)
+Fout=834.70 (A=027, B=130)
+Fout=834.80 (A=028, B=130)
+Fout=834.90 (A=029, B=130)
+Fout=835.00 (A=030, B=130)
+Fout=835.10 (A=031, B=130)
+Fout=835.20 (A=032, B=130)
+Fout=835.30 (A=033, B=130)
+Fout=835.40 (A=034, B=130)
+Fout=835.50 (A=035, B=130)
+Fout=835.60 (A=036, B=130)
+Fout=835.70 (A=037, B=130)
+Fout=835.80 (A=038, B=130)
+Fout=835.90 (A=039, B=130)
+Fout=836.00 (A=040, B=130)
+Fout=836.10 (A=041, B=130)
+Fout=836.20 (A=042, B=130)
+Fout=836.30 (A=043, B=130)
+Fout=836.40 (A=044, B=130)
+Fout=836.50 (A=045, B=130)
+Fout=836.60 (A=046, B=130)
+Fout=836.70 (A=047, B=130)
+Fout=836.80 (A=048, B=130)
+Fout=836.90 (A=049, B=130)
+Fout=837.00 (A=050, B=130)
+Fout=837.10 (A=051, B=130)
+Fout=837.20 (A=052, B=130)
+Fout=837.30 (A=053, B=130)
+Fout=837.40 (A=054, B=130)
+Fout=837.50 (A=055, B=130)
+Fout=837.60 (A=056, B=130)
+Fout=837.70 (A=057, B=130)
+Fout=837.80 (A=058, B=130)
+Fout=837.90 (A=059, B=130)
+Fout=838.00 (A=060, B=130)
+Fout=838.10 (A=061, B=130)
+Fout=838.20 (A=062, B=130)
+======================================================================
+PLL Tx GSM850_2
+Fout=832.00 (A=000, B=065)
+Fout=832.20 (A=001, B=065)
+Fout=832.40 (A=002, B=065)
+Fout=832.60 (A=003, B=065)
+Fout=832.80 (A=004, B=065)
+Fout=833.00 (A=005, B=065)
+Fout=833.20 (A=006, B=065)
+Fout=833.40 (A=007, B=065)
+Fout=833.60 (A=008, B=065)
+Fout=833.80 (A=009, B=065)
+Fout=834.00 (A=010, B=065)
+Fout=834.20 (A=011, B=065)
+Fout=834.40 (A=012, B=065)
+Fout=834.60 (A=013, B=065)
+Fout=834.80 (A=014, B=065)
+Fout=835.00 (A=015, B=065)
+Fout=835.20 (A=016, B=065)
+Fout=835.40 (A=017, B=065)
+Fout=835.60 (A=018, B=065)
+Fout=835.80 (A=019, B=065)
+Fout=836.00 (A=020, B=065)
+Fout=836.20 (A=021, B=065)
+Fout=836.40 (A=022, B=065)
+Fout=836.60 (A=023, B=065)
+Fout=836.80 (A=024, B=065)
+Fout=837.00 (A=025, B=065)
+Fout=837.20 (A=026, B=065)
+Fout=837.40 (A=027, B=065)
+Fout=837.60 (A=028, B=065)
+Fout=837.80 (A=029, B=065)
+Fout=838.00 (A=030, B=065)
+Fout=838.20 (A=031, B=065)
+Fout=838.40 (A=032, B=065)
+Fout=838.60 (A=033, B=065)
+Fout=838.80 (A=034, B=065)
+Fout=839.00 (A=035, B=065)
+Fout=839.20 (A=036, B=065)
+Fout=839.40 (A=037, B=065)
+Fout=839.60 (A=038, B=065)
+Fout=839.80 (A=039, B=065)
+Fout=840.00 (A=040, B=065)
+Fout=840.20 (A=041, B=065)
+Fout=840.40 (A=042, B=065)
+Fout=840.60 (A=043, B=065)
+Fout=840.80 (A=044, B=065)
+Fout=841.00 (A=045, B=065)
+Fout=841.20 (A=046, B=065)
+Fout=841.40 (A=047, B=065)
+Fout=841.60 (A=048, B=065)
+Fout=841.80 (A=049, B=065)
+Fout=842.00 (A=050, B=065)
+Fout=842.20 (A=051, B=065)
+Fout=842.40 (A=052, B=065)
+Fout=842.60 (A=053, B=065)
+Fout=842.80 (A=054, B=065)
+Fout=843.00 (A=055, B=065)
+Fout=843.20 (A=056, B=065)
+Fout=843.40 (A=057, B=065)
+Fout=843.60 (A=058, B=065)
+Fout=843.80 (A=059, B=065)
+Fout=844.00 (A=060, B=065)
+Fout=844.20 (A=061, B=065)
+Fout=844.40 (A=062, B=065)
+Fout=844.60 (A=063, B=065)
+Fout=844.80 (A=000, B=066)
+Fout=845.00 (A=001, B=066)
+Fout=845.20 (A=002, B=066)
+Fout=845.40 (A=003, B=066)
+Fout=845.60 (A=004, B=066)
+Fout=845.80 (A=005, B=066)
+Fout=846.00 (A=006, B=066)
+Fout=846.20 (A=007, B=066)
+Fout=846.40 (A=008, B=066)
+Fout=846.60 (A=009, B=066)
+Fout=846.80 (A=010, B=066)
+Fout=847.00 (A=011, B=066)
+Fout=847.20 (A=012, B=066)
+Fout=847.40 (A=013, B=066)
+Fout=847.60 (A=014, B=066)
+Fout=847.80 (A=015, B=066)
+Fout=848.00 (A=016, B=066)
+Fout=848.20 (A=017, B=066)
+Fout=848.40 (A=018, B=066)
+Fout=848.60 (A=019, B=066)
+Fout=848.80 (A=020, B=066)
+Fout=849.00 (A=021, B=066)
+Fout=849.20 (A=022, B=066)
+Fout=849.40 (A=023, B=066)
+Fout=849.60 (A=024, B=066)
+Fout=849.80 (A=025, B=066)
+Fout=850.00 (A=026, B=066)
+Fout=850.20 (A=027, B=066)
+Fout=850.40 (A=028, B=066)
+Fout=850.60 (A=029, B=066)
+Fout=850.80 (A=030, B=066)
+Fout=851.00 (A=031, B=066)
+Fout=851.20 (A=032, B=066)
+Fout=851.40 (A=033, B=066)
+Fout=851.60 (A=034, B=066)
+Fout=851.80 (A=035, B=066)
+Fout=852.00 (A=036, B=066)
+Fout=852.20 (A=037, B=066)
+Fout=852.40 (A=038, B=066)
+Fout=852.60 (A=039, B=066)
+Fout=852.80 (A=040, B=066)
+Fout=853.00 (A=041, B=066)
+Fout=853.20 (A=042, B=066)
+Fout=853.40 (A=043, B=066)
+Fout=853.60 (A=044, B=066)
+Fout=853.80 (A=045, B=066)
+Fout=854.00 (A=046, B=066)
+Fout=854.20 (A=047, B=066)
+Fout=854.40 (A=048, B=066)
+Fout=854.60 (A=049, B=066)
+Fout=854.80 (A=050, B=066)
+Fout=855.00 (A=051, B=066)
+Fout=855.20 (A=052, B=066)
+Fout=855.40 (A=053, B=066)
+Fout=855.60 (A=054, B=066)
+Fout=855.80 (A=055, B=066)
+Fout=856.00 (A=056, B=066)
+Fout=856.20 (A=057, B=066)
+Fout=856.40 (A=058, B=066)
+Fout=856.60 (A=059, B=066)
+Fout=856.80 (A=060, B=066)
+Fout=857.00 (A=061, B=066)
+Fout=857.20 (A=062, B=066)
+Fout=857.40 (A=063, B=066)
+======================================================================
+PLL Tx GSM900
+Fout=870.40 (A=000, B=068)
+Fout=870.60 (A=001, B=068)
+Fout=870.80 (A=002, B=068)
+Fout=871.00 (A=003, B=068)
+Fout=871.20 (A=004, B=068)
+Fout=871.40 (A=005, B=068)
+Fout=871.60 (A=006, B=068)
+Fout=871.80 (A=007, B=068)
+Fout=872.00 (A=008, B=068)
+Fout=872.20 (A=009, B=068)
+Fout=872.40 (A=010, B=068)
+Fout=872.60 (A=011, B=068)
+Fout=872.80 (A=012, B=068)
+Fout=873.00 (A=013, B=068)
+Fout=873.20 (A=014, B=068)
+Fout=873.40 (A=015, B=068)
+Fout=873.60 (A=016, B=068)
+Fout=873.80 (A=017, B=068)
+Fout=874.00 (A=018, B=068)
+Fout=874.20 (A=019, B=068)
+Fout=874.40 (A=020, B=068)
+Fout=874.60 (A=021, B=068)
+Fout=874.80 (A=022, B=068)
+Fout=875.00 (A=023, B=068)
+Fout=875.20 (A=024, B=068)
+Fout=875.40 (A=025, B=068)
+Fout=875.60 (A=026, B=068)
+Fout=875.80 (A=027, B=068)
+Fout=876.00 (A=028, B=068)
+Fout=876.20 (A=029, B=068)
+Fout=876.40 (A=030, B=068)
+Fout=876.60 (A=031, B=068)
+Fout=876.80 (A=032, B=068)
+Fout=877.00 (A=033, B=068)
+Fout=877.20 (A=034, B=068)
+Fout=877.40 (A=035, B=068)
+Fout=877.60 (A=036, B=068)
+Fout=877.80 (A=037, B=068)
+Fout=878.00 (A=038, B=068)
+Fout=878.20 (A=039, B=068)
+Fout=878.40 (A=040, B=068)
+Fout=878.60 (A=041, B=068)
+Fout=878.80 (A=042, B=068)
+Fout=879.00 (A=043, B=068)
+Fout=879.20 (A=044, B=068)
+Fout=879.40 (A=045, B=068)
+Fout=879.60 (A=046, B=068)
+Fout=879.80 (A=047, B=068)
+Fout=880.00 (A=048, B=068)
+Fout=880.20 (A=049, B=068)
+Fout=880.40 (A=050, B=068)
+Fout=880.60 (A=051, B=068)
+Fout=880.80 (A=052, B=068)
+Fout=881.00 (A=053, B=068)
+Fout=881.20 (A=054, B=068)
+Fout=881.40 (A=055, B=068)
+Fout=881.60 (A=056, B=068)
+Fout=881.80 (A=057, B=068)
+Fout=882.00 (A=058, B=068)
+Fout=882.20 (A=059, B=068)
+Fout=882.40 (A=060, B=068)
+Fout=882.60 (A=061, B=068)
+Fout=882.80 (A=062, B=068)
+Fout=883.00 (A=063, B=068)
+Fout=883.20 (A=000, B=069)
+Fout=883.40 (A=001, B=069)
+Fout=883.60 (A=002, B=069)
+Fout=883.80 (A=003, B=069)
+Fout=884.00 (A=004, B=069)
+Fout=884.20 (A=005, B=069)
+Fout=884.40 (A=006, B=069)
+Fout=884.60 (A=007, B=069)
+Fout=884.80 (A=008, B=069)
+Fout=885.00 (A=009, B=069)
+Fout=885.20 (A=010, B=069)
+Fout=885.40 (A=011, B=069)
+Fout=885.60 (A=012, B=069)
+Fout=885.80 (A=013, B=069)
+Fout=886.00 (A=014, B=069)
+Fout=886.20 (A=015, B=069)
+Fout=886.40 (A=016, B=069)
+Fout=886.60 (A=017, B=069)
+Fout=886.80 (A=018, B=069)
+Fout=887.00 (A=019, B=069)
+Fout=887.20 (A=020, B=069)
+Fout=887.40 (A=021, B=069)
+Fout=887.60 (A=022, B=069)
+Fout=887.80 (A=023, B=069)
+Fout=888.00 (A=024, B=069)
+Fout=888.20 (A=025, B=069)
+Fout=888.40 (A=026, B=069)
+Fout=888.60 (A=027, B=069)
+Fout=888.80 (A=028, B=069)
+Fout=889.00 (A=029, B=069)
+Fout=889.20 (A=030, B=069)
+Fout=889.40 (A=031, B=069)
+Fout=889.60 (A=032, B=069)
+Fout=889.80 (A=033, B=069)
+Fout=890.00 (A=034, B=069)
+Fout=890.20 (A=035, B=069)
+Fout=890.40 (A=036, B=069)
+Fout=890.60 (A=037, B=069)
+Fout=890.80 (A=038, B=069)
+Fout=891.00 (A=039, B=069)
+Fout=891.20 (A=040, B=069)
+Fout=891.40 (A=041, B=069)
+Fout=891.60 (A=042, B=069)
+Fout=891.80 (A=043, B=069)
+Fout=892.00 (A=044, B=069)
+Fout=892.20 (A=045, B=069)
+Fout=892.40 (A=046, B=069)
+Fout=892.60 (A=047, B=069)
+Fout=892.80 (A=048, B=069)
+Fout=893.00 (A=049, B=069)
+Fout=893.20 (A=050, B=069)
+Fout=893.40 (A=051, B=069)
+Fout=893.60 (A=052, B=069)
+Fout=893.80 (A=053, B=069)
+Fout=894.00 (A=054, B=069)
+Fout=894.20 (A=055, B=069)
+Fout=894.40 (A=056, B=069)
+Fout=894.60 (A=057, B=069)
+Fout=894.80 (A=058, B=069)
+Fout=895.00 (A=059, B=069)
+Fout=895.20 (A=060, B=069)
+Fout=895.40 (A=061, B=069)
+Fout=895.60 (A=062, B=069)
+Fout=895.80 (A=063, B=069)
+Fout=896.00 (A=000, B=070)
+Fout=896.20 (A=001, B=070)
+Fout=896.40 (A=002, B=070)
+Fout=896.60 (A=003, B=070)
+Fout=896.80 (A=004, B=070)
+Fout=897.00 (A=005, B=070)
+Fout=897.20 (A=006, B=070)
+Fout=897.40 (A=007, B=070)
+Fout=897.60 (A=008, B=070)
+Fout=897.80 (A=009, B=070)
+Fout=898.00 (A=010, B=070)
+Fout=898.20 (A=011, B=070)
+Fout=898.40 (A=012, B=070)
+Fout=898.60 (A=013, B=070)
+Fout=898.80 (A=014, B=070)
+Fout=899.00 (A=015, B=070)
+Fout=899.20 (A=016, B=070)
+Fout=899.40 (A=017, B=070)
+Fout=899.60 (A=018, B=070)
+Fout=899.80 (A=019, B=070)
+Fout=900.00 (A=020, B=070)
+Fout=900.20 (A=021, B=070)
+Fout=900.40 (A=022, B=070)
+Fout=900.60 (A=023, B=070)
+Fout=900.80 (A=024, B=070)
+Fout=901.00 (A=025, B=070)
+Fout=901.20 (A=026, B=070)
+Fout=901.40 (A=027, B=070)
+Fout=901.60 (A=028, B=070)
+Fout=901.80 (A=029, B=070)
+Fout=902.00 (A=030, B=070)
+Fout=902.20 (A=031, B=070)
+Fout=902.40 (A=032, B=070)
+Fout=902.60 (A=033, B=070)
+Fout=902.80 (A=034, B=070)
+Fout=903.00 (A=035, B=070)
+Fout=903.20 (A=036, B=070)
+Fout=903.40 (A=037, B=070)
+Fout=903.60 (A=038, B=070)
+Fout=903.80 (A=039, B=070)
+Fout=904.00 (A=040, B=070)
+Fout=904.20 (A=041, B=070)
+Fout=904.40 (A=042, B=070)
+Fout=904.60 (A=043, B=070)
+Fout=904.80 (A=044, B=070)
+Fout=905.00 (A=045, B=070)
+Fout=905.20 (A=046, B=070)
+Fout=905.40 (A=047, B=070)
+Fout=905.60 (A=048, B=070)
+Fout=905.80 (A=049, B=070)
+Fout=906.00 (A=050, B=070)
+Fout=906.20 (A=051, B=070)
+Fout=906.40 (A=052, B=070)
+Fout=906.60 (A=053, B=070)
+Fout=906.80 (A=054, B=070)
+Fout=907.00 (A=055, B=070)
+Fout=907.20 (A=056, B=070)
+Fout=907.40 (A=057, B=070)
+Fout=907.60 (A=058, B=070)
+Fout=907.80 (A=059, B=070)
+Fout=908.00 (A=060, B=070)
+Fout=908.20 (A=061, B=070)
+Fout=908.40 (A=062, B=070)
+Fout=908.60 (A=063, B=070)
+Fout=908.80 (A=000, B=071)
+Fout=909.00 (A=001, B=071)
+Fout=909.20 (A=002, B=071)
+Fout=909.40 (A=003, B=071)
+Fout=909.60 (A=004, B=071)
+Fout=909.80 (A=005, B=071)
+Fout=910.00 (A=006, B=071)
+Fout=910.20 (A=007, B=071)
+Fout=910.40 (A=008, B=071)
+Fout=910.60 (A=009, B=071)
+Fout=910.80 (A=010, B=071)
+Fout=911.00 (A=011, B=071)
+Fout=911.20 (A=012, B=071)
+Fout=911.40 (A=013, B=071)
+Fout=911.60 (A=014, B=071)
+Fout=911.80 (A=015, B=071)
+Fout=912.00 (A=016, B=071)
+Fout=912.20 (A=017, B=071)
+Fout=912.40 (A=018, B=071)
+Fout=912.60 (A=019, B=071)
+Fout=912.80 (A=020, B=071)
+Fout=913.00 (A=021, B=071)
+Fout=913.20 (A=022, B=071)
+Fout=913.40 (A=023, B=071)
+Fout=913.60 (A=024, B=071)
+Fout=913.80 (A=025, B=071)
+Fout=914.00 (A=026, B=071)
+Fout=914.20 (A=027, B=071)
+Fout=914.40 (A=028, B=071)
+Fout=914.60 (A=029, B=071)
+Fout=914.80 (A=030, B=071)
+Fout=915.00 (A=031, B=071)
+Fout=915.20 (A=032, B=071)
+Fout=915.40 (A=033, B=071)
+Fout=915.60 (A=034, B=071)
+Fout=915.80 (A=035, B=071)
+Fout=916.00 (A=036, B=071)
+Fout=916.20 (A=037, B=071)
+Fout=916.40 (A=038, B=071)
+Fout=916.60 (A=039, B=071)
+Fout=916.80 (A=040, B=071)
+Fout=917.00 (A=041, B=071)
+Fout=917.20 (A=042, B=071)
+Fout=917.40 (A=043, B=071)
+Fout=917.60 (A=044, B=071)
+Fout=917.80 (A=045, B=071)
+Fout=918.00 (A=046, B=071)
+Fout=918.20 (A=047, B=071)
+Fout=918.40 (A=048, B=071)
+Fout=918.60 (A=049, B=071)
+Fout=918.80 (A=050, B=071)
+Fout=919.00 (A=051, B=071)
+Fout=919.20 (A=052, B=071)
+Fout=919.40 (A=053, B=071)
+Fout=919.60 (A=054, B=071)
+Fout=919.80 (A=055, B=071)
+Fout=920.00 (A=056, B=071)
+Fout=920.20 (A=057, B=071)
+Fout=920.40 (A=058, B=071)
+Fout=920.60 (A=059, B=071)
+Fout=920.80 (A=060, B=071)
+Fout=921.00 (A=061, B=071)
+Fout=921.20 (A=062, B=071)
+Fout=921.40 (A=063, B=071)
+======================================================================
+PLL Tx GSM1800/1900
+Fout=1702.40 (A=000, B=133)
+Fout=1702.60 (A=001, B=133)
+Fout=1702.80 (A=002, B=133)
+Fout=1703.00 (A=003, B=133)
+Fout=1703.20 (A=004, B=133)
+Fout=1703.40 (A=005, B=133)
+Fout=1703.60 (A=006, B=133)
+Fout=1703.80 (A=007, B=133)
+Fout=1704.00 (A=008, B=133)
+Fout=1704.20 (A=009, B=133)
+Fout=1704.40 (A=010, B=133)
+Fout=1704.60 (A=011, B=133)
+Fout=1704.80 (A=012, B=133)
+Fout=1705.00 (A=013, B=133)
+Fout=1705.20 (A=014, B=133)
+Fout=1705.40 (A=015, B=133)
+Fout=1705.60 (A=016, B=133)
+Fout=1705.80 (A=017, B=133)
+Fout=1706.00 (A=018, B=133)
+Fout=1706.20 (A=019, B=133)
+Fout=1706.40 (A=020, B=133)
+Fout=1706.60 (A=021, B=133)
+Fout=1706.80 (A=022, B=133)
+Fout=1707.00 (A=023, B=133)
+Fout=1707.20 (A=024, B=133)
+Fout=1707.40 (A=025, B=133)
+Fout=1707.60 (A=026, B=133)
+Fout=1707.80 (A=027, B=133)
+Fout=1708.00 (A=028, B=133)
+Fout=1708.20 (A=029, B=133)
+Fout=1708.40 (A=030, B=133)
+Fout=1708.60 (A=031, B=133)
+Fout=1708.80 (A=032, B=133)
+Fout=1709.00 (A=033, B=133)
+Fout=1709.20 (A=034, B=133)
+Fout=1709.40 (A=035, B=133)
+Fout=1709.60 (A=036, B=133)
+Fout=1709.80 (A=037, B=133)
+Fout=1710.00 (A=038, B=133)
+Fout=1710.20 (A=039, B=133)
+Fout=1710.40 (A=040, B=133)
+Fout=1710.60 (A=041, B=133)
+Fout=1710.80 (A=042, B=133)
+Fout=1711.00 (A=043, B=133)
+Fout=1711.20 (A=044, B=133)
+Fout=1711.40 (A=045, B=133)
+Fout=1711.60 (A=046, B=133)
+Fout=1711.80 (A=047, B=133)
+Fout=1712.00 (A=048, B=133)
+Fout=1712.20 (A=049, B=133)
+Fout=1712.40 (A=050, B=133)
+Fout=1712.60 (A=051, B=133)
+Fout=1712.80 (A=052, B=133)
+Fout=1713.00 (A=053, B=133)
+Fout=1713.20 (A=054, B=133)
+Fout=1713.40 (A=055, B=133)
+Fout=1713.60 (A=056, B=133)
+Fout=1713.80 (A=057, B=133)
+Fout=1714.00 (A=058, B=133)
+Fout=1714.20 (A=059, B=133)
+Fout=1714.40 (A=060, B=133)
+Fout=1714.60 (A=061, B=133)
+Fout=1714.80 (A=062, B=133)
+Fout=1715.00 (A=063, B=133)
+Fout=1715.20 (A=000, B=134)
+Fout=1715.40 (A=001, B=134)
+Fout=1715.60 (A=002, B=134)
+Fout=1715.80 (A=003, B=134)
+Fout=1716.00 (A=004, B=134)
+Fout=1716.20 (A=005, B=134)
+Fout=1716.40 (A=006, B=134)
+Fout=1716.60 (A=007, B=134)
+Fout=1716.80 (A=008, B=134)
+Fout=1717.00 (A=009, B=134)
+Fout=1717.20 (A=010, B=134)
+Fout=1717.40 (A=011, B=134)
+Fout=1717.60 (A=012, B=134)
+Fout=1717.80 (A=013, B=134)
+Fout=1718.00 (A=014, B=134)
+Fout=1718.20 (A=015, B=134)
+Fout=1718.40 (A=016, B=134)
+Fout=1718.60 (A=017, B=134)
+Fout=1718.80 (A=018, B=134)
+Fout=1719.00 (A=019, B=134)
+Fout=1719.20 (A=020, B=134)
+Fout=1719.40 (A=021, B=134)
+Fout=1719.60 (A=022, B=134)
+Fout=1719.80 (A=023, B=134)
+Fout=1720.00 (A=024, B=134)
+Fout=1720.20 (A=025, B=134)
+Fout=1720.40 (A=026, B=134)
+Fout=1720.60 (A=027, B=134)
+Fout=1720.80 (A=028, B=134)
+Fout=1721.00 (A=029, B=134)
+Fout=1721.20 (A=030, B=134)
+Fout=1721.40 (A=031, B=134)
+Fout=1721.60 (A=032, B=134)
+Fout=1721.80 (A=033, B=134)
+Fout=1722.00 (A=034, B=134)
+Fout=1722.20 (A=035, B=134)
+Fout=1722.40 (A=036, B=134)
+Fout=1722.60 (A=037, B=134)
+Fout=1722.80 (A=038, B=134)
+Fout=1723.00 (A=039, B=134)
+Fout=1723.20 (A=040, B=134)
+Fout=1723.40 (A=041, B=134)
+Fout=1723.60 (A=042, B=134)
+Fout=1723.80 (A=043, B=134)
+Fout=1724.00 (A=044, B=134)
+Fout=1724.20 (A=045, B=134)
+Fout=1724.40 (A=046, B=134)
+Fout=1724.60 (A=047, B=134)
+Fout=1724.80 (A=048, B=134)
+Fout=1725.00 (A=049, B=134)
+Fout=1725.20 (A=050, B=134)
+Fout=1725.40 (A=051, B=134)
+Fout=1725.60 (A=052, B=134)
+Fout=1725.80 (A=053, B=134)
+Fout=1726.00 (A=054, B=134)
+Fout=1726.20 (A=055, B=134)
+Fout=1726.40 (A=056, B=134)
+Fout=1726.60 (A=057, B=134)
+Fout=1726.80 (A=058, B=134)
+Fout=1727.00 (A=059, B=134)
+Fout=1727.20 (A=060, B=134)
+Fout=1727.40 (A=061, B=134)
+Fout=1727.60 (A=062, B=134)
+Fout=1727.80 (A=063, B=134)
+Fout=1728.00 (A=000, B=135)
+Fout=1728.20 (A=001, B=135)
+Fout=1728.40 (A=002, B=135)
+Fout=1728.60 (A=003, B=135)
+Fout=1728.80 (A=004, B=135)
+Fout=1729.00 (A=005, B=135)
+Fout=1729.20 (A=006, B=135)
+Fout=1729.40 (A=007, B=135)
+Fout=1729.60 (A=008, B=135)
+Fout=1729.80 (A=009, B=135)
+Fout=1730.00 (A=010, B=135)
+Fout=1730.20 (A=011, B=135)
+Fout=1730.40 (A=012, B=135)
+Fout=1730.60 (A=013, B=135)
+Fout=1730.80 (A=014, B=135)
+Fout=1731.00 (A=015, B=135)
+Fout=1731.20 (A=016, B=135)
+Fout=1731.40 (A=017, B=135)
+Fout=1731.60 (A=018, B=135)
+Fout=1731.80 (A=019, B=135)
+Fout=1732.00 (A=020, B=135)
+Fout=1732.20 (A=021, B=135)
+Fout=1732.40 (A=022, B=135)
+Fout=1732.60 (A=023, B=135)
+Fout=1732.80 (A=024, B=135)
+Fout=1733.00 (A=025, B=135)
+Fout=1733.20 (A=026, B=135)
+Fout=1733.40 (A=027, B=135)
+Fout=1733.60 (A=028, B=135)
+Fout=1733.80 (A=029, B=135)
+Fout=1734.00 (A=030, B=135)
+Fout=1734.20 (A=031, B=135)
+Fout=1734.40 (A=032, B=135)
+Fout=1734.60 (A=033, B=135)
+Fout=1734.80 (A=034, B=135)
+Fout=1735.00 (A=035, B=135)
+Fout=1735.20 (A=036, B=135)
+Fout=1735.40 (A=037, B=135)
+Fout=1735.60 (A=038, B=135)
+Fout=1735.80 (A=039, B=135)
+Fout=1736.00 (A=040, B=135)
+Fout=1736.20 (A=041, B=135)
+Fout=1736.40 (A=042, B=135)
+Fout=1736.60 (A=043, B=135)
+Fout=1736.80 (A=044, B=135)
+Fout=1737.00 (A=045, B=135)
+Fout=1737.20 (A=046, B=135)
+Fout=1737.40 (A=047, B=135)
+Fout=1737.60 (A=048, B=135)
+Fout=1737.80 (A=049, B=135)
+Fout=1738.00 (A=050, B=135)
+Fout=1738.20 (A=051, B=135)
+Fout=1738.40 (A=052, B=135)
+Fout=1738.60 (A=053, B=135)
+Fout=1738.80 (A=054, B=135)
+Fout=1739.00 (A=055, B=135)
+Fout=1739.20 (A=056, B=135)
+Fout=1739.40 (A=057, B=135)
+Fout=1739.60 (A=058, B=135)
+Fout=1739.80 (A=059, B=135)
+Fout=1740.00 (A=060, B=135)
+Fout=1740.20 (A=061, B=135)
+Fout=1740.40 (A=062, B=135)
+Fout=1740.60 (A=063, B=135)
+Fout=1740.80 (A=000, B=136)
+Fout=1741.00 (A=001, B=136)
+Fout=1741.20 (A=002, B=136)
+Fout=1741.40 (A=003, B=136)
+Fout=1741.60 (A=004, B=136)
+Fout=1741.80 (A=005, B=136)
+Fout=1742.00 (A=006, B=136)
+Fout=1742.20 (A=007, B=136)
+Fout=1742.40 (A=008, B=136)
+Fout=1742.60 (A=009, B=136)
+Fout=1742.80 (A=010, B=136)
+Fout=1743.00 (A=011, B=136)
+Fout=1743.20 (A=012, B=136)
+Fout=1743.40 (A=013, B=136)
+Fout=1743.60 (A=014, B=136)
+Fout=1743.80 (A=015, B=136)
+Fout=1744.00 (A=016, B=136)
+Fout=1744.20 (A=017, B=136)
+Fout=1744.40 (A=018, B=136)
+Fout=1744.60 (A=019, B=136)
+Fout=1744.80 (A=020, B=136)
+Fout=1745.00 (A=021, B=136)
+Fout=1745.20 (A=022, B=136)
+Fout=1745.40 (A=023, B=136)
+Fout=1745.60 (A=024, B=136)
+Fout=1745.80 (A=025, B=136)
+Fout=1746.00 (A=026, B=136)
+Fout=1746.20 (A=027, B=136)
+Fout=1746.40 (A=028, B=136)
+Fout=1746.60 (A=029, B=136)
+Fout=1746.80 (A=030, B=136)
+Fout=1747.00 (A=031, B=136)
+Fout=1747.20 (A=032, B=136)
+Fout=1747.40 (A=033, B=136)
+Fout=1747.60 (A=034, B=136)
+Fout=1747.80 (A=035, B=136)
+Fout=1748.00 (A=036, B=136)
+Fout=1748.20 (A=037, B=136)
+Fout=1748.40 (A=038, B=136)
+Fout=1748.60 (A=039, B=136)
+Fout=1748.80 (A=040, B=136)
+Fout=1749.00 (A=041, B=136)
+Fout=1749.20 (A=042, B=136)
+Fout=1749.40 (A=043, B=136)
+Fout=1749.60 (A=044, B=136)
+Fout=1749.80 (A=045, B=136)
+Fout=1750.00 (A=046, B=136)
+Fout=1750.20 (A=047, B=136)
+Fout=1750.40 (A=048, B=136)
+Fout=1750.60 (A=049, B=136)
+Fout=1750.80 (A=050, B=136)
+Fout=1751.00 (A=051, B=136)
+Fout=1751.20 (A=052, B=136)
+Fout=1751.40 (A=053, B=136)
+Fout=1751.60 (A=054, B=136)
+Fout=1751.80 (A=055, B=136)
+Fout=1752.00 (A=056, B=136)
+Fout=1752.20 (A=057, B=136)
+Fout=1752.40 (A=058, B=136)
+Fout=1752.60 (A=059, B=136)
+Fout=1752.80 (A=060, B=136)
+Fout=1753.00 (A=061, B=136)
+Fout=1753.20 (A=062, B=136)
+Fout=1753.40 (A=063, B=136)
+Fout=1753.60 (A=000, B=137)
+Fout=1753.80 (A=001, B=137)
+Fout=1754.00 (A=002, B=137)
+Fout=1754.20 (A=003, B=137)
+Fout=1754.40 (A=004, B=137)
+Fout=1754.60 (A=005, B=137)
+Fout=1754.80 (A=006, B=137)
+Fout=1755.00 (A=007, B=137)
+Fout=1755.20 (A=008, B=137)
+Fout=1755.40 (A=009, B=137)
+Fout=1755.60 (A=010, B=137)
+Fout=1755.80 (A=011, B=137)
+Fout=1756.00 (A=012, B=137)
+Fout=1756.20 (A=013, B=137)
+Fout=1756.40 (A=014, B=137)
+Fout=1756.60 (A=015, B=137)
+Fout=1756.80 (A=016, B=137)
+Fout=1757.00 (A=017, B=137)
+Fout=1757.20 (A=018, B=137)
+Fout=1757.40 (A=019, B=137)
+Fout=1757.60 (A=020, B=137)
+Fout=1757.80 (A=021, B=137)
+Fout=1758.00 (A=022, B=137)
+Fout=1758.20 (A=023, B=137)
+Fout=1758.40 (A=024, B=137)
+Fout=1758.60 (A=025, B=137)
+Fout=1758.80 (A=026, B=137)
+Fout=1759.00 (A=027, B=137)
+Fout=1759.20 (A=028, B=137)
+Fout=1759.40 (A=029, B=137)
+Fout=1759.60 (A=030, B=137)
+Fout=1759.80 (A=031, B=137)
+Fout=1760.00 (A=032, B=137)
+Fout=1760.20 (A=033, B=137)
+Fout=1760.40 (A=034, B=137)
+Fout=1760.60 (A=035, B=137)
+Fout=1760.80 (A=036, B=137)
+Fout=1761.00 (A=037, B=137)
+Fout=1761.20 (A=038, B=137)
+Fout=1761.40 (A=039, B=137)
+Fout=1761.60 (A=040, B=137)
+Fout=1761.80 (A=041, B=137)
+Fout=1762.00 (A=042, B=137)
+Fout=1762.20 (A=043, B=137)
+Fout=1762.40 (A=044, B=137)
+Fout=1762.60 (A=045, B=137)
+Fout=1762.80 (A=046, B=137)
+Fout=1763.00 (A=047, B=137)
+Fout=1763.20 (A=048, B=137)
+Fout=1763.40 (A=049, B=137)
+Fout=1763.60 (A=050, B=137)
+Fout=1763.80 (A=051, B=137)
+Fout=1764.00 (A=052, B=137)
+Fout=1764.20 (A=053, B=137)
+Fout=1764.40 (A=054, B=137)
+Fout=1764.60 (A=055, B=137)
+Fout=1764.80 (A=056, B=137)
+Fout=1765.00 (A=057, B=137)
+Fout=1765.20 (A=058, B=137)
+Fout=1765.40 (A=059, B=137)
+Fout=1765.60 (A=060, B=137)
+Fout=1765.80 (A=061, B=137)
+Fout=1766.00 (A=062, B=137)
+Fout=1766.20 (A=063, B=137)
+Fout=1766.40 (A=000, B=138)
+Fout=1766.60 (A=001, B=138)
+Fout=1766.80 (A=002, B=138)
+Fout=1767.00 (A=003, B=138)
+Fout=1767.20 (A=004, B=138)
+Fout=1767.40 (A=005, B=138)
+Fout=1767.60 (A=006, B=138)
+Fout=1767.80 (A=007, B=138)
+Fout=1768.00 (A=008, B=138)
+Fout=1768.20 (A=009, B=138)
+Fout=1768.40 (A=010, B=138)
+Fout=1768.60 (A=011, B=138)
+Fout=1768.80 (A=012, B=138)
+Fout=1769.00 (A=013, B=138)
+Fout=1769.20 (A=014, B=138)
+Fout=1769.40 (A=015, B=138)
+Fout=1769.60 (A=016, B=138)
+Fout=1769.80 (A=017, B=138)
+Fout=1770.00 (A=018, B=138)
+Fout=1770.20 (A=019, B=138)
+Fout=1770.40 (A=020, B=138)
+Fout=1770.60 (A=021, B=138)
+Fout=1770.80 (A=022, B=138)
+Fout=1771.00 (A=023, B=138)
+Fout=1771.20 (A=024, B=138)
+Fout=1771.40 (A=025, B=138)
+Fout=1771.60 (A=026, B=138)
+Fout=1771.80 (A=027, B=138)
+Fout=1772.00 (A=028, B=138)
+Fout=1772.20 (A=029, B=138)
+Fout=1772.40 (A=030, B=138)
+Fout=1772.60 (A=031, B=138)
+Fout=1772.80 (A=032, B=138)
+Fout=1773.00 (A=033, B=138)
+Fout=1773.20 (A=034, B=138)
+Fout=1773.40 (A=035, B=138)
+Fout=1773.60 (A=036, B=138)
+Fout=1773.80 (A=037, B=138)
+Fout=1774.00 (A=038, B=138)
+Fout=1774.20 (A=039, B=138)
+Fout=1774.40 (A=040, B=138)
+Fout=1774.60 (A=041, B=138)
+Fout=1774.80 (A=042, B=138)
+Fout=1775.00 (A=043, B=138)
+Fout=1775.20 (A=044, B=138)
+Fout=1775.40 (A=045, B=138)
+Fout=1775.60 (A=046, B=138)
+Fout=1775.80 (A=047, B=138)
+Fout=1776.00 (A=048, B=138)
+Fout=1776.20 (A=049, B=138)
+Fout=1776.40 (A=050, B=138)
+Fout=1776.60 (A=051, B=138)
+Fout=1776.80 (A=052, B=138)
+Fout=1777.00 (A=053, B=138)
+Fout=1777.20 (A=054, B=138)
+Fout=1777.40 (A=055, B=138)
+Fout=1777.60 (A=056, B=138)
+Fout=1777.80 (A=057, B=138)
+Fout=1778.00 (A=058, B=138)
+Fout=1778.20 (A=059, B=138)
+Fout=1778.40 (A=060, B=138)
+Fout=1778.60 (A=061, B=138)
+Fout=1778.80 (A=062, B=138)
+Fout=1779.00 (A=063, B=138)
+Fout=1779.20 (A=000, B=139)
+Fout=1779.40 (A=001, B=139)
+Fout=1779.60 (A=002, B=139)
+Fout=1779.80 (A=003, B=139)
+Fout=1780.00 (A=004, B=139)
+Fout=1780.20 (A=005, B=139)
+Fout=1780.40 (A=006, B=139)
+Fout=1780.60 (A=007, B=139)
+Fout=1780.80 (A=008, B=139)
+Fout=1781.00 (A=009, B=139)
+Fout=1781.20 (A=010, B=139)
+Fout=1781.40 (A=011, B=139)
+Fout=1781.60 (A=012, B=139)
+Fout=1781.80 (A=013, B=139)
+Fout=1782.00 (A=014, B=139)
+Fout=1782.20 (A=015, B=139)
+Fout=1782.40 (A=016, B=139)
+Fout=1782.60 (A=017, B=139)
+Fout=1782.80 (A=018, B=139)
+Fout=1783.00 (A=019, B=139)
+Fout=1783.20 (A=020, B=139)
+Fout=1783.40 (A=021, B=139)
+Fout=1783.60 (A=022, B=139)
+Fout=1783.80 (A=023, B=139)
+Fout=1784.00 (A=024, B=139)
+Fout=1784.20 (A=025, B=139)
+Fout=1784.40 (A=026, B=139)
+Fout=1784.60 (A=027, B=139)
+Fout=1784.80 (A=028, B=139)
+Fout=1785.00 (A=029, B=139)
+Fout=1785.20 (A=030, B=139)
+Fout=1785.40 (A=031, B=139)
+Fout=1785.60 (A=032, B=139)
+Fout=1785.80 (A=033, B=139)
+Fout=1786.00 (A=034, B=139)
+Fout=1786.20 (A=035, B=139)
+Fout=1786.40 (A=036, B=139)
+Fout=1786.60 (A=037, B=139)
+Fout=1786.80 (A=038, B=139)
+Fout=1787.00 (A=039, B=139)
+Fout=1787.20 (A=040, B=139)
+Fout=1787.40 (A=041, B=139)
+Fout=1787.60 (A=042, B=139)
+Fout=1787.80 (A=043, B=139)
+Fout=1788.00 (A=044, B=139)
+Fout=1788.20 (A=045, B=139)
+Fout=1788.40 (A=046, B=139)
+Fout=1788.60 (A=047, B=139)
+Fout=1788.80 (A=048, B=139)
+Fout=1789.00 (A=049, B=139)
+Fout=1789.20 (A=050, B=139)
+Fout=1789.40 (A=051, B=139)
+Fout=1789.60 (A=052, B=139)
+Fout=1789.80 (A=053, B=139)
+Fout=1790.00 (A=054, B=139)
+Fout=1790.20 (A=055, B=139)
+Fout=1790.40 (A=056, B=139)
+Fout=1790.60 (A=057, B=139)
+Fout=1790.80 (A=058, B=139)
+Fout=1791.00 (A=059, B=139)
+Fout=1791.20 (A=060, B=139)
+Fout=1791.40 (A=061, B=139)
+Fout=1791.60 (A=062, B=139)
+Fout=1791.80 (A=063, B=139)
+Fout=1792.00 (A=000, B=140)
+Fout=1792.20 (A=001, B=140)
+Fout=1792.40 (A=002, B=140)
+Fout=1792.60 (A=003, B=140)
+Fout=1792.80 (A=004, B=140)
+Fout=1793.00 (A=005, B=140)
+Fout=1793.20 (A=006, B=140)
+Fout=1793.40 (A=007, B=140)
+Fout=1793.60 (A=008, B=140)
+Fout=1793.80 (A=009, B=140)
+Fout=1794.00 (A=010, B=140)
+Fout=1794.20 (A=011, B=140)
+Fout=1794.40 (A=012, B=140)
+Fout=1794.60 (A=013, B=140)
+Fout=1794.80 (A=014, B=140)
+Fout=1795.00 (A=015, B=140)
+Fout=1795.20 (A=016, B=140)
+Fout=1795.40 (A=017, B=140)
+Fout=1795.60 (A=018, B=140)
+Fout=1795.80 (A=019, B=140)
+Fout=1796.00 (A=020, B=140)
+Fout=1796.20 (A=021, B=140)
+Fout=1796.40 (A=022, B=140)
+Fout=1796.60 (A=023, B=140)
+Fout=1796.80 (A=024, B=140)
+Fout=1797.00 (A=025, B=140)
+Fout=1797.20 (A=026, B=140)
+Fout=1797.40 (A=027, B=140)
+Fout=1797.60 (A=028, B=140)
+Fout=1797.80 (A=029, B=140)
+Fout=1798.00 (A=030, B=140)
+Fout=1798.20 (A=031, B=140)
+Fout=1798.40 (A=032, B=140)
+Fout=1798.60 (A=033, B=140)
+Fout=1798.80 (A=034, B=140)
+Fout=1799.00 (A=035, B=140)
+Fout=1799.20 (A=036, B=140)
+Fout=1799.40 (A=037, B=140)
+Fout=1799.60 (A=038, B=140)
+Fout=1799.80 (A=039, B=140)
+Fout=1800.00 (A=040, B=140)
+Fout=1800.20 (A=041, B=140)
+Fout=1800.40 (A=042, B=140)
+Fout=1800.60 (A=043, B=140)
+Fout=1800.80 (A=044, B=140)
+Fout=1801.00 (A=045, B=140)
+Fout=1801.20 (A=046, B=140)
+Fout=1801.40 (A=047, B=140)
+Fout=1801.60 (A=048, B=140)
+Fout=1801.80 (A=049, B=140)
+Fout=1802.00 (A=050, B=140)
+Fout=1802.20 (A=051, B=140)
+Fout=1802.40 (A=052, B=140)
+Fout=1802.60 (A=053, B=140)
+Fout=1802.80 (A=054, B=140)
+Fout=1803.00 (A=055, B=140)
+Fout=1803.20 (A=056, B=140)
+Fout=1803.40 (A=057, B=140)
+Fout=1803.60 (A=058, B=140)
+Fout=1803.80 (A=059, B=140)
+Fout=1804.00 (A=060, B=140)
+Fout=1804.20 (A=061, B=140)
+Fout=1804.40 (A=062, B=140)
+Fout=1804.60 (A=063, B=140)
+Fout=1804.80 (A=000, B=141)
+Fout=1805.00 (A=001, B=141)
+Fout=1805.20 (A=002, B=141)
+Fout=1805.40 (A=003, B=141)
+Fout=1805.60 (A=004, B=141)
+Fout=1805.80 (A=005, B=141)
+Fout=1806.00 (A=006, B=141)
+Fout=1806.20 (A=007, B=141)
+Fout=1806.40 (A=008, B=141)
+Fout=1806.60 (A=009, B=141)
+Fout=1806.80 (A=010, B=141)
+Fout=1807.00 (A=011, B=141)
+Fout=1807.20 (A=012, B=141)
+Fout=1807.40 (A=013, B=141)
+Fout=1807.60 (A=014, B=141)
+Fout=1807.80 (A=015, B=141)
+Fout=1808.00 (A=016, B=141)
+Fout=1808.20 (A=017, B=141)
+Fout=1808.40 (A=018, B=141)
+Fout=1808.60 (A=019, B=141)
+Fout=1808.80 (A=020, B=141)
+Fout=1809.00 (A=021, B=141)
+Fout=1809.20 (A=022, B=141)
+Fout=1809.40 (A=023, B=141)
+Fout=1809.60 (A=024, B=141)
+Fout=1809.80 (A=025, B=141)
+Fout=1810.00 (A=026, B=141)
+Fout=1810.20 (A=027, B=141)
+Fout=1810.40 (A=028, B=141)
+Fout=1810.60 (A=029, B=141)
+Fout=1810.80 (A=030, B=141)
+Fout=1811.00 (A=031, B=141)
+Fout=1811.20 (A=032, B=141)
+Fout=1811.40 (A=033, B=141)
+Fout=1811.60 (A=034, B=141)
+Fout=1811.80 (A=035, B=141)
+Fout=1812.00 (A=036, B=141)
+Fout=1812.20 (A=037, B=141)
+Fout=1812.40 (A=038, B=141)
+Fout=1812.60 (A=039, B=141)
+Fout=1812.80 (A=040, B=141)
+Fout=1813.00 (A=041, B=141)
+Fout=1813.20 (A=042, B=141)
+Fout=1813.40 (A=043, B=141)
+Fout=1813.60 (A=044, B=141)
+Fout=1813.80 (A=045, B=141)
+Fout=1814.00 (A=046, B=141)
+Fout=1814.20 (A=047, B=141)
+Fout=1814.40 (A=048, B=141)
+Fout=1814.60 (A=049, B=141)
+Fout=1814.80 (A=050, B=141)
+Fout=1815.00 (A=051, B=141)
+Fout=1815.20 (A=052, B=141)
+Fout=1815.40 (A=053, B=141)
+Fout=1815.60 (A=054, B=141)
+Fout=1815.80 (A=055, B=141)
+Fout=1816.00 (A=056, B=141)
+Fout=1816.20 (A=057, B=141)
+Fout=1816.40 (A=058, B=141)
+Fout=1816.60 (A=059, B=141)
+Fout=1816.80 (A=060, B=141)
+Fout=1817.00 (A=061, B=141)
+Fout=1817.20 (A=062, B=141)
+Fout=1817.40 (A=063, B=141)
+Fout=1817.60 (A=000, B=142)
+Fout=1817.80 (A=001, B=142)
+Fout=1818.00 (A=002, B=142)
+Fout=1818.20 (A=003, B=142)
+Fout=1818.40 (A=004, B=142)
+Fout=1818.60 (A=005, B=142)
+Fout=1818.80 (A=006, B=142)
+Fout=1819.00 (A=007, B=142)
+Fout=1819.20 (A=008, B=142)
+Fout=1819.40 (A=009, B=142)
+Fout=1819.60 (A=010, B=142)
+Fout=1819.80 (A=011, B=142)
+Fout=1820.00 (A=012, B=142)
+Fout=1820.20 (A=013, B=142)
+Fout=1820.40 (A=014, B=142)
+Fout=1820.60 (A=015, B=142)
+Fout=1820.80 (A=016, B=142)
+Fout=1821.00 (A=017, B=142)
+Fout=1821.20 (A=018, B=142)
+Fout=1821.40 (A=019, B=142)
+Fout=1821.60 (A=020, B=142)
+Fout=1821.80 (A=021, B=142)
+Fout=1822.00 (A=022, B=142)
+Fout=1822.20 (A=023, B=142)
+Fout=1822.40 (A=024, B=142)
+Fout=1822.60 (A=025, B=142)
+Fout=1822.80 (A=026, B=142)
+Fout=1823.00 (A=027, B=142)
+Fout=1823.20 (A=028, B=142)
+Fout=1823.40 (A=029, B=142)
+Fout=1823.60 (A=030, B=142)
+Fout=1823.80 (A=031, B=142)
+Fout=1824.00 (A=032, B=142)
+Fout=1824.20 (A=033, B=142)
+Fout=1824.40 (A=034, B=142)
+Fout=1824.60 (A=035, B=142)
+Fout=1824.80 (A=036, B=142)
+Fout=1825.00 (A=037, B=142)
+Fout=1825.20 (A=038, B=142)
+Fout=1825.40 (A=039, B=142)
+Fout=1825.60 (A=040, B=142)
+Fout=1825.80 (A=041, B=142)
+Fout=1826.00 (A=042, B=142)
+Fout=1826.20 (A=043, B=142)
+Fout=1826.40 (A=044, B=142)
+Fout=1826.60 (A=045, B=142)
+Fout=1826.80 (A=046, B=142)
+Fout=1827.00 (A=047, B=142)
+Fout=1827.20 (A=048, B=142)
+Fout=1827.40 (A=049, B=142)
+Fout=1827.60 (A=050, B=142)
+Fout=1827.80 (A=051, B=142)
+Fout=1828.00 (A=052, B=142)
+Fout=1828.20 (A=053, B=142)
+Fout=1828.40 (A=054, B=142)
+Fout=1828.60 (A=055, B=142)
+Fout=1828.80 (A=056, B=142)
+Fout=1829.00 (A=057, B=142)
+Fout=1829.20 (A=058, B=142)
+Fout=1829.40 (A=059, B=142)
+Fout=1829.60 (A=060, B=142)
+Fout=1829.80 (A=061, B=142)
+Fout=1830.00 (A=062, B=142)
+Fout=1830.20 (A=063, B=142)
+Fout=1830.40 (A=000, B=143)
+Fout=1830.60 (A=001, B=143)
+Fout=1830.80 (A=002, B=143)
+Fout=1831.00 (A=003, B=143)
+Fout=1831.20 (A=004, B=143)
+Fout=1831.40 (A=005, B=143)
+Fout=1831.60 (A=006, B=143)
+Fout=1831.80 (A=007, B=143)
+Fout=1832.00 (A=008, B=143)
+Fout=1832.20 (A=009, B=143)
+Fout=1832.40 (A=010, B=143)
+Fout=1832.60 (A=011, B=143)
+Fout=1832.80 (A=012, B=143)
+Fout=1833.00 (A=013, B=143)
+Fout=1833.20 (A=014, B=143)
+Fout=1833.40 (A=015, B=143)
+Fout=1833.60 (A=016, B=143)
+Fout=1833.80 (A=017, B=143)
+Fout=1834.00 (A=018, B=143)
+Fout=1834.20 (A=019, B=143)
+Fout=1834.40 (A=020, B=143)
+Fout=1834.60 (A=021, B=143)
+Fout=1834.80 (A=022, B=143)
+Fout=1835.00 (A=023, B=143)
+Fout=1835.20 (A=024, B=143)
+Fout=1835.40 (A=025, B=143)
+Fout=1835.60 (A=026, B=143)
+Fout=1835.80 (A=027, B=143)
+Fout=1836.00 (A=028, B=143)
+Fout=1836.20 (A=029, B=143)
+Fout=1836.40 (A=030, B=143)
+Fout=1836.60 (A=031, B=143)
+Fout=1836.80 (A=032, B=143)
+Fout=1837.00 (A=033, B=143)
+Fout=1837.20 (A=034, B=143)
+Fout=1837.40 (A=035, B=143)
+Fout=1837.60 (A=036, B=143)
+Fout=1837.80 (A=037, B=143)
+Fout=1838.00 (A=038, B=143)
+Fout=1838.20 (A=039, B=143)
+Fout=1838.40 (A=040, B=143)
+Fout=1838.60 (A=041, B=143)
+Fout=1838.80 (A=042, B=143)
+Fout=1839.00 (A=043, B=143)
+Fout=1839.20 (A=044, B=143)
+Fout=1839.40 (A=045, B=143)
+Fout=1839.60 (A=046, B=143)
+Fout=1839.80 (A=047, B=143)
+Fout=1840.00 (A=048, B=143)
+Fout=1840.20 (A=049, B=143)
+Fout=1840.40 (A=050, B=143)
+Fout=1840.60 (A=051, B=143)
+Fout=1840.80 (A=052, B=143)
+Fout=1841.00 (A=053, B=143)
+Fout=1841.20 (A=054, B=143)
+Fout=1841.40 (A=055, B=143)
+Fout=1841.60 (A=056, B=143)
+Fout=1841.80 (A=057, B=143)
+Fout=1842.00 (A=058, B=143)
+Fout=1842.20 (A=059, B=143)
+Fout=1842.40 (A=060, B=143)
+Fout=1842.60 (A=061, B=143)
+Fout=1842.80 (A=062, B=143)
+Fout=1843.00 (A=063, B=143)
+Fout=1843.20 (A=000, B=144)
+Fout=1843.40 (A=001, B=144)
+Fout=1843.60 (A=002, B=144)
+Fout=1843.80 (A=003, B=144)
+Fout=1844.00 (A=004, B=144)
+Fout=1844.20 (A=005, B=144)
+Fout=1844.40 (A=006, B=144)
+Fout=1844.60 (A=007, B=144)
+Fout=1844.80 (A=008, B=144)
+Fout=1845.00 (A=009, B=144)
+Fout=1845.20 (A=010, B=144)
+Fout=1845.40 (A=011, B=144)
+Fout=1845.60 (A=012, B=144)
+Fout=1845.80 (A=013, B=144)
+Fout=1846.00 (A=014, B=144)
+Fout=1846.20 (A=015, B=144)
+Fout=1846.40 (A=016, B=144)
+Fout=1846.60 (A=017, B=144)
+Fout=1846.80 (A=018, B=144)
+Fout=1847.00 (A=019, B=144)
+Fout=1847.20 (A=020, B=144)
+Fout=1847.40 (A=021, B=144)
+Fout=1847.60 (A=022, B=144)
+Fout=1847.80 (A=023, B=144)
+Fout=1848.00 (A=024, B=144)
+Fout=1848.20 (A=025, B=144)
+Fout=1848.40 (A=026, B=144)
+Fout=1848.60 (A=027, B=144)
+Fout=1848.80 (A=028, B=144)
+Fout=1849.00 (A=029, B=144)
+Fout=1849.20 (A=030, B=144)
+Fout=1849.40 (A=031, B=144)
+Fout=1849.60 (A=032, B=144)
+Fout=1849.80 (A=033, B=144)
+Fout=1850.00 (A=034, B=144)
+Fout=1850.20 (A=035, B=144)
+Fout=1850.40 (A=036, B=144)
+Fout=1850.60 (A=037, B=144)
+Fout=1850.80 (A=038, B=144)
+Fout=1851.00 (A=039, B=144)
+Fout=1851.20 (A=040, B=144)
+Fout=1851.40 (A=041, B=144)
+Fout=1851.60 (A=042, B=144)
+Fout=1851.80 (A=043, B=144)
+Fout=1852.00 (A=044, B=144)
+Fout=1852.20 (A=045, B=144)
+Fout=1852.40 (A=046, B=144)
+Fout=1852.60 (A=047, B=144)
+Fout=1852.80 (A=048, B=144)
+Fout=1853.00 (A=049, B=144)
+Fout=1853.20 (A=050, B=144)
+Fout=1853.40 (A=051, B=144)
+Fout=1853.60 (A=052, B=144)
+Fout=1853.80 (A=053, B=144)
+Fout=1854.00 (A=054, B=144)
+Fout=1854.20 (A=055, B=144)
+Fout=1854.40 (A=056, B=144)
+Fout=1854.60 (A=057, B=144)
+Fout=1854.80 (A=058, B=144)
+Fout=1855.00 (A=059, B=144)
+Fout=1855.20 (A=060, B=144)
+Fout=1855.40 (A=061, B=144)
+Fout=1855.60 (A=062, B=144)
+Fout=1855.80 (A=063, B=144)
+Fout=1856.00 (A=000, B=145)
+Fout=1856.20 (A=001, B=145)
+Fout=1856.40 (A=002, B=145)
+Fout=1856.60 (A=003, B=145)
+Fout=1856.80 (A=004, B=145)
+Fout=1857.00 (A=005, B=145)
+Fout=1857.20 (A=006, B=145)
+Fout=1857.40 (A=007, B=145)
+Fout=1857.60 (A=008, B=145)
+Fout=1857.80 (A=009, B=145)
+Fout=1858.00 (A=010, B=145)
+Fout=1858.20 (A=011, B=145)
+Fout=1858.40 (A=012, B=145)
+Fout=1858.60 (A=013, B=145)
+Fout=1858.80 (A=014, B=145)
+Fout=1859.00 (A=015, B=145)
+Fout=1859.20 (A=016, B=145)
+Fout=1859.40 (A=017, B=145)
+Fout=1859.60 (A=018, B=145)
+Fout=1859.80 (A=019, B=145)
+Fout=1860.00 (A=020, B=145)
+Fout=1860.20 (A=021, B=145)
+Fout=1860.40 (A=022, B=145)
+Fout=1860.60 (A=023, B=145)
+Fout=1860.80 (A=024, B=145)
+Fout=1861.00 (A=025, B=145)
+Fout=1861.20 (A=026, B=145)
+Fout=1861.40 (A=027, B=145)
+Fout=1861.60 (A=028, B=145)
+Fout=1861.80 (A=029, B=145)
+Fout=1862.00 (A=030, B=145)
+Fout=1862.20 (A=031, B=145)
+Fout=1862.40 (A=032, B=145)
+Fout=1862.60 (A=033, B=145)
+Fout=1862.80 (A=034, B=145)
+Fout=1863.00 (A=035, B=145)
+Fout=1863.20 (A=036, B=145)
+Fout=1863.40 (A=037, B=145)
+Fout=1863.60 (A=038, B=145)
+Fout=1863.80 (A=039, B=145)
+Fout=1864.00 (A=040, B=145)
+Fout=1864.20 (A=041, B=145)
+Fout=1864.40 (A=042, B=145)
+Fout=1864.60 (A=043, B=145)
+Fout=1864.80 (A=044, B=145)
+Fout=1865.00 (A=045, B=145)
+Fout=1865.20 (A=046, B=145)
+Fout=1865.40 (A=047, B=145)
+Fout=1865.60 (A=048, B=145)
+Fout=1865.80 (A=049, B=145)
+Fout=1866.00 (A=050, B=145)
+Fout=1866.20 (A=051, B=145)
+Fout=1866.40 (A=052, B=145)
+Fout=1866.60 (A=053, B=145)
+Fout=1866.80 (A=054, B=145)
+Fout=1867.00 (A=055, B=145)
+Fout=1867.20 (A=056, B=145)
+Fout=1867.40 (A=057, B=145)
+Fout=1867.60 (A=058, B=145)
+Fout=1867.80 (A=059, B=145)
+Fout=1868.00 (A=060, B=145)
+Fout=1868.20 (A=061, B=145)
+Fout=1868.40 (A=062, B=145)
+Fout=1868.60 (A=063, B=145)
+Fout=1868.80 (A=000, B=146)
+Fout=1869.00 (A=001, B=146)
+Fout=1869.20 (A=002, B=146)
+Fout=1869.40 (A=003, B=146)
+Fout=1869.60 (A=004, B=146)
+Fout=1869.80 (A=005, B=146)
+Fout=1870.00 (A=006, B=146)
+Fout=1870.20 (A=007, B=146)
+Fout=1870.40 (A=008, B=146)
+Fout=1870.60 (A=009, B=146)
+Fout=1870.80 (A=010, B=146)
+Fout=1871.00 (A=011, B=146)
+Fout=1871.20 (A=012, B=146)
+Fout=1871.40 (A=013, B=146)
+Fout=1871.60 (A=014, B=146)
+Fout=1871.80 (A=015, B=146)
+Fout=1872.00 (A=016, B=146)
+Fout=1872.20 (A=017, B=146)
+Fout=1872.40 (A=018, B=146)
+Fout=1872.60 (A=019, B=146)
+Fout=1872.80 (A=020, B=146)
+Fout=1873.00 (A=021, B=146)
+Fout=1873.20 (A=022, B=146)
+Fout=1873.40 (A=023, B=146)
+Fout=1873.60 (A=024, B=146)
+Fout=1873.80 (A=025, B=146)
+Fout=1874.00 (A=026, B=146)
+Fout=1874.20 (A=027, B=146)
+Fout=1874.40 (A=028, B=146)
+Fout=1874.60 (A=029, B=146)
+Fout=1874.80 (A=030, B=146)
+Fout=1875.00 (A=031, B=146)
+Fout=1875.20 (A=032, B=146)
+Fout=1875.40 (A=033, B=146)
+Fout=1875.60 (A=034, B=146)
+Fout=1875.80 (A=035, B=146)
+Fout=1876.00 (A=036, B=146)
+Fout=1876.20 (A=037, B=146)
+Fout=1876.40 (A=038, B=146)
+Fout=1876.60 (A=039, B=146)
+Fout=1876.80 (A=040, B=146)
+Fout=1877.00 (A=041, B=146)
+Fout=1877.20 (A=042, B=146)
+Fout=1877.40 (A=043, B=146)
+Fout=1877.60 (A=044, B=146)
+Fout=1877.80 (A=045, B=146)
+Fout=1878.00 (A=046, B=146)
+Fout=1878.20 (A=047, B=146)
+Fout=1878.40 (A=048, B=146)
+Fout=1878.60 (A=049, B=146)
+Fout=1878.80 (A=050, B=146)
+Fout=1879.00 (A=051, B=146)
+Fout=1879.20 (A=052, B=146)
+Fout=1879.40 (A=053, B=146)
+Fout=1879.60 (A=054, B=146)
+Fout=1879.80 (A=055, B=146)
+Fout=1880.00 (A=056, B=146)
+Fout=1880.20 (A=057, B=146)
+Fout=1880.40 (A=058, B=146)
+Fout=1880.60 (A=059, B=146)
+Fout=1880.80 (A=060, B=146)
+Fout=1881.00 (A=061, B=146)
+Fout=1881.20 (A=062, B=146)
+Fout=1881.40 (A=063, B=146)
+Fout=1881.60 (A=000, B=147)
+Fout=1881.80 (A=001, B=147)
+Fout=1882.00 (A=002, B=147)
+Fout=1882.20 (A=003, B=147)
+Fout=1882.40 (A=004, B=147)
+Fout=1882.60 (A=005, B=147)
+Fout=1882.80 (A=006, B=147)
+Fout=1883.00 (A=007, B=147)
+Fout=1883.20 (A=008, B=147)
+Fout=1883.40 (A=009, B=147)
+Fout=1883.60 (A=010, B=147)
+Fout=1883.80 (A=011, B=147)
+Fout=1884.00 (A=012, B=147)
+Fout=1884.20 (A=013, B=147)
+Fout=1884.40 (A=014, B=147)
+Fout=1884.60 (A=015, B=147)
+Fout=1884.80 (A=016, B=147)
+Fout=1885.00 (A=017, B=147)
+Fout=1885.20 (A=018, B=147)
+Fout=1885.40 (A=019, B=147)
+Fout=1885.60 (A=020, B=147)
+Fout=1885.80 (A=021, B=147)
+Fout=1886.00 (A=022, B=147)
+Fout=1886.20 (A=023, B=147)
+Fout=1886.40 (A=024, B=147)
+Fout=1886.60 (A=025, B=147)
+Fout=1886.80 (A=026, B=147)
+Fout=1887.00 (A=027, B=147)
+Fout=1887.20 (A=028, B=147)
+Fout=1887.40 (A=029, B=147)
+Fout=1887.60 (A=030, B=147)
+Fout=1887.80 (A=031, B=147)
+Fout=1888.00 (A=032, B=147)
+Fout=1888.20 (A=033, B=147)
+Fout=1888.40 (A=034, B=147)
+Fout=1888.60 (A=035, B=147)
+Fout=1888.80 (A=036, B=147)
+Fout=1889.00 (A=037, B=147)
+Fout=1889.20 (A=038, B=147)
+Fout=1889.40 (A=039, B=147)
+Fout=1889.60 (A=040, B=147)
+Fout=1889.80 (A=041, B=147)
+Fout=1890.00 (A=042, B=147)
+Fout=1890.20 (A=043, B=147)
+Fout=1890.40 (A=044, B=147)
+Fout=1890.60 (A=045, B=147)
+Fout=1890.80 (A=046, B=147)
+Fout=1891.00 (A=047, B=147)
+Fout=1891.20 (A=048, B=147)
+Fout=1891.40 (A=049, B=147)
+Fout=1891.60 (A=050, B=147)
+Fout=1891.80 (A=051, B=147)
+Fout=1892.00 (A=052, B=147)
+Fout=1892.20 (A=053, B=147)
+Fout=1892.40 (A=054, B=147)
+Fout=1892.60 (A=055, B=147)
+Fout=1892.80 (A=056, B=147)
+Fout=1893.00 (A=057, B=147)
+Fout=1893.20 (A=058, B=147)
+Fout=1893.40 (A=059, B=147)
+Fout=1893.60 (A=060, B=147)
+Fout=1893.80 (A=061, B=147)
+Fout=1894.00 (A=062, B=147)
+Fout=1894.20 (A=063, B=147)
+Fout=1894.40 (A=000, B=148)
+Fout=1894.60 (A=001, B=148)
+Fout=1894.80 (A=002, B=148)
+Fout=1895.00 (A=003, B=148)
+Fout=1895.20 (A=004, B=148)
+Fout=1895.40 (A=005, B=148)
+Fout=1895.60 (A=006, B=148)
+Fout=1895.80 (A=007, B=148)
+Fout=1896.00 (A=008, B=148)
+Fout=1896.20 (A=009, B=148)
+Fout=1896.40 (A=010, B=148)
+Fout=1896.60 (A=011, B=148)
+Fout=1896.80 (A=012, B=148)
+Fout=1897.00 (A=013, B=148)
+Fout=1897.20 (A=014, B=148)
+Fout=1897.40 (A=015, B=148)
+Fout=1897.60 (A=016, B=148)
+Fout=1897.80 (A=017, B=148)
+Fout=1898.00 (A=018, B=148)
+Fout=1898.20 (A=019, B=148)
+Fout=1898.40 (A=020, B=148)
+Fout=1898.60 (A=021, B=148)
+Fout=1898.80 (A=022, B=148)
+Fout=1899.00 (A=023, B=148)
+Fout=1899.20 (A=024, B=148)
+Fout=1899.40 (A=025, B=148)
+Fout=1899.60 (A=026, B=148)
+Fout=1899.80 (A=027, B=148)
+Fout=1900.00 (A=028, B=148)
+Fout=1900.20 (A=029, B=148)
+Fout=1900.40 (A=030, B=148)
+Fout=1900.60 (A=031, B=148)
+Fout=1900.80 (A=032, B=148)
+Fout=1901.00 (A=033, B=148)
+Fout=1901.20 (A=034, B=148)
+Fout=1901.40 (A=035, B=148)
+Fout=1901.60 (A=036, B=148)
+Fout=1901.80 (A=037, B=148)
+Fout=1902.00 (A=038, B=148)
+Fout=1902.20 (A=039, B=148)
+Fout=1902.40 (A=040, B=148)
+Fout=1902.60 (A=041, B=148)
+Fout=1902.80 (A=042, B=148)
+Fout=1903.00 (A=043, B=148)
+Fout=1903.20 (A=044, B=148)
+Fout=1903.40 (A=045, B=148)
+Fout=1903.60 (A=046, B=148)
+Fout=1903.80 (A=047, B=148)
+Fout=1904.00 (A=048, B=148)
+Fout=1904.20 (A=049, B=148)
+Fout=1904.40 (A=050, B=148)
+Fout=1904.60 (A=051, B=148)
+Fout=1904.80 (A=052, B=148)
+Fout=1905.00 (A=053, B=148)
+Fout=1905.20 (A=054, B=148)
+Fout=1905.40 (A=055, B=148)
+Fout=1905.60 (A=056, B=148)
+Fout=1905.80 (A=057, B=148)
+Fout=1906.00 (A=058, B=148)
+Fout=1906.20 (A=059, B=148)
+Fout=1906.40 (A=060, B=148)
+Fout=1906.60 (A=061, B=148)
+Fout=1906.80 (A=062, B=148)
+Fout=1907.00 (A=063, B=148)
+Fout=1907.20 (A=000, B=149)
+Fout=1907.40 (A=001, B=149)
+Fout=1907.60 (A=002, B=149)
+Fout=1907.80 (A=003, B=149)
+Fout=1908.00 (A=004, B=149)
+Fout=1908.20 (A=005, B=149)
+Fout=1908.40 (A=006, B=149)
+Fout=1908.60 (A=007, B=149)
+Fout=1908.80 (A=008, B=149)
+Fout=1909.00 (A=009, B=149)
+Fout=1909.20 (A=010, B=149)
+Fout=1909.40 (A=011, B=149)
+Fout=1909.60 (A=012, B=149)
+Fout=1909.80 (A=013, B=149)
+Fout=1910.00 (A=014, B=149)
+Fout=1910.20 (A=015, B=149)
+Fout=1910.40 (A=016, B=149)
+Fout=1910.60 (A=017, B=149)
+Fout=1910.80 (A=018, B=149)
+Fout=1911.00 (A=019, B=149)
+Fout=1911.20 (A=020, B=149)
+Fout=1911.40 (A=021, B=149)
+Fout=1911.60 (A=022, B=149)
+Fout=1911.80 (A=023, B=149)
+Fout=1912.00 (A=024, B=149)
+Fout=1912.20 (A=025, B=149)
+Fout=1912.40 (A=026, B=149)
+Fout=1912.60 (A=027, B=149)
+Fout=1912.80 (A=028, B=149)
+Fout=1913.00 (A=029, B=149)
+Fout=1913.20 (A=030, B=149)
+Fout=1913.40 (A=031, B=149)
+Fout=1913.60 (A=032, B=149)
+Fout=1913.80 (A=033, B=149)
+Fout=1914.00 (A=034, B=149)
+Fout=1914.20 (A=035, B=149)
+Fout=1914.40 (A=036, B=149)
+Fout=1914.60 (A=037, B=149)
+Fout=1914.80 (A=038, B=149)
+Fout=1915.00 (A=039, B=149)
+Fout=1915.20 (A=040, B=149)
+Fout=1915.40 (A=041, B=149)
+Fout=1915.60 (A=042, B=149)
+Fout=1915.80 (A=043, B=149)
+Fout=1916.00 (A=044, B=149)
+Fout=1916.20 (A=045, B=149)
+Fout=1916.40 (A=046, B=149)
+Fout=1916.60 (A=047, B=149)
+Fout=1916.80 (A=048, B=149)
+Fout=1917.00 (A=049, B=149)
+Fout=1917.20 (A=050, B=149)
+Fout=1917.40 (A=051, B=149)
+Fout=1917.60 (A=052, B=149)
+Fout=1917.80 (A=053, B=149)
+Fout=1918.00 (A=054, B=149)
+Fout=1918.20 (A=055, B=149)
+Fout=1918.40 (A=056, B=149)
+Fout=1918.60 (A=057, B=149)
+Fout=1918.80 (A=058, B=149)
+Fout=1919.00 (A=059, B=149)
+Fout=1919.20 (A=060, B=149)
+Fout=1919.40 (A=061, B=149)
+Fout=1919.60 (A=062, B=149)
+Fout=1919.80 (A=063, B=149)
diff --git a/src/host/rita_pll/rita_pll_notes.txt b/src/host/rita_pll/rita_pll_notes.txt
new file mode 100644
index 00000000..8557d3ae
--- /dev/null
+++ b/src/host/rita_pll/rita_pll_notes.txt
@@ -0,0 +1,8 @@
+
+Regular Operation as per DS GSM SPEC
+
+GSM900 Tx: 870.4 ... 921.4 MHz 880.0 ... 914.8
+GSM900 Rx: 864.4 ... 966.2 MHz 925.0 ... 959.8
+
+GSM1800 Tx: 1702.4 ... 1919.8 MHz 1710.2 ... 1784.8
+GSM1800 Rx: 1804.8 ... 1996.4 MHz 1805.2 ... 1879.8
diff --git a/src/target/firmware/.gitignore b/src/target/firmware/.gitignore
new file mode 100644
index 00000000..5dff144b
--- /dev/null
+++ b/src/target/firmware/.gitignore
@@ -0,0 +1,7 @@
+*.o
+*.a
+*.lst
+*.bin
+*.elf
+*.size
+*~
diff --git a/src/target/firmware/Makefile b/src/target/firmware/Makefile
new file mode 100644
index 00000000..0e5ff2cc
--- /dev/null
+++ b/src/target/firmware/Makefile
@@ -0,0 +1,69 @@
+INCLUDES=-Iinclude/ -I../../../include
+-include Makefile.inc
+
+# individual list of object files, they should probably become libraries
+FLASH_OBJS=flash/cfi_flash.o
+DISPLAY_OBJS=display/font_r8x8.o display/st7558.o
+ABB_OBJS=abb/twl3025.o
+RF_OBJS=rf/trf6151.o
+BOARD_C123_OBJS=board/common/rffe_compal_dualband.o board/compal_e88/init.o
+START=board/common/compal_ramload_start.S
+LDS=board/common/compal_ramload.lds
+
+# The objects that we want to link with every application
+OBJS=start.o $(ABB_OBJS) $(RF_OBJS) $(DISPLAY_OBJS) $(FLASH_OBJS) $(BOARD_C123_OBJS)
+
+# The libraries that we want to link with every application
+LIBS=calypso/libcalypso.a layer1/liblayer1.a lib/libmini.a comm/libcomm.a
+
+# The list of applications we ant to build. Please add your apps here!
+APPS=hello_world l1test compal_dump compal_dsp_dump layer1
+
+APP_BINS=$(APPS:=.bin)
+APP_ELFS=$(APPS:=.elf)
+APP_OBJS=$(patsubst %,apps/%/main.o, $(APPS))
+APP_SIZES=$(APP_ELFS:.elf=.size)
+
+LST=$(OBJS:.o=.lst) $(APP_OBJS:.o=.lst) $(START:.S=.lst)
+
+all: $(APP_BINS) $(APP_ELFS) $(APP_SIZES)
+
+start.o: $(START)
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
+
+%.o: %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
+
+%.elf: $(OBJS) apps/%/main.o $(LIBS)
+ $(CROSS_COMPILE)$(LD) $(LDFLAGS) -T $(LDS) -Bstatic -Map $@.map -o $@ --start-group $^ --end-group
+ $(CROSS_COMPILE)$(SIZE) $@
+
+%.size: %.elf
+ $(CROSS_COMPILE)$(SIZE) -A $^ > $@
+
+%.bin: %.elf
+ $(CROSS_COMPILE)objcopy --gap-fill=0xff -O binary $^ $@
+
+# FIXME: we don't do dependencies into the subdirectories, so we always rebuild
+.PHONY: calypso/libcalypso.a
+calypso/libcalypso.a:
+ make -C calypso all
+
+# FIXME: we don't do dependencies into the subdirectories, so we always rebuild
+.PHONY: layer1/liblayer1.a
+layer1/liblayer1.a:
+ make -C layer1 all
+
+lib/libmini.a:
+ make -C lib all
+
+# FIXME: we don't do dependencies into the subdirectories, so we always rebuild
+.PHONY: comm/libcomm.a
+comm/libcomm.a:
+ make -C comm all
+clean:
+ make -C calypso clean
+ make -C layer1 clean
+ make -C lib clean
+ make -C comm clean
+ rm -f *.map $(OBJS) $(APP_BINS) $(APP_ELFS) $(APP_SIZES) $(LST)
diff --git a/src/target/firmware/Makefile.inc b/src/target/firmware/Makefile.inc
new file mode 100644
index 00000000..f3f19478
--- /dev/null
+++ b/src/target/firmware/Makefile.inc
@@ -0,0 +1,19 @@
+CROSS_COMPILE?=arm-elf-
+CC=gcc
+LD=ld
+SIZE=size
+OBJCOPY=objcopy
+
+DEBUGF=dwarf-2
+
+CFLAGS=-mcpu=arm7tdmi $(INCLUDES)
+CFLAGS += -Wall -Wextra -Wcast-align -Wimplicit -Wunused
+CFLAGS += -Wswitch -Wredundant-decls -Wreturn-type -Wshadow -Wnested-externs
+CFLAGS += -Wbad-function-cast -Wsign-compare -Waggregate-return
+CFLAGS += -Wa,-adhlns=$(subst $(suffix $<),.lst,$<)
+CFLAGS += -Os -ffunction-sections
+CFLAGS += -g$(DEBUGF)
+
+ASFLAGS=-Wa,-adhlns=$(<:.S=.lst),--g$(DEBUGF) $(INCLUDES) -D__ASSEMBLY__
+
+LDFLAGS = -nostartfiles -nostdlib -nodefaultlibs --gc-sections #-Wl,-Map=$(TARGET).map,--cref
diff --git a/src/target/firmware/abb/twl3025.c b/src/target/firmware/abb/twl3025.c
new file mode 100644
index 00000000..bce6cc6d
--- /dev/null
+++ b/src/target/firmware/abb/twl3025.c
@@ -0,0 +1,291 @@
+/* Driver for Analog Baseband Circuit (TWL3025) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <spi.h>
+#include <calypso/irq.h>
+#include <calypso/tsp.h>
+#include <calypso/tpu.h>
+#include <abb/twl3025.h>
+
+/* TWL3025 */
+#define REG_PAGE(n) (n >> 7)
+#define REG_ADDR(n) (n & 0x3f)
+
+#define TWL3025_DEV_IDX 0 /* On the SPI bus */
+#define TWL3025_TSP_DEV_IDX 0 /* On the TSP bus */
+
+struct twl3025 {
+ uint8_t page;
+};
+static struct twl3025 twl3025_state;
+
+/* Switch the register page of the TWL3025 */
+static void twl3025_switch_page(uint8_t page)
+{
+ if (page == 0)
+ twl3025_reg_write(PAGEREG, 1 << 0);
+ else
+ twl3025_reg_write(PAGEREG, 1 << 1);
+
+ twl3025_state.page = page;
+}
+
+static void handle_charger(void)
+{
+ uint16_t status;
+ printd("handle_charger();");
+
+ status = twl3025_reg_read(VRPCSTS);
+// printd("\nvrpcsts: 0x%02x", status);
+
+ if (status & 0x40) {
+ printd(" inserted\n");
+ } else {
+ printd(" removed\n");
+ }
+
+// twl3025_dump_madc();
+}
+
+static void handle_adc_done(void)
+{
+ printd("handle_adc_done();");
+}
+
+static void twl3025_irq(enum irq_nr nr)
+{
+ uint16_t src;
+ printd("twl3025_irq: 0x%02x\n",nr);
+ switch (nr){
+ case IRQ_EXTERNAL: // charger in/out, pwrbtn, adc done
+ src = twl3025_reg_read(ITSTATREG);
+// printd("itstatreg 0x%02x\n", src);
+ if (src & 0x08)
+ handle_charger();
+ if (src & 0x20)
+ handle_adc_done();
+ break;
+ case IRQ_EXTERNAL_FIQ: // vcc <2.8V emergency power off
+ puts("\nBROWNOUT!1!");
+ twl3025_power_off();
+ break;
+ default:
+ return;
+ }
+}
+
+void twl3025_init(void)
+{
+ spi_init();
+ twl3025_switch_page(0);
+ twl3025_clk13m(1);
+ twl3025_reg_write(AFCCTLADD, 0x01); /* AFCCK(1:0) must not be zero! */
+ twl3025_unit_enable(TWL3025_UNIT_AFC, 1);
+
+ irq_register_handler(IRQ_EXTERNAL, &twl3025_irq);
+ irq_config(IRQ_EXTERNAL, 0, 0, 0);
+ irq_enable(IRQ_EXTERNAL);
+
+ irq_register_handler(IRQ_EXTERNAL_FIQ, &twl3025_irq);
+ irq_config(IRQ_EXTERNAL_FIQ, 1, 0, 0);
+ irq_enable(IRQ_EXTERNAL_FIQ);
+}
+
+void twl3025_reg_write(uint8_t reg, uint16_t data)
+{
+ uint16_t tx;
+
+ printd("tw3025_reg_write(%u,%u)=0x%04x\n", REG_PAGE(reg),
+ REG_ADDR(reg), data);
+
+ if (reg != PAGEREG && REG_PAGE(reg) != twl3025_state.page)
+ twl3025_switch_page(REG_PAGE(reg));
+
+ tx = ((data & 0x3ff) << 6) | (REG_ADDR(reg) << 1);
+
+ spi_xfer(TWL3025_DEV_IDX, 16, &tx, NULL);
+}
+
+void twl3025_tsp_write(uint8_t data)
+{
+ tsp_write(TWL3025_TSP_DEV_IDX, 7, data);
+}
+
+uint16_t twl3025_reg_read(uint8_t reg)
+{
+ uint16_t tx, rx;
+
+ if (REG_PAGE(reg) != twl3025_state.page)
+ twl3025_switch_page(REG_PAGE(reg));
+
+ tx = (REG_ADDR(reg) << 1) | 1;
+
+ /* A read cycle contains two SPI transfers */
+ spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
+ delay_ms(1);
+ spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
+
+ rx >>= 6;
+
+ printd("tw3025_reg_read(%u,%u)=0x%04x\n", REG_PAGE(reg),
+ REG_ADDR(reg), rx);
+
+ return rx;
+}
+
+static void twl3025_wait_ibic_access(void)
+{
+ /* Wait 6 * 32kHz clock cycles for first IBIC access (187us + 10% = 210us) */
+ delay_ms(1);
+}
+
+void twl3025_power_off(void)
+{
+ twl3025_reg_write(VRPCDEV, 0x01);
+}
+
+void twl3025_clk13m(int enable)
+{
+ if (enable) {
+ twl3025_reg_write(TOGBR2, TOGBR2_ACTS);
+ twl3025_wait_ibic_access();
+ /* for whatever reason we need to do this twice */
+ twl3025_reg_write(TOGBR2, TOGBR2_ACTS);
+ twl3025_wait_ibic_access();
+ } else {
+ twl3025_reg_write(TOGBR2, TOGBR2_ACTR);
+ twl3025_wait_ibic_access();
+ }
+}
+
+#define TSP_DELAY 6 /* 13* Tclk6M5 = ~ 3 GSM Qbits + 3 TPU instructions */
+#define BDLON_TO_BDLCAL 6
+#define BDLCAL_DURATION 66
+#define BDLON_TO_BDLENA 7
+#define BULON_TO_BULENA 16
+
+/* Enqueue a series of TSP commands in the TPU to (de)activate the downlink path */
+void twl3025_downlink(int on, int16_t at)
+{
+ int16_t bdl_ena = at - TSP_DELAY - 6;
+
+ if (on) {
+ if (bdl_ena < 0)
+ printf("BDLENA time negative (%d)\n", bdl_ena);
+ /* FIXME: calibration should be done just before BDLENA */
+ twl3025_tsp_write(BDLON);
+ tpu_enq_wait(BDLON_TO_BDLCAL - TSP_DELAY);
+ twl3025_tsp_write(BDLON | BDLCAL);
+ tpu_enq_wait(BDLCAL_DURATION - TSP_DELAY);
+ twl3025_tsp_write(BDLON);
+ //tpu_enq_wait(BDLCAL_TO_BDLENA) this is only 3.7us == 4 qbits, i.e. less than the TSP_DELAY
+ tpu_enq_at(bdl_ena);
+ twl3025_tsp_write(BDLON | BDLENA);
+ } else {
+ tpu_enq_at(bdl_ena);
+ twl3025_tsp_write(BDLON);
+ //tpu_enq_wait(nBDLENA_TO_nBDLON) this is only 3.7us == 4 qbits, i.e. less than the TSP_DELAY
+ twl3025_tsp_write(0);
+ }
+}
+
+void twl3025_afc_set(int16_t val)
+{
+ printf("twl3025_afc_set(%d)\n", val);
+
+ if (val > 4095)
+ val = 4095;
+ else if (val <= -4096)
+ val = -4096;
+
+ /* FIXME: we currently write from the USP rather than BSP */
+ twl3025_reg_write(AUXAFC2, val >> 10);
+ twl3025_reg_write(AUXAFC1, val & 0x3ff);
+}
+
+int16_t twl3025_afc_get(void)
+{
+ int16_t val;
+
+ val = (twl3025_reg_read(AUXAFC2) & 0x7);
+ val = val << 10;
+ val = val | (twl3025_reg_read(AUXAFC1) & 0x3ff);
+
+ if (val > 4095)
+ val = -(8192 - val);
+ return val;
+}
+
+void twl3025_unit_enable(enum twl3025_unit unit, int on)
+{
+ uint16_t togbr1 = 0;
+
+ switch (unit) {
+ case TWL3025_UNIT_AFC:
+ if (on)
+ togbr1 = (1 << 7);
+ else
+ togbr1 = (1 << 6);
+ break;
+ case TWL3025_UNIT_MAD:
+ if (on)
+ togbr1 = (1 << 9);
+ else
+ togbr1 = (1 << 8);
+ break;
+ case TWL3025_UNIT_ADA:
+ if (on)
+ togbr1 = (1 << 5);
+ else
+ togbr1 = (1 << 4);
+ case TWL3025_UNIT_VDL:
+ if (on)
+ togbr1 = (1 << 3);
+ else
+ togbr1 = (1 << 2);
+ break;
+ case TWL3025_UNIT_VUL:
+ if (on)
+ togbr1 = (1 << 1);
+ else
+ togbr1 = (1 << 0);
+ break;
+ }
+ twl3025_reg_write(TOGBR1, togbr1);
+}
+
+uint8_t twl3025_afcout_get(void)
+{
+ return twl3025_reg_read(AFCOUT) & 0xff;
+}
+
+void twl3025_afcout_set(uint8_t val)
+{
+ twl3025_reg_write(AFCCTLADD, 0x05);
+ twl3025_reg_write(AFCOUT, val);
+}
diff --git a/src/target/firmware/apps/compal_dsp_dump/main.c b/src/target/firmware/apps/compal_dsp_dump/main.c
new file mode 100644
index 00000000..468db235
--- /dev/null
+++ b/src/target/firmware/apps/compal_dsp_dump/main.c
@@ -0,0 +1,78 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <abb/twl3025.h>
+#include <display/st7558.h>
+#include <rf/trf6151.h>
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+void main(void)
+{
+ int i;
+ uint16_t twl_reg;
+
+ puts("\n\nCompal DSP data dumper\n");
+ puts(hr);
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ /* Initialize basic board support */
+ board_init();
+ puts(hr);
+
+ /* Dump DSP content */
+ dsp_dump();
+
+ while (1) {}
+}
+
diff --git a/src/target/firmware/apps/compal_dump/main.c b/src/target/firmware/apps/compal_dump/main.c
new file mode 100644
index 00000000..444dfd47
--- /dev/null
+++ b/src/target/firmware/apps/compal_dump/main.c
@@ -0,0 +1,90 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <cfi_flash.h>
+#include <abb/twl3025.h>
+#include <calypso/clock.h>
+#include <calypso/timer.h>
+#include <calypso/misc.h>
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+#define KBIT 1024
+#define MBIT (1024*KBIT)
+
+#define REG_DEV_ID_CODE 0xfffef000
+#define REG_DEV_VER_CODE 0xfffef002
+#define REG_DEV_ARMVER_CODE 0xfffffe00
+#define REG_cDSP_ID_CODE 0xfffffe02
+#define REG_DIE_ID_CODE 0xfffef010
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+int main(void)
+{
+ puts("\n\nCompal device data dumper\n");
+ puts(hr);
+
+ /* Disable watchdog (for phones that have it enabled after boot) */
+ wdog_enable(0);
+
+ /* Initialize TWL3025 for power control */
+ twl3025_init();
+
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ /* Initialize flash, dumping the protection area. */
+ cfi_flash_t f;
+ flash_init(&f, 0x00000000);
+ flash_dump_info(&f);
+ puts(hr);
+
+ /* Dump flash contents */
+ printf("Dump %d kbytes of external flash\n", f.f_size/1024);
+ memdump_range((void *)0x00000000, f.f_size);
+ puts(hr);
+
+ /* Power down */
+ twl3025_power_off();
+
+ while (1) {}
+}
+
diff --git a/src/target/firmware/apps/hello_world/main.c b/src/target/firmware/apps/hello_world/main.c
new file mode 100644
index 00000000..7f6aeef9
--- /dev/null
+++ b/src/target/firmware/apps/hello_world/main.c
@@ -0,0 +1,126 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+#include <abb/twl3025.h>
+#include <display/st7558.h>
+#include <rf/trf6151.h>
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+#include <comm/sercomm.h>
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+void key_handler(enum key_codes code, enum key_states state);
+
+static void *console_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ if (dlci != SC_DLCI_CONSOLE) {
+ printf("Message for unknown DLCI %u\n", dlci);
+ return;
+ }
+
+ printf("Message on console DLCI: '%s'\n", msg->data);
+ st7558_puts(msg->data);
+ msgb_free(msg);
+}
+
+int main(void)
+{
+ board_init();
+ puts("\n\nHello World from " __FILE__ " program code\n");
+ puts(hr);
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ /* Dump clock config before PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config aftee PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ /* Dump all memory */
+ //dump_mem();
+#if 0
+ /* Dump Bootloader */
+ memdump_range((void *)0x00000000, 0x2000);
+ puts(hr);
+#endif
+
+ st7558_set_attr(DISP_ATTR_INVERT);
+ st7558_puts("Hello World");
+
+ sercomm_register_rx_cb(SC_DLCI_CONSOLE, console_rx_cb);
+
+ /* beyond this point we only react to interrupts */
+ puts("entering interrupt loop\n");
+ while (1) {
+ }
+
+ twl3025_power_off();
+
+ while (1) {}
+}
+
+void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ default:
+ break;
+ }
+}
diff --git a/src/target/firmware/apps/l1test/main.c b/src/target/firmware/apps/l1test/main.c
new file mode 100644
index 00000000..b19f72c1
--- /dev/null
+++ b/src/target/firmware/apps/l1test/main.c
@@ -0,0 +1,289 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <gsm.h>
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+
+#include <abb/twl3025.h>
+#include <display/st7558.h>
+#include <rf/trf6151.h>
+
+#include <comm/sercomm.h>
+
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+
+#include <layer1/sync.h>
+#include <layer1/tpu_window.h>
+
+#define SCAN
+
+#ifdef SCAN
+/* if scanning is enabled, scan from 0 ... 124 */
+#define BASE_ARFCN 0
+#else
+/* fixed ARFCN in GSM1800 at which Harald has his GSM test license */
+#define BASE_ARFCN 871
+#endif
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+/* Main Program */
+const char *hr = "======================================================================\n";
+
+/* Best ARFCN MAP ************************************************************/
+
+struct arfcn_map {
+ uint16_t arfcn;
+ int16_t dbm8;
+};
+
+static struct arfcn_map best_arfcn_map[10];
+static void best_arfcn_update(uint16_t arfcn, int16_t dbm8)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(best_arfcn_map); i++) {
+ if (best_arfcn_map[i].dbm8 < dbm8 ||
+ best_arfcn_map[i].dbm8 == 0) {
+ best_arfcn_map[i].dbm8 = dbm8;
+ best_arfcn_map[i].arfcn = arfcn;
+ return;
+ }
+ }
+}
+
+static void best_arfcn_dump(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(best_arfcn_map); i++) {
+ if (best_arfcn_map[i].dbm8 == 0)
+ continue;
+ printf("ARFCN %3d: %d dBm\n",
+ best_arfcn_map[i].arfcn,
+ best_arfcn_map[i].dbm8/8);
+ }
+}
+
+
+/* MAIN program **************************************************************/
+
+enum l1test_state {
+ STATE_NONE,
+ STATE_PM,
+ STATE_FB,
+};
+
+static enum l1test_state l1test_state;
+
+static void l1test_state_change(enum l1test_state new_state)
+{
+ switch (new_state) {
+ case STATE_PM:
+ puts("Performing power measurement over GSM900\n");
+ l1s_pm_test(1, BASE_ARFCN);
+ break;
+ case STATE_FB:
+ puts("Starting FCCH Recognition\n");
+ l1s_fb_test(1, 0);
+ break;
+ case STATE_NONE:
+ /* disable frame interrupts */
+ tpu_frame_irq_en(0, 0);
+ break;
+ }
+}
+
+/* completion call-back for the L1 Sync Pwer Measurement */
+static void l1s_signal_cb(struct l1_signal *sig)
+{
+ uint16_t i, next_arfcn;
+
+ switch (sig->signum) {
+ case L1_SIG_PM:
+ best_arfcn_update(sig->arfcn, sig->pm.dbm8[0]);
+ next_arfcn = sig->arfcn + 1;
+
+ if (next_arfcn >= 124) {
+ puts("ARFCN Top 10 Rx Level\n");
+ best_arfcn_dump();
+
+ trf6151_rx_window(0, best_arfcn_map[0].arfcn, 40, 0);
+ tpu_end_scenario();
+
+ /* PM phase completed, do FB det */
+ l1test_state_change(STATE_FB);
+
+ break;
+ }
+
+ /* restart Power Measurement */
+ l1s_pm_test(1, next_arfcn);
+ break;
+ case L1_SIG_NB:
+ puts("NB SNR ");
+ for (i = 0; i < 4; i++) {
+ uint16_t snr = sig->nb.meas[i].snr;
+ printf("%d.%03u ", l1s_snr_int(snr), l1s_snr_fract(snr));
+ }
+ putchar('\n');
+ printf("--> Frame %d %d 0x%04X ", sig->nb.fire, sig->nb.crc, sig->nb.num_biterr);
+ for (i = 0; i < ARRAY_SIZE(sig->nb.frame); i++)
+ printf("%02X ", sig->nb.frame[i]);
+ putchar('\n');
+ break;
+ }
+}
+
+static void key_handler(enum key_codes code, enum key_states state);
+
+int main(void)
+{
+ board_init();
+ puts("\n\nHello World from " __FILE__ " program code\n");
+
+ puts(hr);
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config aftee PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ st7558_set_attr(DISP_ATTR_INVERT);
+ st7558_puts("l1test.bin");
+
+ layer1_init();
+ l1s_set_handler(&l1s_signal_cb);
+
+ //dsp_checksum_task();
+#ifdef SCAN
+ l1test_state_change(STATE_PM);
+#else
+ l1test_state_change(STATE_FB);
+#endif
+ tpu_frame_irq_en(1, 1);
+
+ while (1) {}
+
+ /* NOT REACHED */
+
+ twl3025_power_off();
+}
+
+static int8_t vga_gain = 40;
+static int high_gain = 0;
+static int afcout = 0;
+
+static void update_vga_gain(void)
+{
+ printf("VGA Gain: %u %s\n", vga_gain, high_gain ? "HIGH" : "LOW");
+ trf6151_set_gain(vga_gain, high_gain);
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+static void tspact_toggle(uint8_t num)
+{
+ printf("TSPACT%u toggle\n", num);
+ tsp_act_toggle((1 << num));
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+static void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ case KEY_1: /* VGA gain decrement */
+ vga_gain -= 2;
+ if (vga_gain < 14)
+ vga_gain = 14;
+ update_vga_gain();
+ break;
+ case KEY_2: /* High/Low Rx gain */
+ high_gain ^= 1;
+ update_vga_gain();
+ break;
+ case KEY_3: /* VGA gain increment */
+ vga_gain += 2;
+ if (vga_gain > 40)
+ vga_gain = 40;
+ update_vga_gain();
+ break;
+ case KEY_4:
+ tspact_toggle(6); /* TRENA (RFFE) */
+ break;
+ case KEY_5:
+ tspact_toggle(8); /* GSM_TXEN (RFFE) */
+ break;
+ case KEY_6:
+ tspact_toggle(1); /* PAENA (RFFE) */
+ break;
+ case KEY_7: /* decrement AFC OUT */
+ afcout -= 100;
+ if (afcout < -4096)
+ afcout = -4096;
+ twl3025_afc_set(afcout);
+ printf("AFC OUT: %u\n", twl3025_afcout_get());
+ break;
+ case KEY_9: /* increase AFC OUT */
+ afcout += 100;
+ if (afcout > 4095)
+ afcout = 4095;
+ twl3025_afc_set(afcout);
+ printf("AFC OUT: %u\n", twl3025_afcout_get());
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/target/firmware/apps/layer1/main.c b/src/target/firmware/apps/layer1/main.c
new file mode 100644
index 00000000..3b1b686a
--- /dev/null
+++ b/src/target/firmware/apps/layer1/main.c
@@ -0,0 +1,214 @@
+/* main program of Free Software for Calypso Phone */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <gsm.h>
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <keypad.h>
+#include <board.h>
+
+#include <abb/twl3025.h>
+#include <display/st7558.h>
+#include <rf/trf6151.h>
+
+#include <comm/sercomm.h>
+
+#include <calypso/clock.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/irq.h>
+#include <calypso/misc.h>
+
+#include <layer1/sync.h>
+#include <layer1/tpu_window.h>
+
+/* FIXME: We need proper calibrated delay loops at some point! */
+void delay_us(unsigned int us)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < us*4; i++) { i; }
+}
+
+void delay_ms(unsigned int ms)
+{
+ volatile unsigned int i;
+
+ for (i= 0; i < ms*1300; i++) { i; }
+}
+
+const char *hr = "======================================================================\n";
+
+/* MAIN program **************************************************************/
+
+/* completion call-back for the L1 Sync Pwer Measurement */
+static void l1s_signal_cb(struct l1_signal *sig)
+{
+ uint16_t i, next_arfcn;
+
+ switch (sig->signum) {
+ case L1_SIG_PM:
+ break;
+ case L1_SIG_NB:
+ break;
+ }
+}
+
+static void key_handler(enum key_codes code, enum key_states state);
+static void la1_l23_rx_cb(uint8_t dlci, struct msgb *msg);
+
+int main(void)
+{
+ board_init();
+ puts("\n\nHello World from " __FILE__ " program code\n");
+
+ puts(hr);
+ /* Dump device identification */
+ dump_dev_id();
+ puts(hr);
+
+ keypad_set_handler(&key_handler);
+
+ /* Dump clock config aftee PLL set */
+ calypso_clk_dump();
+ puts(hr);
+
+ st7558_set_attr(DISP_ATTR_INVERT);
+ st7558_puts("layer1.bin");
+
+ sercomm_register_rx_cb(SC_DLCI_L1A_L23, la1_l23_rx_cb);
+
+ layer1_init();
+ l1s_set_handler(&l1s_signal_cb);
+
+ tpu_frame_irq_en(1, 1);
+
+ while (1) {}
+
+ /* NOT REACHED */
+
+ twl3025_power_off();
+}
+
+static int8_t vga_gain = 40;
+static int high_gain = 0;
+static int afcout = 0;
+
+static void update_vga_gain(void)
+{
+ printf("VGA Gain: %u %s\n", vga_gain, high_gain ? "HIGH" : "LOW");
+ trf6151_set_gain(vga_gain, high_gain);
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+static void tspact_toggle(uint8_t num)
+{
+ printf("TSPACT%u toggle\n", num);
+ tsp_act_toggle((1 << num));
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+static void key_handler(enum key_codes code, enum key_states state)
+{
+ if (state != PRESSED)
+ return;
+
+ switch (code) {
+ case KEY_1: /* VGA gain decrement */
+ vga_gain -= 2;
+ if (vga_gain < 14)
+ vga_gain = 14;
+ update_vga_gain();
+ break;
+ case KEY_2: /* High/Low Rx gain */
+ high_gain ^= 1;
+ update_vga_gain();
+ break;
+ case KEY_3: /* VGA gain increment */
+ vga_gain += 2;
+ if (vga_gain > 40)
+ vga_gain = 40;
+ update_vga_gain();
+ break;
+ case KEY_4:
+ tspact_toggle(6); /* TRENA (RFFE) */
+ break;
+ case KEY_5:
+ tspact_toggle(8); /* GSM_TXEN (RFFE) */
+ break;
+ case KEY_6:
+ tspact_toggle(1); /* PAENA (RFFE) */
+ break;
+ case KEY_7: /* decrement AFC OUT */
+ afcout -= 100;
+ if (afcout < -4096)
+ afcout = -4096;
+ twl3025_afc_set(afcout);
+ printf("AFC OUT: %u\n", twl3025_afcout_get());
+ break;
+ case KEY_9: /* increase AFC OUT */
+ afcout += 100;
+ if (afcout > 4095)
+ afcout = 4095;
+ twl3025_afc_set(afcout);
+ printf("AFC OUT: %u\n", twl3025_afcout_get());
+ break;
+ default:
+ break;
+ }
+}
+
+static void la1_l23_rx_cb(uint8_t dlci, struct msgb *msg)
+{
+ struct l1_info_ul *ul = msg->data;
+ struct l1_sync_new_ccch_req *sync_req;
+
+ if (sizeof(*ul) > msg->len) {
+ printf("la1_l23_cb: Short message. %u\n", msg->len);
+ goto exit;
+ }
+
+ switch (ul->msg_type) {
+ case SYNC_NEW_CCCH_REQ:
+ if (sizeof(*ul) + sizeof(*sync_req) > msg->len) {
+ printf("Short sync msg. %u\n", msg->len);
+ break;
+ }
+
+ sync_req = (struct l1_sync_new_ccch_req *) (&msg->data[0] + sizeof(*ul));
+ printf("Asked to tune to frequency: %u\n", sync_req->band_arfcn);
+ break;
+ case DEDIC_MODE_EST_REQ:
+ break;
+ }
+
+exit:
+ msgb_free(msg);
+}
diff --git a/src/target/firmware/board/common/compal_ramload.lds b/src/target/firmware/board/common/compal_ramload.lds
new file mode 100644
index 00000000..ae791c5d
--- /dev/null
+++ b/src/target/firmware/board/common/compal_ramload.lds
@@ -0,0 +1,83 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ /* area that can be initialized by the loader (plus some reserved stuff) */
+ LRAM (rw) : ORIGIN = 0x00800000, LENGTH = 0x00010000
+ /* remainder of internal ram, can be used for bss and the like */
+ IRAM (rw) : ORIGIN = 0x00810000, LENGTH = 0x00030000
+ /* external ram on a C123 */
+ ERAM (rw) : ORIGIN = 0x01000000, LENGTH = 0x00040000
+}
+SECTIONS
+{
+ . = 0x800000;
+
+ /* reserved (what is in here?) */
+ .compal.reserved1 (NOLOAD) : { . = 0x100; } > LRAM
+
+ /* XXX: leftovers from exception vector trickery development? */
+ /* .compal.reserved1 (NOLOAD) : { . = 0x1C; } > LRAM */
+ /* .compal.reserved2 (NOLOAD) : { . = 0xC8; } > LRAM */
+
+ /* image signature (prepended by compal_dnload according to phone type) */
+ .compal.header (NOLOAD) : { . = 4; } > LRAM
+
+ /* code */
+ . = ALIGN(4);
+ .text_start : {
+ /* initialization code */
+ PROVIDE(_start = .);
+ KEEP(*(.init))
+ *(.text._start)
+ _exceptions = .;
+ } > LRAM
+
+ /* exception vectors from 0x80001c to 0x800034 */
+ .text.exceptions 0x80001c: AT (LOADADDR(.text_start) + SIZEOF(.text_start)) {
+ KEEP(*(.text.exceptions))
+ * (.text.exceptions)
+ . = ALIGN(4);
+ } > LRAM
+
+ /* code */
+ . = ALIGN(4);
+ .text (LOADADDR(.text.exceptions) + SIZEOF(.text.exceptions)) :
+ AT (LOADADDR(.text.exceptions) + SIZEOF(.text.exceptions)) {
+ /* regular code */
+ *(.text*)
+ } > LRAM
+
+ /* read-only data */
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata)
+ } > LRAM
+
+ /* initialized data */
+ . = ALIGN(4);
+ .data : {
+ *(.data)
+ } > LRAM
+
+ /* pic offset tables */
+ . = ALIGN(4);
+ .got : {
+ *(.got)
+ } > LRAM
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss)
+ } > IRAM
+ . = ALIGN(4);
+ __bss_end = .;
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/common/compal_ramload_start.S b/src/target/firmware/board/common/compal_ramload_start.S
new file mode 100644
index 00000000..4f6fadef
--- /dev/null
+++ b/src/target/firmware/board/common/compal_ramload_start.S
@@ -0,0 +1,257 @@
+
+#define BA_UART_MODEM 0xFFFF5800
+
+#
+
+.macro senduart, rd, rx
+ strb \rd, [\rx, #0]
+.endm
+
+.macro busyuart, rd, rx
+1001:
+ @busy waiting until THR is empty
+ ldrb \rd, [\rx, #5] @ read LSR register
+ mov \rd, \rd, lsr #6
+ tst \rd, #1
+ beq 1001b
+.endm
+
+.macro loadsp, rd
+ ldr \rd, =BA_UART_MODEM
+.endm
+
+
+ .EQU ARM_MODE_FIQ, 0x11
+ .EQU ARM_MODE_IRQ, 0x12
+ .EQU ARM_MODE_SVC, 0x13
+
+ .EQU I_BIT, 0x80
+ .EQU F_BIT, 0x40
+
+#define TOP_OF_RAM 0x083fff0
+#define FIQ_STACK_SIZE 1024
+#define IRQ_STACK_SIZE 1024
+
+.section .text._start
+.globl _start
+_start:
+ @ clear bss section
+ .global __bss_start
+ .global __bss_end
+ mov r0, #0
+ ldr r1, =__bss_start
+ ldr r2, =__bss_end
+2: cmp r1, r2
+ strlo r0, [r1], #4
+ blo 2b
+
+ ldr r0, =TOP_OF_RAM
+ /* initialize FIQ stack */
+ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #FIQ_STACK_SIZE
+
+ /* initialize IRQ stack */
+ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #IRQ_STACK_SIZE
+
+ /* initialize supervisor stack */
+ msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT
+ mov r13, r0
+
+ @ set backlight to moderate level
+ bl pwl_init
+ mov r0, #50
+ bl pwl_set_level
+
+ @ldr r0, =string
+ @bl puts_asm
+
+ @ some memory dumps
+ @ldr r0, =0xfffef000
+ @bl memdump
+ @ldr r0, =0xfffffe00
+ @bl memdump
+
+ ldr pc, _jump_main
+
+ @ endless loop at end of program
+_end: b _end
+ b _start
+
+_jump_main: .word main
+
+string: .word 0x6c6c6548
+ .word 0x6f57206f
+ .word 0x00646c72
+
+foo: .word 0xee4c9f63
+bar: .word 0x639f4cee
+
+ .align 2
+ .type phexbuf, #object
+phexbuf: .space 12
+ .size phexubf, . - phexbuf
+
+.globl phex
+phex: adr r3, phexbuf
+ mov r2, #0
+ strb r2, [r3, r1]
+1: subs r1, r1, #1
+ movmi r0, r3
+ bmi puts_asm
+ and r2, r0, #15
+ mov r0, r0, lsr #4
+ cmp r2, #10
+ addge r2, r2, #7
+ add r2, r2, #'0'
+ strb r2, [r3, r1]
+ b 1b
+
+puts_asm: loadsp r3
+1: ldrb r2, [r0], #1
+ teq r2, #0
+ moveq pc, lr
+2: senduart r2, r3
+ busyuart r1, r3
+ teq r2, #'\n'
+ moveq r2, #'\r'
+ beq 2b
+ teq r0, #0
+ bne 1b
+ mov pc, lr
+.globl putchar_asm
+putchar_asm:
+ mov r2, r0
+ mov r0, #0
+ loadsp r3
+ b 2b
+
+memdump: mov r12, r0
+ mov r10, lr
+ mov r11, #0
+2: mov r0, r11, lsl #2
+ add r0, r0, r12
+ mov r1, #8
+ bl phex
+ mov r0, #':'
+ bl putchar_asm
+1: mov r0, #' '
+ bl putchar_asm
+ ldr r0, [r12, r11, lsl #2]
+ mov r1, #8
+ bl phex
+ and r0, r11, #7
+ teq r0, #3
+ moveq r0, #' '
+ bleq putchar_asm
+ and r0, r11, #7
+ add r11, r11, #1
+ teq r0, #7
+ bne 1b
+ mov r0, #'\n'
+ bl putchar_asm
+ cmp r11, #64
+ blt 2b
+ mov pc, r10
+
+
+#define ASIC_CONF_REG 0xfffef008
+#define BA_PWL 0xfffe8000
+
+pwl_init: ldr r1, =ASIC_CONF_REG
+ ldr r2, [r1]
+ orr r2, r2, #0x10 @ set light output to PWL
+ str r2, [r1]
+ ldr r1, =BA_PWL
+ mov r0, #1
+ strb r0, [r1, #1] @ enable clock of PWL unut
+ mov pc, lr
+
+pwl_set_level: ldr r1, =BA_PWL
+ strb r0, [r1]
+ mov pc, lr
+
+handle_abort:
+ @ print the PC we would jump back to...
+ sub lr, lr, #4 @ we assume to be ARM32
+
+ mov r0, lr
+ mov r1, #8
+ bl phex
+
+ @ print abort message
+ mov r0, #'A'
+ bl putchar_asm
+ mov r0, #'B'
+ bl putchar_asm
+ mov r0, #'O'
+ bl putchar_asm
+ mov r0, #'R'
+ bl putchar_asm
+ mov r0, #'T'
+ bl putchar_asm
+0: @ dead
+ b 0b
+
+irq_entry:
+ /* Adjust and save LR_irq in IRQ stack */
+ sub lr, lr, #4
+ stmfd sp!, {lr}
+
+ /* Save SPSR for nested interrupt */
+ mrs r14, SPSR
+ stmfd sp!, {r14}
+
+ /* Call the interrupt handler C function */
+ stmfd sp!, {r0-r4, r12}
+ bl irq
+ ldmfd sp!, {r0-r4, r12}
+
+ /* Restore SPSR_irq from IRQ stack */
+ ldmia sp!, {r14}
+ msr SPSR_cxsf, r14
+
+ /* Restore adjusted LR_irq from IRQ stack directly in the PC */
+ ldmia sp!, {pc}^
+
+fiq_entry:
+ /* Adjust and save LR_irq in IRQ stack */
+ sub lr, lr, #4
+ stmfd sp!, {lr}
+
+ /* Save SPSR for nested interrupt */
+ mrs r14, SPSR
+ stmfd sp!, {r14}
+
+ /* Call the interrupt handler C function */
+ stmfd sp!, {r0-r4, r12}
+ bl fiq
+ ldmfd sp!, {r0-r4, r12}
+
+ /* Restore SPSR_irq from IRQ stack */
+ ldmia sp!, {r14}
+ msr SPSR_cxsf, r14
+
+ /* Restore adjusted LR_irq from IRQ stack directly in the PC */
+ ldmia sp!, {pc}^
+
+/* Exception Vectors like they are needed for the exception vector
+ indirection of the internal boot ROM. The following section must be liked
+ to appear at 0x80'001c */
+.section .text.exceptions
+_undef_instr:
+ b handle_abort
+_sw_interr:
+ b _sw_interr
+_prefetch_abort:
+ b handle_abort
+_data_abort:
+ b handle_abort
+_reserved:
+ b _reserved
+_irq:
+ b irq_entry
+_fiq:
+ b fiq_entry
diff --git a/src/target/firmware/board/common/rffe_compal_dualband.c b/src/target/firmware/board/common/rffe_compal_dualband.c
new file mode 100644
index 00000000..b796c6f5
--- /dev/null
+++ b/src/target/firmware/board/common/rffe_compal_dualband.c
@@ -0,0 +1,70 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rffe.h>
+#include <calypso/tsp.h>
+#include <rf/trf6151.h>
+
+/* describe how the RF frontend is wired on the Motorola E88 board (C117/C118/C121/C123) */
+
+#define RITA_RESET TSPACT(0) /* Reset of the Rita TRF6151 */
+#define PA_ENABLE TSPACT(1) /* Enable the Power Amplifier */
+#define TRENA TSPACT(6) /* Transmit Enable (Antenna Switch) */
+#define GSM_TXEN TSPACT(8) /* GSM (as opposed to DCS) Transmit */
+
+#define IOTA_STROBE TSPEN0 /* Strobe for the Iota TSP */
+#define RITA_STROBE TSPEN2 /* Strobe for the Rita TSP */
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx)
+{
+ uint16_t tspact = tsp_act_state();
+
+ /* First we mask off all bits from the state cache */
+ tspact &= ~PA_ENABLE;
+ tspact |= TRENA | GSM_TXEN; /* low-active */
+
+ /* Then we selectively set the bits on, if required */
+ if (tx) {
+ tspact &= ~TRENA;
+ if (band == GSM_900)
+ tspact &= ~GSM_TXEN;
+ }
+
+ tsp_act_update(tspact);
+}
+
+#define MCU_SW_TRACE 0xfffef00e
+#define ARM_CONF_REG 0xfffef006
+
+void rffe_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ARM_CONF_REG);
+ reg &= ~ (1 << 5); /* TSPACT6 I/O function, not nCS6 */
+ writew(reg, ARM_CONF_REG);
+
+ reg = readw(MCU_SW_TRACE);
+ reg &= ~(1 << 5); /* TSPACT8 I/O function, not nMREQ */
+ writew(reg, MCU_SW_TRACE);
+}
+
+uint8_t rffe_get_gain(void)
+{
+ return trf6151_get_gain();
+}
+
+/* Given the expected input level of exp_inp dBm/8 and the target of target_bb
+ * dBm8, configure the RF Frontend with the respective gain */
+void rffe_set_gain(int16_t exp_inp, int16_t target_bb)
+{
+
+}
+
+void rffe_rx_win_ctrl(int16_t exp_inp, int16_t target_bb)
+{
+
+}
diff --git a/src/target/firmware/board/compal_e88/init.c b/src/target/firmware/board/compal_e88/init.c
new file mode 100644
index 00000000..f51f3e8d
--- /dev/null
+++ b/src/target/firmware/board/compal_e88/init.c
@@ -0,0 +1,126 @@
+/* Initialization for the Compal E88 (Motorola C115...C123) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <console.h>
+#include <cfi_flash.h>
+
+#include <calypso/irq.h>
+#include <calypso/clock.h>
+#include <calypso/dma.h>
+#include <calypso/rtc.h>
+#include <calypso/timer.h>
+#include <calypso/uart.h>
+
+#include <comm/sercomm.h>
+
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+#include <display/st7558.h>
+
+#define ARMIO_LATCH_OUT 0xfffe4802
+#define ARMIO_CNTL_REG 0xfffe4804
+#define ASIC_CONF_REG 0xfffef008
+
+static void board_io_init(void)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+ /* LCD Set I/O(3) / SA0 to I/O(3) mode */
+ reg &= ~(1 << 10);
+ /* Set function pins to I2C Mode */
+ reg |= 0x1080; /* SCL / SDA */
+ /* TWL3025: Set SPI+RIF RX clock to rising edge */
+ reg |= (1 << 13) | (1 << 14);
+ writew(reg, ASIC_CONF_REG);
+
+ /* LCD Set I/O(3) to output mode */
+ reg = readw(ARMIO_CNTL_REG);
+ reg &= ~(1 << 3);
+ writew(reg, ARMIO_CNTL_REG);
+
+ /* LCD Set I/O(3) output low */
+ reg = readw(ARMIO_LATCH_OUT);
+ reg &= ~(1 << 3);
+ writew(reg, ARMIO_LATCH_OUT);
+}
+
+void board_init(void)
+{
+ /* FIXME: this needs to go to board_e99/init.c once we have it */
+ wdog_enable(0);
+
+ static cfi_flash_t flash;
+ // XXX: move after mapping initialization and use final address
+ flash_init(&flash, 0x00000000);
+
+ calypso_mem_cfg(CALYPSO_nCS0, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS1, 3, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS2, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS3, 5, CALYPSO_MEM_16bit, 1);
+ calypso_mem_cfg(CALYPSO_CS4, 0, CALYPSO_MEM_8bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS6, 0, CALYPSO_MEM_32bit, 1);
+ calypso_mem_cfg(CALYPSO_nCS7, 0, CALYPSO_MEM_32bit, 0);
+
+ /* Set VTCXO_DIV2 = 1, configure PLL for 104 MHz and give ARM half of that */
+ calypso_clock_set(2, CALYPSO_PLL13_104_MHZ, ARM_MCLK_DIV_2);
+
+ /* Configure the RHEA bridge with some sane default values */
+ calypso_rhea_cfg(0, 0, 0xff, 0, 1, 0, 0);
+
+ board_io_init();
+
+ /* Enable bootrom mapping to route exception vectors to RAM */
+ calypso_bootrom(1);
+ calypso_exceptions_install();
+
+ irq_init();
+
+ /* initialize MODEM UART to be used for sercomm*/
+ uart_init(SERCOMM_UART_NR);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+
+ /* initialize IRDA UART to be used for old-school console code.
+ * note: IRDA uart only accessible on C115 and C117 PCB */
+ uart_init(CONS_UART_NR);
+ uart_baudrate(CONS_UART_NR, UART_115200);
+
+ hwtimer_init();
+
+ dma_init();
+ rtc_init();
+
+ /* Initialize LCD driver (uses I2C) */
+ st7558_init();
+
+ keypad_init();
+
+ /* Initialize ABB driver (uses SPI) */
+ twl3025_init();
+}
diff --git a/src/target/firmware/calypso/Makefile b/src/target/firmware/calypso/Makefile
new file mode 100644
index 00000000..a2be3cfa
--- /dev/null
+++ b/src/target/firmware/calypso/Makefile
@@ -0,0 +1,17 @@
+INCLUDES=-I../include/
+-include ../Makefile.inc
+
+OBJS=arm.o clock.o dma.o dsp.o du.o i2c.o irq.o rtc.o spi.o tpu.o tsp.o keypad.o misc.o timer.o backlight.o uart.o
+
+LST=$(OBJS:.o=.lst)
+
+all: libcalypso.a
+
+%.o: %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
+
+libcalypso.a: $(OBJS)
+ $(CROSS_COMPILE)$(AR) cru $@ $^
+
+clean:
+ rm -f *.a $(OBJS) $(LST)
diff --git a/src/target/firmware/calypso/arm.c b/src/target/firmware/calypso/arm.c
new file mode 100644
index 00000000..8794ee35
--- /dev/null
+++ b/src/target/firmware/calypso/arm.c
@@ -0,0 +1,26 @@
+
+/* enable IRQ+FIQ interrupts */
+void arm_enable_interrupts (void)
+{
+ unsigned long temp;
+ __asm__ __volatile__("mrs %0, cpsr\n"
+ "bic %0, %0, #0xc0\n"
+ "msr cpsr_c, %0"
+ : "=r" (temp)
+ :
+ : "memory");
+}
+
+/* disable IRQ/FIQ interrupts
+ * returns true if interrupts had been enabled before we disabled them */
+int arm_disable_interrupts(void)
+{
+ unsigned long old,temp;
+ __asm__ __volatile__("mrs %0, cpsr\n"
+ "orr %1, %0, #0xc0\n"
+ "msr cpsr_c, %1"
+ : "=r" (old), "=r" (temp)
+ :
+ : "memory");
+ return (old & 0x80) == 0;
+}
diff --git a/src/target/firmware/calypso/backlight.c b/src/target/firmware/calypso/backlight.c
new file mode 100644
index 00000000..e2ff29cc
--- /dev/null
+++ b/src/target/firmware/calypso/backlight.c
@@ -0,0 +1,67 @@
+/* Calypso DBB internal PWL (Pulse Width / Light) Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <memory.h>
+
+#define BASE_ADDR_PWL 0xfffe8000
+#define PWL_REG(m) (BASE_ADDR_PWL + (m))
+
+#define ASIC_CONF_REG 0xfffef008
+#define LIGHT_LEVEL_REG 0xfffe4810
+
+enum pwl_reg {
+ PWL_LEVEL = 0,
+ PWL_CTRL = 2,
+};
+
+#define ASCONF_PWL_ENA (1 << 4)
+
+void bl_mode_pwl(int on)
+{
+ uint16_t reg;
+
+ reg = readw(ASIC_CONF_REG);
+
+ if (on) {
+ writeb(0x01, PWL_REG(PWL_CTRL));
+ /* Switch pin from LT to PWL */
+ reg |= ASCONF_PWL_ENA;
+ writew(reg, ASIC_CONF_REG);
+ } else {
+ /* Switch pin from PWL to LT */
+ reg |= ~ASCONF_PWL_ENA;
+ writew(reg, ASIC_CONF_REG);
+ writeb(0x00, PWL_REG(PWL_CTRL));
+ }
+}
+
+void bl_level(uint8_t level)
+{
+ if (readw(ASIC_CONF_REG) & ASCONF_PWL_ENA) {
+ writeb(level, PWL_REG(PWL_LEVEL));
+ } else {
+ /* we need to scale the light level, as the
+ * ARMIO light controller only knows 0..63 */
+ writeb(level>>2, LIGHT_LEVEL_REG);
+ }
+}
diff --git a/src/target/firmware/calypso/clock.c b/src/target/firmware/calypso/clock.c
new file mode 100644
index 00000000..d5b2c090
--- /dev/null
+++ b/src/target/firmware/calypso/clock.c
@@ -0,0 +1,202 @@
+/* Driver for Calypso clock management */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+//#define DEBUG
+#include <debug.h>
+
+#include <memory.h>
+#include <calypso/clock.h>
+
+#define REG_DPLL 0xffff9800
+#define DPLL_LOCK (1 << 0)
+#define DPLL_BREAKLN (1 << 1)
+#define DPLL_BYPASS_DIV_SHIFT 2 /* 2 bits */
+#define DPLL_PLL_ENABLE (1 << 4)
+#define DPLL_PLL_DIV_SHIFT 5 /* 2 bits */
+#define DPLL_PLL_MULT_SHIFT 7 /* 5 bits */
+#define DPLL_TEST (1 << 12)
+#define DPLL_IOB (1 << 13) /* Initialize on break */
+#define DPLL_IAI (1 << 14) /* Initialize after Idle */
+
+#define BASE_ADDR_CLKM 0xfffffd00
+#define CLKM_REG(m) (BASE_ADDR_CLKM+(m))
+
+enum clkm_reg {
+ CNTL_ARM_CLK = 0,
+ CNTL_CLK = 2,
+ CNTL_RST = 4,
+ CNTL_ARM_DIV = 8,
+};
+
+/* CNTL_ARM_CLK */
+#define ARM_CLK_BIG_SLEEP (1 << 0) /* MCU Master Clock enabled? */
+#define ARM_CLK_CLKIN_SEL0 (1 << 1) /* MCU source clock (0 = DPLL output, 1 = VTCXO or CLKIN */
+#define ARM_CLK_CLKIN_SEL (1 << 2) /* 0 = VTCXO or 1 = CLKIN */
+#define ARM_CLK_MCLK_DIV5 (1 << 3) /* enable 1.5 or 2.5 division factor */
+#define ARM_CLK_MCLK_DIV_SHIFT 4 /* 3 bits */
+#define ARM_CLK_DEEP_POWER_SHIFT 8
+#define ARM_CLK_DEEP_SLEEP 12
+
+/* CNTL_CLK */
+#define CLK_IRQ_CLK_DIS (1 << 0) /* IRQ clock control (0 always, 1 according ARM_MCLK_EN) */
+#define CLK_BRIDGE_CLK_DIS (1 << 1)
+#define CLK_TIMER_CLK_DIS (1 << 2)
+#define CLK_DPLL_DIS (1 << 3) /* 0: DPLL is not stopped during SLEEP */
+#define CLK_CLKOUT_EN (1 << 4) /* Enable CLKOUT output pins */
+#define CLK_EN_IDLE3_FLG (1 << 5) /* DSP idle flag control (1 =
+ * SAM/HOM register forced to HOM when DSP IDLE3) */
+#define CLK_VCLKOUT_DIV2 (1 << 6) /* 1: VCLKOUT-FR is divided by 2 */
+#define CLK_VTCXO_DIV2 (1 << 7) /* 1: VTCXO is dividied by 2 */
+
+#define BASE_ADDR_MEMIF 0xfffffb00
+#define MEMIF_REG(x) (BASE_ADDR_MEMIF+(x))
+
+enum memif_reg {
+ API_RHEA_CTL = 0x0e,
+ EXTRA_CONF = 0x10,
+};
+
+static void dump_reg16(uint32_t addr, char *name)
+{
+ printf("%s=0x%04x\n", name, readw(addr));
+}
+
+void calypso_clk_dump(void)
+{
+ dump_reg16(REG_DPLL, "REG_DPLL");
+ dump_reg16(CLKM_REG(CNTL_ARM_CLK), "CNTL_ARM_CLK");
+ dump_reg16(CLKM_REG(CNTL_CLK), "CNTL_CLK");
+ dump_reg16(CLKM_REG(CNTL_RST), "CNTL_RST");
+ dump_reg16(CLKM_REG(CNTL_ARM_DIV), "CNTL_ARM_DIV");
+}
+
+void calypso_pll_set(uint16_t inp)
+{
+ uint8_t mult = inp >> 8;
+ uint8_t div = inp & 0xff;
+ uint16_t reg = readw(REG_DPLL);
+
+ reg &= ~0x0fe0;
+ reg |= (div & 0x3) << DPLL_PLL_DIV_SHIFT;
+ reg |= (mult & 0x1f) << DPLL_PLL_MULT_SHIFT;
+ reg |= DPLL_PLL_ENABLE;
+
+ writew(reg, REG_DPLL);
+}
+
+void calypso_reset_set(enum calypso_rst calypso_rst, int active)
+{
+ uint8_t reg = readb(CLKM_REG(CNTL_RST));
+
+ if (active)
+ reg |= calypso_rst;
+ else
+ reg &= ~calypso_rst;
+
+ writeb(reg, CLKM_REG(CNTL_RST));
+}
+
+int calypso_reset_get(enum calypso_rst calypso_rst)
+{
+ uint8_t reg = readb(CLKM_REG(CNTL_RST));
+
+ if (reg & calypso_rst)
+ return 1;
+ else
+ return 0;
+}
+
+void calypso_clock_set(uint8_t vtcxo_div2, uint16_t inp, enum mclk_div mclk_div)
+{
+ uint16_t cntl_clock = readw(CLKM_REG(CNTL_CLK));
+ uint16_t cntl_arm_clk = readw(CLKM_REG(CNTL_ARM_CLK));
+
+ /* First set the vtcxo_div2 */
+ cntl_clock &= ~CLK_VCLKOUT_DIV2;
+ if (vtcxo_div2)
+ cntl_clock |= CLK_VTCXO_DIV2;
+ else
+ cntl_clock &= ~CLK_VTCXO_DIV2;
+ writew(cntl_clock, CLKM_REG(CNTL_CLK));
+
+ /* Then configure the MCLK divider */
+ cntl_arm_clk &= ~ARM_CLK_CLKIN_SEL0;
+ if (mclk_div & 0x80) {
+ mclk_div &= ~0x80;
+ cntl_arm_clk |= ARM_CLK_MCLK_DIV5;
+ } else
+ cntl_arm_clk &= ~ARM_CLK_MCLK_DIV5;
+ cntl_arm_clk &= ~(0x7 << ARM_CLK_MCLK_DIV_SHIFT);
+ cntl_arm_clk |= (mclk_div << ARM_CLK_MCLK_DIV_SHIFT);
+ writew(cntl_arm_clk, CLKM_REG(CNTL_ARM_CLK));
+
+ /* Then finally set the PLL */
+ calypso_pll_set(inp);
+}
+
+void calypso_mem_cfg(enum calypso_bank bank, uint8_t ws,
+ enum calypso_mem_width width, int we)
+{
+ writew((ws & 0x1f) | ((width & 3) << 5) | ((we & 1) << 7),
+ BASE_ADDR_MEMIF + bank);
+}
+
+void calypso_bootrom(int enable)
+{
+ uint16_t conf = readw(MEMIF_REG(EXTRA_CONF));
+
+ conf &= ~(3 << 8);
+
+ // XXX: this can't be correct
+ if (enable)
+ conf |= (1 << 8);
+ else
+ conf |= (1 << 8);
+ writew(conf, MEMIF_REG(EXTRA_CONF));
+}
+
+void calypso_debugunit(int enable)
+{
+ uint16_t conf = readw(MEMIF_REG(EXTRA_CONF));
+
+ if (enable)
+ conf &= ~(1 << 11);
+ else
+ conf |= (1 << 11);
+
+ writew(conf, MEMIF_REG(EXTRA_CONF));
+}
+
+#define REG_RHEA_CNTL 0xfffff900
+#define REG_API_CNTL 0xfffff902
+#define REG_ARM_RHEA 0xfffff904
+
+void calypso_rhea_cfg(uint8_t fac0, uint8_t fac1, uint8_t timeout,
+ uint8_t ws_h, uint8_t ws_l, uint8_t w_en0, uint8_t w_en1)
+{
+ writew(fac0 | (fac1 << 4) | (timeout << 8), REG_RHEA_CNTL);
+ writew(ws_h | (ws_l << 5), REG_API_CNTL);
+ writew(w_en0 | (w_en1 << 1), REG_ARM_RHEA);
+}
diff --git a/src/target/firmware/calypso/dma.c b/src/target/firmware/calypso/dma.c
new file mode 100644
index 00000000..35c5be82
--- /dev/null
+++ b/src/target/firmware/calypso/dma.c
@@ -0,0 +1,44 @@
+/* Driver for Calypso DMA controller */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+
+#define BASE_ADDR_DMA 0xfffffc00
+
+enum dma_reg {
+ CONTROLLER_CONF = 0x00,
+ ALLOC_CONFIG = 0x02,
+};
+#define DMA_REG(m) (BASE_ADDR_DMA + (m))
+
+#define DMA_RAD(x) DMA_REG((x)*0x10 + 0x0)
+#define DMA_RDPATH(x) DMA_REG((x)*0x10 + 0x2)
+#define DMA_AAD(x) DMA_REG((x)*0x10 + 0x4)
+#define DMA_ALGTH(x) DMA_REG((x)*0x10 + 0x6)
+#define DMA_CTRL(x) DMA_REG((x)*0x10 + 0x8)
+#define DMA_CUR_OFF_API(x) DMA_REG((x)*0x10 + 0xa)
+
+void dma_init(void)
+{
+ /* DMA 1 (RIF Tx), 2 (RIF Rx) allocated to DSP, all others to ARM */
+ writew(0x000c, DMA_REG(ALLOC_CONFIG));
+}
diff --git a/src/target/firmware/calypso/dsp.c b/src/target/firmware/calypso/dsp.c
new file mode 100644
index 00000000..59176567
--- /dev/null
+++ b/src/target/firmware/calypso/dsp.c
@@ -0,0 +1,391 @@
+#define DEBUG
+/* Driver for the Calypso integrated DSP */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <calypso/clock.h>
+#include <calypso/dsp.h>
+#include <calypso/dsp_api.h>
+#include <calypso/tpu.h>
+
+#define REG_API_CONTROL 0xfffe0000
+#define APIC_R_SMODE_HOM (1 << 1) /* API is configured in HOM mode */
+#define APIC_R_HINT (1 << 3) /* Host processor interrupt (DSP->MCU) */
+#define APIC_W_DSPINT (1 << 2) /* ARM issues interrupt to DSP */
+
+#define REG_API_WS 0xfffff902 /* Number of wait states for ARM access to API memory */
+#define REG_ARM_RHEA_CTL 0xfffff904 /* Write buffer bypassing */
+#define REG_EXT_RHEA_CTL 0xfffff906 /* Some timeout */
+
+#define API_SIZE 0x2000U /* in words */
+
+#define BASE_API_RAM 0xffd00000 /* Base address of API RAM form ARM point of view */
+
+#define DSP_BASE_API 0x0800 /* Base address of API RAM for DSP */
+#define DSP_BASE_API_MIRROR 0xe000 /* Base address of API RAM for DSP (API boot mirrot */
+#define DSP_START 0x7000 /* DSP Start address */
+
+/* Boot loader */
+#define BL_CMD_STATUS (BASE_API_RAM + 0x0ffe) /* Status / Command var */
+#define BL_ADDR_LO (BASE_API_RAM + 0x0ffc) /* Address (16 lsbs) */
+#define BL_ADDR_HI (BASE_API_RAM + 0x0ff8) /* Address (ext page bits) */
+#define BL_SIZE (BASE_API_RAM + 0x0ffa) /* Size */
+
+#define BL_MAX_BLOCK_SIZE 0x7F0 /* Maximum size of copied block */
+
+ /* Possible values for the download status */
+#define BL_STATUS_NA 0
+#define BL_STATUS_IDLE 1
+#define BL_CMD_COPY_BLOCK 2
+#define BL_CMD_COPY_MODE 4
+
+#define BL_MODE_PROG_WRITE 0
+#define BL_MODE_DATA_WRITE 1
+#define BL_MODE_PROG_READ 2
+#define BL_MODE_DATA_READ 3
+#define BL_MODE_PROM_READ 4
+#define BL_MODE_DROM_READ 5
+
+
+struct dsp_section {
+ uint32_t addr; /* addr for DSP */
+ uint32_t size; /* size in words */
+ const uint16_t *data;
+};
+
+#include "dsp_params.c"
+#include "dsp_bootcode.c"
+#include "dsp_dumpcode.c"
+
+struct dsp_api dsp_api = {
+ .ndb = (T_NDB_MCU_DSP *) BASE_API_NDB,
+ .db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0,
+ .db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0,
+ .param = (T_PARAM_MCU_DSP *) BASE_API_PARAM,
+ .r_page = 0,
+ .w_page = 0,
+};
+
+
+void dsp_dump_version(void)
+{
+ printf("DSP Download Status: 0x%04x\n", readw(BL_CMD_STATUS));
+ printf("DSP API Version: 0x%04x 0x%04x\n",
+ dsp_api.ndb->d_version_number1, dsp_api.ndb->d_version_number2);
+}
+
+static void dsp_bl_wait_ready(void)
+{
+ while (readw(BL_CMD_STATUS) != BL_STATUS_IDLE);
+}
+
+static int dsp_upload_sections_api(const struct dsp_section *sec, uint16_t dsp_base_api)
+{
+ for (; sec->data; sec++) {
+ unsigned int i;
+ volatile uint16_t *dptr;
+
+ if (sec->addr & ~((1<<16)-1)) /* 64k max addr */
+ return -1;
+ if (sec->addr < dsp_base_api)
+ return -1;
+ if ((sec->addr + sec->size) > (dsp_base_api + API_SIZE))
+ return -1;
+
+ dptr = (volatile uint16_t *)(BASE_API_RAM + ((sec->addr - dsp_base_api) * sizeof(uint16_t)));
+ for (i=0; i<sec->size; i++)
+ *dptr++ = sec->data[i];
+ }
+
+ /* FIXME need eioio or wb ? */
+
+ return 0;
+}
+
+static void dsp_pre_boot(const struct dsp_section *bootcode)
+{
+ dputs("Assert DSP into Reset\n");
+ calypso_reset_set(RESET_DSP, 1);
+
+ if (bootcode) {
+ dputs("Loading initial DSP bootcode (API boot mode)\n");
+ dsp_upload_sections_api(dsp_bootcode, DSP_BASE_API_MIRROR);
+
+ writew(BL_STATUS_NA, BL_CMD_STATUS);
+ } else
+ delay_ms(10);
+
+ dputs("Releasing DSP from Reset\n");
+ calypso_reset_set(RESET_DSP, 0);
+
+ /* Wait 10 us */
+ delay_ms(100);
+
+ dsp_bl_wait_ready();
+}
+
+static void dsp_set_params(int16_t *param_tab, int param_size)
+{
+ int i;
+ int16_t *param_ptr = (int16_t *) BASE_API_PARAM;
+
+ /* Start DSP up to bootloader */
+ dsp_pre_boot(dsp_bootcode);
+
+ /* FIXME: Implement Patch download, if any */
+
+ dputs("Setting some dsp_api.ndb values\n");
+ dsp_api.ndb->d_background_enable = 0;
+ dsp_api.ndb->d_background_abort = 0;
+ dsp_api.ndb->d_background_state = 0;
+ dsp_api.ndb->d_debug_ptr = 0x0074;
+ dsp_api.ndb->d_debug_bk = 0x0001;
+ dsp_api.ndb->d_pll_config = 0x154; //C_PLL_CONFIG;
+ dsp_api.ndb->p_debug_buffer = 0x17ff; //C_DEBUG_BUFFER_ADD;
+ dsp_api.ndb->d_debug_buffer_size = 7; //C_DEBUG_BUFFER_SIZE;
+ dsp_api.ndb->d_debug_trace_type = 0; //C_DEBUG_TRACE_TYPE;
+ dsp_api.ndb->d_dsp_state = 3; //C_DSP_IDLE3;
+ dsp_api.ndb->d_audio_gain_ul = 0;
+ dsp_api.ndb->d_audio_gain_dl = 0;
+ dsp_api.ndb->d_es_level_api = 0x5213;
+ dsp_api.ndb->d_mu_api = 0x5000;
+
+ dputs("Setting API NDB parameters\n");
+ for (i = 0; i < param_size; i ++)
+ *param_ptr++ = param_tab[i];
+
+ dsp_dump_version();
+
+ dputs("Finishing download phase\n");
+ writew(0, BL_SIZE);
+ writew(DSP_START, BL_ADDR_LO);
+ writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
+
+ dsp_dump_version();
+}
+
+void dsp_api_memset(uint16_t *ptr, int octets)
+{
+ uint16_t i;
+ for (i = 0; i < octets / sizeof(uint16_t); i++)
+ *ptr++ = 0;
+}
+
+static void dsp_ndb_init(void)
+{
+ T_NDB_MCU_DSP *ndb = dsp_api.ndb;
+
+ ndb->d_fb_mode = 1; /* mode 1 FCCH burst detection */
+ ndb->d_fb_det = 0; /* we have not yet detected a FB */
+ ndb->a_cd[0] = (1<<B_FIRE1); /* CCCH/SACCH downlink */
+ ndb->a_dd_0[0] = 0;
+ ndb->a_dd_0[2] = 0xffff;
+ ndb->a_dd_1[0] = 0;
+ ndb->a_dd_1[2] = 0xffff;
+ ndb->a_du_0[0] = 0;
+ ndb->a_du_0[2] = 0xffff;
+ ndb->a_du_1[0] = 0;
+ ndb->a_du_1[2] = 0xffff;
+ ndb->a_fd[0] = (1<<B_FIRE1);
+ ndb->a_fd[2] = 0xffff;
+ ndb->d_a5mode = 0;
+ ndb->d_tch_mode = 0x0800;
+ /* FIXME: set guard bits */
+ ndb->a_sch26[0] = (1<<B_SCH_CRC);
+ /* Interrupt RIF transmit if FIFO <= threshold with threshold == 0 */
+ /* MCM = 1, XRST = 0, CLKX_AUTO=1, TXM=1, NCLK_EN=1, NCLK13_EN=1,
+ * THRESHOLD = 0, DIV_CLK = 0 (13MHz) */
+ ndb->d_spcx_rif = 0x179;
+}
+
+static void dsp_db_init(void)
+{
+ dsp_api_memset((void *)BASE_API_W_PAGE_0, sizeof(T_DB_MCU_TO_DSP));
+ dsp_api_memset((void *)BASE_API_W_PAGE_1, sizeof(T_DB_MCU_TO_DSP));
+ dsp_api_memset((void *)BASE_API_R_PAGE_0, sizeof(T_DB_DSP_TO_MCU));
+ dsp_api_memset((void *)BASE_API_R_PAGE_1, sizeof(T_DB_DSP_TO_MCU));
+}
+
+void dsp_power_on(void)
+{
+ dsp_set_params((int16_t *)&dsp_params, sizeof(dsp_params)/2);
+ dsp_ndb_init();
+ dsp_db_init();
+ dsp_api.frame_ctr = 0;
+ dsp_api.r_page = dsp_api.w_page = dsp_api.r_page_used = 0;
+}
+
+/* test for frequency burst detection */
+#define REG_INT_STAT 0xffff1004
+static void wait_for_frame_irq(void)
+{
+ //puts("Waiting for Frame Interrupt");
+ //while (readb(REG_INT_STAT) & 1)
+ while (readb((void *)0xffff1000) & (1<<4))
+ ;// putchar('.');
+ //puts("Done!\n");
+}
+
+void dsp_end_scenario(void)
+{
+ /* FIXME: we don't yet deal with the MISC_TASK */
+
+ /* End the DSP Scenario */
+ dsp_api.ndb->d_dsp_page = B_GSM_TASK | dsp_api.w_page;
+ dsp_api.w_page ^= 1;
+
+ /* Tell TPU to generate a FRAME interrupt to the DSP */
+ tpu_dsp_frameirq_enable();
+ tpu_frame_irq_en(1, 1);
+}
+
+void dsp_load_rx_task(uint16_t task, uint8_t burst_id, uint8_t tsc)
+{
+ dsp_api.db_w->d_task_d = task;
+ dsp_api.db_w->d_burst_d = burst_id;
+ dsp_api.db_w->d_ctrl_system |= tsc & 0x7;
+}
+
+void dsp_load_tx_task(uint16_t task, uint8_t burst_id, uint8_t tsc)
+{
+ dsp_api.db_w->d_task_u = task;
+ dsp_api.db_w->d_burst_u = burst_id;
+ dsp_api.db_w->d_ctrl_system |= tsc & 0x7;
+}
+
+#define SC_CHKSUM_VER (BASE_API_W_PAGE_0 + (2 * (0x08DB - 0x800)))
+static void dsp_dump_csum(void)
+{
+ printf("dsp page : %u\n", dsp_api.ndb->d_dsp_page);
+ printf("dsp code version : 0x%04x\n", dsp_api.db_r->a_pm[0]);
+ printf("dsp checksum : 0x%04x\n", dsp_api.db_r->a_pm[1]);
+ printf("dsp patch version : 0x%04x\n", readw(SC_CHKSUM_VER));
+}
+
+void dsp_checksum_task(void)
+{
+ dsp_dump_csum();
+ dsp_api.db_w->d_task_md = CHECKSUM_DSP_TASK;
+ dsp_api.ndb->d_fb_mode = 1;
+
+ dsp_end_scenario();
+
+ wait_for_frame_irq();
+
+ dsp_dump_csum();
+}
+
+#define L1D_AUXAPC 0x0012
+#define L1D_APCRAM 0x0014
+
+void dsp_load_apc_dac(uint16_t apc)
+{
+ dsp_api.db_w->d_power_ctl = (apc << 6) | L1D_AUXAPC;
+}
+
+
+static void _dsp_dump_range(uint32_t addr, uint32_t size, int mode)
+{
+ uint32_t bs;
+
+ /* Mode selection */
+ writew(mode, BASE_API_RAM);
+ writew(BL_CMD_COPY_MODE, BL_CMD_STATUS);
+ dsp_bl_wait_ready();
+
+ /* Block by block dump */
+ while (size) {
+ volatile uint16_t *api = (volatile uint16_t *)BASE_API_RAM;
+
+ bs = (size > BL_MAX_BLOCK_SIZE) ? BL_MAX_BLOCK_SIZE : size;
+ size -= bs;
+
+ writew(addr >> 16, BL_ADDR_HI);
+ writew(addr & 0xffff, BL_ADDR_LO);
+ writew(bs, BL_SIZE);
+ writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
+
+ dsp_bl_wait_ready();
+
+ while (bs--) {
+ if ((addr&15)==0)
+ printf("%05ux : ", addr);
+ printf("%04hx%c", *api++, ((addr&15)==15)?'\n':' ');
+ addr++;
+ }
+ };
+ puts("\n");
+}
+
+void dsp_dump(void)
+{
+ static const struct {
+ const char *name;
+ uint32_t addr;
+ uint32_t size;
+ int mode;
+ } dr[] = {
+ { "Registers", 0x00000, 0x0060, BL_MODE_DATA_READ },
+ { "DROM", 0x09000, 0x5000, BL_MODE_DROM_READ },
+ { "PDROM", 0x0e000, 0x2000, BL_MODE_DROM_READ },
+ { "PROM0", 0x07000, 0x7000, BL_MODE_PROM_READ },
+ { "PROM1", 0x18000, 0x8000, BL_MODE_PROM_READ },
+ { "PROM2", 0x28000, 0x8000, BL_MODE_PROM_READ },
+ { "PROM3", 0x38000, 0x2000, BL_MODE_PROM_READ },
+ { NULL, 0, 0, -1 }
+ };
+
+ int i;
+
+ /* Start DSP up to bootloader */
+ dsp_pre_boot(dsp_bootcode);
+
+ /* Load and execute our dump code in the DSP */
+ dsp_upload_sections_api(dsp_dumpcode, DSP_BASE_API);
+
+ writew(0, BL_ADDR_HI);
+ writew(DSP_DUMPCODE_START, BL_ADDR_LO);
+ writew(0, BL_SIZE);
+ writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
+
+ /* our dump code actually simulates the boot loaded
+ * but with added read commands */
+ dsp_bl_wait_ready();
+
+ /* Test the 'version' command */
+ writew(0xffff, BL_CMD_STATUS);
+ dsp_bl_wait_ready();
+ printf("DSP bootloader version 0x%04x\n", readw(BASE_API_RAM));
+
+ /* Dump each range */
+ for (i=0; dr[i].name; i++) {
+ printf("DSP dump: %s [%05ux-%05ux]\n", dr[i].name,
+ dr[i].addr, dr[i].addr+dr[i].size-1);
+ _dsp_dump_range(dr[i].addr, dr[i].size, dr[i].mode);
+ }
+}
+
diff --git a/src/target/firmware/calypso/dsp_bootcode.c b/src/target/firmware/calypso/dsp_bootcode.c
new file mode 100644
index 00000000..2db46568
--- /dev/null
+++ b/src/target/firmware/calypso/dsp_bootcode.c
@@ -0,0 +1,9 @@
+/* Calypso integrated DSP boot code */
+
+#define _SA_DECL (const uint16_t *)&(const uint16_t [])
+
+/* We don't really need any DSP boot code, it happily works with its own ROM */
+static const struct dsp_section *dsp_bootcode = NULL;
+
+#undef _SA_DECL
+
diff --git a/src/target/firmware/calypso/dsp_dumpcode.c b/src/target/firmware/calypso/dsp_dumpcode.c
new file mode 100644
index 00000000..265a1c12
--- /dev/null
+++ b/src/target/firmware/calypso/dsp_dumpcode.c
@@ -0,0 +1,45 @@
+/* Generated from src/target_dsp/calypso/dsp_dump.bin */
+
+#define _SA_DECL (const uint16_t *)&(const uint16_t [])
+
+static const struct dsp_section dsp_dumpcode[] = {
+ {
+ .addr = 0x1000,
+ .size = 0x005b,
+ .data = _SA_DECL {
+ 0x69f8, 0x0029, 0x0002, 0xea1f,
+ 0x7718, 0x1100, 0x7714, 0x0000,
+ 0x7712, 0x0800, 0x767f, 0x0001,
+ 0x607f, 0xffff, 0xf820, 0x1014,
+ 0xf273, 0x1008, 0x7682, 0x0100,
+ 0x607f, 0x0004, 0xf820, 0x101c,
+ 0xf273, 0x1008, 0x7214, 0x0800,
+ 0x607f, 0x0002, 0xf820, 0x100c,
+ 0x127e, 0x8813, 0x3c7c, 0x137d,
+ 0x8911, 0xf84c, 0x1028, 0xf4e2,
+ 0x7715, 0x0014, 0x963d, 0xfa30,
+ 0x104b, 0x6d89, 0x963f, 0xfa30,
+ 0x103f, 0x963e, 0xf495, 0xf830,
+ 0x103a, 0x47f8, 0x0011, 0x7f92,
+ 0xf073, 0x1008, 0x47f8, 0x0011,
+ 0x7e92, 0xf073, 0x1008, 0xf830,
+ 0x1046, 0x47f8, 0x0011, 0xe589,
+ 0xf073, 0x1008, 0x47f8, 0x0011,
+ 0xe598, 0xf073, 0x1008, 0x4911,
+ 0x891a, 0xf830, 0x1055, 0xf072,
+ 0x1052, 0xf074, 0x7213, 0xf073,
+ 0x1008, 0xf072, 0x1058, 0xf074,
+ 0xe4b8, 0xf073, 0x1008,
+ },
+ },
+ { /* Guard */
+ .addr = 0,
+ .size = 0,
+ .data = NULL,
+ },
+};
+
+#define DSP_DUMPCODE_START 0x1000
+
+#undef _SA_DECL
+
diff --git a/src/target/firmware/calypso/dsp_params.c b/src/target/firmware/calypso/dsp_params.c
new file mode 100644
index 00000000..ec44a0ed
--- /dev/null
+++ b/src/target/firmware/calypso/dsp_params.c
@@ -0,0 +1,94 @@
+/* Values from an actual phone firmware that uses the 3306 DSP ROM code version */
+static T_PARAM_MCU_DSP dsp_params = {
+ .d_transfer_rate = 0x6666,
+ /* Latencies */
+ .d_lat_mcu_bridge = 15,
+ .d_lat_mcu_hom2sam = 12,
+ .d_lat_mcu_bef_fast_access = 5,
+ .d_lat_dsp_after_sam = 4,
+ /* DSP Start Address */
+ .d_gprs_install_address = 0x7002, /* needs to be set by patch or manually */
+ .d_misc_config = 1,
+ .d_cn_sw_workaround = 0xE,
+ .d_hole2_param = { 0, 0, 0, 0 },
+ /* Frequency Burst */
+ .d_fb_margin_beg = 24,
+ .d_fb_margin_end = 22,
+ .d_nsubb_idle = 296,
+ .d_nsubb_dedic = 30,
+ .d_fb_thr_det_iacq = 0x3333,
+ .d_fb_thr_det_track = 0x28f6,
+ /* Demodulation */
+ .d_dc_off_thres = 0x7fff,
+ .d_dummy_thres = 17408,
+ .d_dem_pond_gewl = 26624,
+ .d_dem_pond_red = 20152,
+ /* TCH Full Speech */
+ .d_maccthresh1 = 7872,
+ .d_mldt = -4,
+ .d_maccthresh = 7172,
+ .d_gu = 5772,
+ .d_go = 7872,
+ .d_attmax = 53,
+ .d_sm = -892,
+ .d_b = 208,
+ /* V.42 bis */
+ .d_v42b_switch_hyst = 16,
+ .d_v42b_switch_min = 64,
+ .d_v42b_switch_max = 250,
+ .d_v42b_reset_delay = 10,
+ /* TCH Half Speech */
+ .d_ldT_hr = -5,
+ .d_maccthresh_hr = 6500,
+ .d_maccthresh1_hr = 6500,
+ .d_gu_hr = 2620,
+ .d_go_hr = 3700,
+ .d_b_hr = 182,
+ .d_sm_hr = -1608,
+ .d_attmax_hr = 53,
+ /* TCH Enhanced FR Speech */
+ .c_mldt_efr = -4,
+ .c_maccthresh_efr = 8000,
+ .c_maccthresh1_efr = 8000,
+ .c_gu_efr = 4522,
+ .c_go_efr = 6500,
+ .c_b_efr = 174,
+ .c_sm_efr = -878,
+ .c_attmax_efr = 53,
+ /* CHED TCH Full Speech */
+ .d_sd_min_thr_tchfs = 15,
+ .d_ma_min_thr_tchfs = 738,
+ .d_md_max_thr_tchfs = 1700,
+ .d_md1_max_thr_tchfs = 99,
+ /* CHED TCH Half Speech */
+ .d_sd_min_thr_tchhs = 37,
+ .d_ma_min_thr_tchhs = 344,
+ .d_sd_av_thr_tchhs = 1845,
+ .d_md_max_thr_tchhs = 2175,
+ .d_md1_max_thr_tchhs = 138,
+ /* CHED TCH/F EFR Speech */
+ .d_sd_min_thr_tchefs = 15,
+ .d_ma_min_thr_tchefs = 738,
+ .d_md_max_thr_tchefs = 0x4ce,
+ .d_md1_max_thr_tchefs = 0x63,
+ /* */
+ .d_wed_fil_ini = 0x122a,
+ .d_wed_fil_tc = 0x7c00,
+ .d_x_min = 0xf,
+ .d_x_max = 0x17,
+ .d_slope = 0x87,
+ .d_y_min = 0x2bf,
+ .d_y_max = 0x99c,
+ .d_wed_diff_threshold = 0x196,
+ .d_mabfi_min_thr_tchhs = 0x14c8,
+ /* FACCH module */
+ .d_facch_thr = 0,
+ /* IDS module */
+ .d_max_ovsp_ul = 8,
+ .d_sync_thres = 0x3f50,
+ .d_idle_thres = 0x4000,
+ .d_m1_thres = 5,
+ .d_max_ovsp_dl = 8,
+ .d_gsm_bgd_mgt = 0,
+ /* we don't set the FIR coefficients !?! */
+};
diff --git a/src/target/firmware/calypso/du.c b/src/target/firmware/calypso/du.c
new file mode 100644
index 00000000..58783b06
--- /dev/null
+++ b/src/target/firmware/calypso/du.c
@@ -0,0 +1,51 @@
+/* Calypso DU (Debug Unit) Driver */
+
+/* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <memory.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <calypso/du.h>
+
+#define BASE_ADDR_DU 0x03c00000
+#define DU_REG(m) (BASE_ADDR_DU+(m))
+
+void calypso_du_init() {
+ unsigned char c;
+ calypso_debugunit(1);
+ for(c = 0; c < 64; c++) {
+ writew(DU_REG(c), 0x00000000);
+ }
+}
+
+void calypso_du_stop() {
+ calypso_debugunit(0);
+}
+
+void calypso_du_dump() {
+ unsigned char c;
+ puts("Debug unit traceback:\n");
+ for(c = 0; c < 64; c++) {
+ uint32_t w = readw(DU_REG(c));
+ printf("t-%2x: 0x%8x\n", c, (unsigned int)w);
+ }
+}
diff --git a/src/target/firmware/calypso/i2c.c b/src/target/firmware/calypso/i2c.c
new file mode 100644
index 00000000..a46fd72a
--- /dev/null
+++ b/src/target/firmware/calypso/i2c.c
@@ -0,0 +1,123 @@
+/* Driver for I2C Master Controller inside TI Calypso */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <i2c.h>
+
+#define BASE_ADDR_I2C 0xfffe2800
+#define I2C_REG(x) (BASE_ADDR_I2C+(x))
+
+enum i2c_reg {
+ DEVICE_REG = 0,
+ ADDRESS_REG,
+ DATA_WR_REG,
+ DATA_RD_REG,
+ CMD_REG,
+ CONF_FIFO_REG,
+ CONF_CLK_REG,
+ CONF_CLK_FUNC_REF,
+ STATUS_FIFO_REG,
+ STATUS_ACTIVITY_REG,
+};
+
+#define I2C_CMD_SOFT_RESET (1 << 0)
+#define I2C_CMD_EN_CLK (1 << 1)
+#define I2C_CMD_START (1 << 2)
+#define I2C_CMD_RW_READ (1 << 3)
+#define I2C_CMD_COMP_READ (1 << 4)
+#define I2C_CMD_IRQ_ENABLE (1 << 5)
+
+#define I2C_STATUS_ERROR_DATA (1 << 0)
+#define I2C_STATUS_ERROR_DEV (1 << 1)
+#define I2C_STATUS_IDLE (1 << 2)
+#define I2C_STATUS_INTERRUPT (1 << 3)
+
+int i2c_write(uint8_t chip, uint32_t addr, int alen, const uint8_t *buffer, int len)
+{
+ uint8_t cmd;
+
+ /* Calypso I2C controller doesn't support fancy addressing */
+ if (alen > 1)
+ return -1;
+
+ /* FIXME: implement writes longer than fifo size */
+ if (len > 16)
+ return -1;
+
+ printd("i2c_write(chip=0x%02u, addr=0x%02u): ", chip, addr)
+
+ writeb(chip & 0x3f, I2C_REG(DEVICE_REG));
+ writeb(addr & 0xff, I2C_REG(ADDRESS_REG));
+
+ /* we have to tell the controler how many bits we'll put into the fifo ?!? */
+ writeb(len-1, I2C_REG(CONF_FIFO_REG));
+
+ /* fill the FIFO */
+ while (len--) {
+ uint8_t byte = *buffer++;
+ writeb(byte, I2C_REG(DATA_WR_REG));
+ printd("%02X ", byte);
+ }
+ dputchar('\n');
+
+ /* start the transfer */
+ cmd = readb(I2C_REG(CMD_REG));
+ cmd |= I2C_CMD_START;
+ writeb(cmd, I2C_REG(CMD_REG));
+
+ /* wait until transfer completes */
+ while (1) {
+ uint8_t reg = readb(I2C_REG(STATUS_ACTIVITY_REG));
+ printd("I2C Status: 0x%02x\n", rerg & 0xf);
+ if (reg & I2C_STATUS_IDLE)
+ break;
+ }
+ dputs("I2C transfer completed\n");
+
+ return 0;
+}
+
+void i2c_init(int speed, int slaveadd)
+{
+ /* scl_out = clk_func_ref / 3,
+ clk_func_ref = master_clock_freq / (divisor_2 + 1)
+ master_clock_freq = ext_clock_freq / divisor_1 */
+ /* clk_func_ref = scl_out * 3,
+ divisor_2 = (master_clock_freq / clk_func_ref) - 1
+ divisor_1 = ext_clock_freq / master_clock_freq */
+ /* for a target freq of 200kHz:
+ ext_clock_freq = 13MHz
+ clk_func_ref = 3 * 300kHZ = 600kHz
+ divisor_1 = 1 => master_clock_freq = ext_clock_freq = 13MHz
+ divisor_2 = 21 => clk_func_ref = 13MHz / (21+2) = 590.91 kHz
+ scl_out = clk_func_ref / 3 = 509.91 kHz / 3 = 196.97kHz */
+ writeb(I2C_CMD_SOFT_RESET, I2C_REG(CMD_REG));
+
+ writeb(0x00, I2C_REG(CONF_CLK_REG));
+ writeb(21, I2C_REG(CONF_CLK_FUNC_REF));
+
+ writeb(I2C_CMD_EN_CLK, I2C_REG(CMD_REG));
+}
diff --git a/src/target/firmware/calypso/irq.c b/src/target/firmware/calypso/irq.c
new file mode 100644
index 00000000..d019918d
--- /dev/null
+++ b/src/target/firmware/calypso/irq.c
@@ -0,0 +1,266 @@
+/* Driver for Calypso IRQ controller */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <arm.h>
+#include <calypso/irq.h>
+
+#define BASE_ADDR_IRQ 0xfffffa00
+
+enum irq_reg {
+ IT_REG1 = 0x00,
+ IT_REG2 = 0x02,
+ MASK_IT_REG1 = 0x08,
+ MASK_IT_REG2 = 0x0a,
+ IRQ_NUM = 0x10,
+ FIQ_NUM = 0x12,
+ IRQ_CTRL = 0x14,
+};
+
+#define ILR_IRQ(x) (0x20 + (x*2))
+#define IRQ_REG(x) ((void *)BASE_ADDR_IRQ + (x))
+
+#define NR_IRQS 32
+
+static uint8_t default_irq_prio[] = {
+ [IRQ_WATCHDOG] = 0xff,
+ [IRQ_TIMER1] = 0xff,
+ [IRQ_TIMER2] = 0xff,
+ [IRQ_TSP_RX] = 0,
+ [IRQ_TPU_FRAME] = 3,
+ [IRQ_TPU_PAGE] = 0xff,
+ [IRQ_SIMCARD] = 0xff,
+ [IRQ_UART_MODEM] = 8,
+ [IRQ_KEYPAD_GPIO] = 4,
+ [IRQ_RTC_TIMER] = 9,
+ [IRQ_RTC_ALARM_I2C] = 10,
+ [IRQ_ULPD_GAUGING] = 2,
+ [IRQ_EXTERNAL] = 12,
+ [IRQ_SPI] = 0xff,
+ [IRQ_DMA] = 0xff,
+ [IRQ_API] = 0xff,
+ [IRQ_SIM_DETECT] = 0,
+ [IRQ_EXTERNAL_FIQ] = 7,
+ [IRQ_UART_IRDA] = 2,
+ [IRQ_ULPD_GSM_TIMER] = 1,
+ [IRQ_GEA] = 0xff,
+};
+
+static irq_handler *irq_handlers[NR_IRQS];
+
+static void _irq_enable(enum irq_nr nr, int enable)
+{
+ uint16_t *reg = IRQ_REG(MASK_IT_REG1);
+ uint16_t val;
+
+ if (nr > 15) {
+ reg = IRQ_REG(MASK_IT_REG2);
+ nr -= 16;
+ }
+
+ val = readw(reg);
+ if (enable)
+ val &= ~(1 << nr);
+ else
+ val |= (1 << nr);
+ writew(val, reg);
+}
+
+void irq_enable(enum irq_nr nr)
+{
+ _irq_enable(nr, 1);
+}
+
+void irq_disable(enum irq_nr nr)
+{
+ _irq_enable(nr, 0);
+}
+
+void irq_config(enum irq_nr nr, int fiq, int edge, int8_t prio)
+{
+ uint16_t val;
+
+ if (prio == -1)
+ prio = default_irq_prio[nr];
+
+ if (prio > 31)
+ prio = 31;
+
+ val = prio << 2;
+ if (edge)
+ val |= 0x02;
+ if (fiq)
+ val |= 0x01;
+
+ writew(val, IRQ_REG(ILR_IRQ(nr)));
+}
+
+/* Entry point for interrupts */
+void irq(void)
+{
+ uint8_t num, tmp;
+ irq_handler *handler;
+
+#if 1
+ /* Hardware interrupt detection mode */
+ num = readb(IRQ_REG(IRQ_NUM)) & 0x1f;
+
+ printd("i%02x\n", num);
+
+ handler = irq_handlers[num];
+
+ if (handler)
+ handler(num);
+#else
+ /* Software interrupt detection mode */
+ {
+ uint16_t it_reg, mask_reg;
+ uint32_t irqs;
+
+ it_reg = readw(IRQ_REG(IT_REG1));
+ mask_reg = readw(IRQ_REG(MASK_IT_REG1));
+ irqs = it_reg & ~mask_reg;
+
+ it_reg = readw(IRQ_REG(IT_REG2));
+ mask_reg = readw(IRQ_REG(MASK_IT_REG2));
+ irqs |= (it_reg & ~mask_reg) << 16;
+
+ for (num = 0; num < 32; num++) {
+ if (irqs & (1 << num)) {
+ printd("i%d\n", num);
+ handler = irq_handlers[num];
+ if (handler)
+ handler(num);
+ /* clear this interrupt */
+ if (num < 16)
+ writew(~(1 << num), IRQ_REG(IT_REG1));
+ else
+ writew(~(1 << (num-16)), IRQ_REG(IT_REG2));
+ }
+ }
+ dputchar('\n');
+ }
+#endif
+ /* Start new IRQ agreement */
+ tmp = readb(IRQ_REG(IRQ_CTRL));
+ tmp |= 0x01;
+ writeb(tmp, IRQ_REG(IRQ_CTRL));
+}
+
+/* Entry point for FIQs */
+void fiq(void)
+{
+ uint8_t num, tmp;
+ irq_handler *handler;
+
+ num = readb(IRQ_REG(FIQ_NUM)) & 0x1f;
+ if (num) {
+ printd("f%02x\n", num);
+ }
+
+ handler = irq_handlers[num];
+
+ if (handler)
+ handler(num);
+
+ /* Start new FIQ agreement */
+ tmp = readb(IRQ_REG(IRQ_CTRL));
+ tmp |= 0x02;
+ writeb(tmp, IRQ_REG(IRQ_CTRL));
+}
+
+void irq_register_handler(enum irq_nr nr, irq_handler *handler)
+{
+ if (nr > NR_IRQS)
+ return;
+
+ irq_handlers[nr] = handler;
+}
+
+#define BASE_ADDR_IBOOT_EXC 0x0080001C
+extern uint32_t _exceptions;
+
+/* Install the exception handlers to where the ROM loader jumps */
+void calypso_exceptions_install(void)
+{
+ uint32_t *exceptions_dst = (uint32_t *) BASE_ADDR_IBOOT_EXC;
+ uint32_t *exceptions_src = &_exceptions;
+ int i;
+
+ for (i = 0; i < 7; i++)
+ *exceptions_dst++ = *exceptions_src++;
+
+}
+
+static void set_default_priorities(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(default_irq_prio); i++) {
+ uint16_t val;
+ uint8_t prio = default_irq_prio[i];
+ if (prio > 31)
+ prio = 31;
+
+ val = readw(IRQ_REG(ILR_IRQ(i)));
+ val &= ~(0x1f << 2);
+ val |= prio << 2;
+ writew(val, IRQ_REG(ILR_IRQ(i)));
+ }
+}
+
+static uint32_t irq_nest_mask;
+/* mask off all interrupts that have a lower priority than irq_nr */
+static void mask_all_lower_prio_irqs(enum irq_nr irq)
+{
+ uint8_t our_prio = readb(IRQ_REG(ILR_IRQ(irq))) >> 2;
+ int i;
+
+ for (i = 0; i < _NR_IRQ; i++) {
+ uint8_t prio;
+
+ if (i == irq)
+ continue;
+
+ prio = readb(IRQ_REG(ILR_IRQ(i))) >> 2;
+ if (prio >= our_prio)
+ irq_nest_mask |= (1 << i);
+ }
+}
+
+void irq_init(void)
+{
+ /* set default priorities */
+ set_default_priorities();
+ /* mask all interrupts off */
+ writew(0xffff, IRQ_REG(MASK_IT_REG1));
+ writew(0xffff, IRQ_REG(MASK_IT_REG2));
+ /* clear all pending interrupts */
+ writew(0, IRQ_REG(IT_REG1));
+ writew(0, IRQ_REG(IT_REG2));
+ /* enable interrupts globally to the ARM core */
+ arm_enable_interrupts();
+}
diff --git a/src/target/firmware/calypso/keypad.c b/src/target/firmware/calypso/keypad.c
new file mode 100644
index 00000000..27f48c0b
--- /dev/null
+++ b/src/target/firmware/calypso/keypad.c
@@ -0,0 +1,165 @@
+/* Driver for the keypad attached to the TI Calypso */
+
+/* (C) 2010 by roh <roh@hyte.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <keypad.h>
+
+#include <calypso/irq.h>
+#include <abb/twl3025.h>
+
+
+#define KBR_LATCH_REG 0xfffe480a
+#define KBC_REG 0xfffe480c
+#define KBD_GPIO_INT 0xfffe4816
+#define KBD_GPIO_MASKIT 0xfffe4818
+
+static key_handler_t key_handler = NULL;
+
+void emit_key(uint8_t key, uint8_t state)
+{
+ printf("key=%u %s\n", key, state == PRESSED ? "pressed" : "released");
+
+ if (state == RELEASED)
+ if (key == KEY_POWER)
+ twl3025_power_off();
+
+ if(key_handler) {
+ key_handler(key, state);
+ }
+}
+
+volatile uint32_t lastbuttons;
+
+#define BTN_TO_KEY(name) \
+ ((diff & BTN_##name) == BTN_##name) \
+ { \
+ key = KEY_##name; \
+ diff = diff & ~BTN_##name; \
+ }
+
+void dispatch_buttons(uint32_t buttons)
+{
+ uint8_t state;
+
+ if (buttons == lastbuttons)
+ return;
+
+ if (buttons > lastbuttons)
+ state = PRESSED;
+ else
+ state = RELEASED;
+
+ uint32_t diff = buttons ^ lastbuttons;
+ uint8_t key=KEY_INV;
+
+ while (diff != 0)
+ {
+ if BTN_TO_KEY(POWER)
+ else if BTN_TO_KEY(0)
+ else if BTN_TO_KEY(1)
+ else if BTN_TO_KEY(2)
+ else if BTN_TO_KEY(3)
+ else if BTN_TO_KEY(4)
+ else if BTN_TO_KEY(5)
+ else if BTN_TO_KEY(6)
+ else if BTN_TO_KEY(7)
+ else if BTN_TO_KEY(8)
+ else if BTN_TO_KEY(9)
+ else if BTN_TO_KEY(STAR)
+ else if BTN_TO_KEY(HASH)
+ else if BTN_TO_KEY(MENU)
+ else if BTN_TO_KEY(LEFT_SB)
+ else if BTN_TO_KEY(RIGHT_SB)
+ else if BTN_TO_KEY(UP)
+ else if BTN_TO_KEY(DOWN)
+ else if BTN_TO_KEY(LEFT)
+ else if BTN_TO_KEY(RIGHT)
+ else if BTN_TO_KEY(OK)
+ else
+ {
+ printf("\nunknown keycode: 0x%08x\n", diff);
+ break;
+ }
+ if ( key == KEY_POWER )
+ diff = 0;
+ emit_key(key, state);
+ }
+ lastbuttons = buttons;
+}
+
+static void keypad_irq(enum irq_nr nr)
+{
+ keypad_scan();
+}
+
+void keypad_init()
+{
+ lastbuttons = 0;
+ writew(0, KBD_GPIO_MASKIT);
+ writew(0, KBC_REG);
+
+ irq_register_handler(IRQ_KEYPAD_GPIO, &keypad_irq);
+ irq_config(IRQ_KEYPAD_GPIO, 0, 0, 0);
+ irq_enable(IRQ_KEYPAD_GPIO);
+}
+
+void keypad_set_handler(key_handler_t handler)
+{
+ key_handler = handler;
+}
+
+void keypad_scan()
+{
+ uint16_t reg;
+ uint16_t col;
+ uint32_t buttons;
+
+// putchar('\n');
+ buttons = 0x0;
+ //scan for BTN_POWER
+ writew(0xff, KBC_REG);
+ delay_ms(1);
+ reg = readw(KBR_LATCH_REG);
+// printd("%02x ", (~reg & 0x1f));
+ buttons = buttons | ((~reg & 0x1f) << 20 );
+
+ //scan for muxed keys if not powerbtn
+ if ((~reg & 0x1f) != 0x10)
+ for (col=0;col<4;col++)
+ {
+ writew(0x1f & ~(0x1 << col ), KBC_REG);
+ delay_ms(1);
+ reg = readw(KBR_LATCH_REG);
+ buttons = buttons | ((~reg & 0x1f) << (col * 5 ));
+// printd("%02x ", (~reg & 0x1f));
+ }
+ //enable keypad irq via master 'or' gate (needs col lines low in idle to work)
+ writew(0, KBC_REG);
+ dispatch_buttons(buttons);
+
+}
+
diff --git a/src/target/firmware/calypso/misc.c b/src/target/firmware/calypso/misc.c
new file mode 100644
index 00000000..460cc5d5
--- /dev/null
+++ b/src/target/firmware/calypso/misc.c
@@ -0,0 +1,60 @@
+
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+
+/* dump a memory range */
+void memdump_range(unsigned int *ptr, unsigned int len)
+{
+ unsigned int *end = ptr + (len/4);
+ unsigned int *tmp;
+
+ for (tmp = ptr; tmp < end; tmp += 8) {
+ int i;
+ printf("%08X: ", (unsigned int) tmp);
+
+ for (i = 0; i < 8; i++)
+ printf("%08X %s", *(tmp+i), i == 3 ? " " : "");
+
+ putchar('\n');
+ }
+}
+
+#define KBIT 1024
+#define MBIT (1024*KBIT)
+void dump_mem(void)
+{
+ puts("Dump 64kBits of internal ROM\n");
+ memdump_range((void *)0x03800000, 64*KBIT/8);
+
+ puts("Dump 8Mbits of external flash\n");
+ memdump_range((void *)0x00000000, 8*MBIT/8);
+
+ puts("Dump 2Mbits of internal RAM\n");
+ memdump_range((void *)0x00800000, 2*MBIT/8);
+
+ puts("Dump 2Mbits of external RAM\n");
+ memdump_range((void *)0x01000000, 2*MBIT/8);
+}
+
+#define REG_DEV_ID_CODE 0xfffef000
+#define REG_DEV_VER_CODE 0xfffef002
+#define REG_DEV_ARMVER_CODE 0xfffffe00
+#define REG_cDSP_ID_CODE 0xfffffe02
+#define REG_DIE_ID_CODE 0xfffef010
+
+void dump_dev_id(void)
+{
+ int i;
+
+ printf("Device ID code: 0x%04x\n", readw(REG_DEV_ID_CODE));
+ printf("Device Version code: 0x%04x\n", readw(REG_DEV_VER_CODE));
+ printf("ARM ID code: 0x%04x\n", readw(REG_DEV_ARMVER_CODE));
+ printf("cDSP ID code: 0x%04x\n", readw(REG_cDSP_ID_CODE));
+ puts("Die ID code: ");
+ for (i = 0; i < 64/8; i += 4)
+ printf("%08x", readl(REG_DIE_ID_CODE+i));
+ putchar('\n');
+}
+
+
diff --git a/src/target/firmware/calypso/rtc.c b/src/target/firmware/calypso/rtc.c
new file mode 100644
index 00000000..afa3824b
--- /dev/null
+++ b/src/target/firmware/calypso/rtc.c
@@ -0,0 +1,82 @@
+/* Driver for Calypso RTC controller */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <calypso/irq.h>
+#include <display/st7558.h>
+
+#define BASE_ADDR_RTC 0xfffe1800
+#define RTC_REG(x) ((void *)BASE_ADDR_RTC + (x))
+
+enum rtc_reg {
+ SECOND_REG = 0x00,
+ MINUTES_REG = 0x01,
+ HOURS_REG = 0x02,
+ DAYS_REG = 0x03,
+ MONTHS_REG = 0x04,
+ YEARS_REG = 0x05,
+ WEEK_REG = 0x06,
+ /* reserved */
+ ALARM_SECOND_REG = 0x08,
+ ALARM_MINUTES_REG = 0x09,
+ ALARM_HOURS_REG = 0x0a,
+ ALARM_DAYS_REG = 0x0b,
+ ALARM_MONTHS_REG = 0x0c,
+ ALARM_YEARS_REG = 0x0d,
+ /* reserved */
+ /* reserved */
+ CTRL_REG = 0x10,
+ STATUS_REG = 0x11,
+ INT_REG = 0x12,
+ COMP_LSB_REG = 0x13,
+ COMP_MSB_REG = 0x14,
+ RES_PROG_REG = 0x15,
+};
+
+static int tick_ctr;
+
+static void rtc_irq_tick(enum irq_nr nr)
+{
+ if (tick_ctr & 1)
+ st7558_set_attr(DISP_ATTR_INVERT);
+ else
+ st7558_unset_attr(DISP_ATTR_INVERT);
+ tick_ctr++;
+}
+
+void rtc_init(void)
+{
+ irq_register_handler(IRQ_RTC_TIMER, &rtc_irq_tick);
+ irq_config(IRQ_RTC_TIMER, 0, 1, 0);
+ irq_enable(IRQ_RTC_TIMER);
+
+ /* clear power-up reset */
+ writeb(0x80, RTC_REG(STATUS_REG));
+ /* enable RTC running */
+ writeb(0x01, RTC_REG(CTRL_REG));
+ /* enable periodic interrupts every second */
+ writeb(0x04, RTC_REG(INT_REG));
+}
diff --git a/src/target/firmware/calypso/spi.c b/src/target/firmware/calypso/spi.c
new file mode 100644
index 00000000..049ac080
--- /dev/null
+++ b/src/target/firmware/calypso/spi.c
@@ -0,0 +1,141 @@
+/* Driver for SPI Master Controller inside TI Calypso */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+//#define DEBUG
+#include <debug.h>
+
+#include <memory.h>
+#include <spi.h>
+#include <delay.h>
+
+#define BASE_ADDR_SPI 0xfffe3000
+#define SPI_REG(n) (BASE_ADDR_SPI+(n))
+
+enum spi_regs {
+ REG_SET1 = 0x00,
+ REG_SET2 = 0x02,
+ REG_CTRL = 0x04,
+ REG_STATUS = 0x06,
+ REG_TX_LSB = 0x08,
+ REG_TX_MSB = 0x0a,
+ REG_RX_LSB = 0x0c,
+ REG_RX_MSB = 0x0e,
+};
+
+#define SPI_SET1_EN_CLK (1 << 0)
+#define SPI_SET1_WR_IRQ_DIS (1 << 4)
+#define SPI_SET1_RDWR_IRQ_DIS (1 << 5)
+
+#define SPI_CTRL_RDWR (1 << 0)
+#define SPI_CTRL_WR (1 << 1)
+#define SPI_CTRL_NB_SHIFT 2
+#define SPI_CTRL_AD_SHIFT 7
+
+#define SPI_STATUS_RE (1 << 0) /* Read End */
+#define SPI_STATUS_WE (1 << 1) /* Write End */
+
+void spi_init(void)
+{
+ writew(SPI_SET1_EN_CLK | SPI_SET1_WR_IRQ_DIS | SPI_SET1_RDWR_IRQ_DIS,
+ SPI_REG(REG_SET1));
+
+ writew(0x0001, SPI_REG(REG_SET2));
+}
+
+int spi_xfer(uint8_t dev_idx, uint8_t bitlen, const void *dout, void *din)
+{
+ uint8_t bytes_per_xfer;
+ uint8_t reg_status, reg_ctrl = 0;
+ uint32_t tmp;
+
+ if (bitlen == 0)
+ return 0;
+
+ if (bitlen > 32)
+ return -1;
+
+ if (dev_idx > 4)
+ return -1;
+
+ bytes_per_xfer = bitlen / 8;
+ if (bitlen % 8)
+ bytes_per_xfer ++;
+
+ reg_ctrl |= (bitlen - 1) << SPI_CTRL_NB_SHIFT;
+ reg_ctrl |= (dev_idx & 0x7) << SPI_CTRL_AD_SHIFT;
+
+ if (bitlen <= 8) {
+ tmp = *(uint8_t *)dout;
+ tmp <<= 24 + (8-bitlen); /* align to MSB */
+ } else if (bitlen <= 16) {
+ tmp = *(uint16_t *)dout;
+ tmp <<= 16 + (16-bitlen); /* align to MSB */
+ } else {
+ tmp = *(uint32_t *)dout;
+ tmp <<= (32-bitlen); /* align to MSB */
+ }
+ printd("spi_xfer(dev_idx=%u, bitlen=%u, data_out=0x%08x): ",
+ dev_idx, bitlen, tmp);
+
+ /* fill transmit registers */
+ writew(tmp >> 16, SPI_REG(REG_TX_MSB));
+ writew(tmp & 0xffff, SPI_REG(REG_TX_LSB));
+
+ /* initiate transfer */
+ if (din)
+ reg_ctrl |= SPI_CTRL_RDWR;
+ else
+ reg_ctrl |= SPI_CTRL_WR;
+ writew(reg_ctrl, SPI_REG(REG_CTRL));
+ printd("reg_ctrl=0x%04x ", reg_ctrl);
+
+ /* wait until the transfer is complete */
+ while (1) {
+ reg_status = readw(SPI_REG(REG_STATUS));
+ printd("status=0x%04x ", reg_status);
+ if (din && (reg_status & SPI_STATUS_RE))
+ break;
+ else if (reg_status & SPI_STATUS_WE)
+ break;
+ }
+ /* FIXME: calibrate how much delay we really need (seven 13MHz cycles) */
+ delay_ms(1);
+
+ if (din) {
+ tmp = readw(SPI_REG(REG_RX_MSB)) << 16;
+ tmp |= readw(SPI_REG(REG_RX_LSB));
+ printd("data_in=0x%08x ", tmp);
+
+ if (bitlen <= 8)
+ *(uint8_t *)din = tmp & 0xff;
+ else if (bitlen <= 16)
+ *(uint16_t *)din = tmp & 0xffff;
+ else
+ *(uint32_t *)din = tmp;
+ }
+ dputchar('\n');
+
+ return 0;
+}
diff --git a/src/target/firmware/calypso/timer.c b/src/target/firmware/calypso/timer.c
new file mode 100644
index 00000000..050c7c93
--- /dev/null
+++ b/src/target/firmware/calypso/timer.c
@@ -0,0 +1,127 @@
+/* Calypso DBB internal Timer Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <memory.h>
+#include <stdint.h>
+
+#include <calypso/timer.h>
+#include <calypso/irq.h>
+
+#define BASE_ADDR_TIMER 0xfffe3800
+#define TIMER2_OFFSET 0x3000
+
+#define TIMER_REG(n, m) (((n)-1) ? (BASE_ADDR_TIMER + TIMER2_OFFSET + (m)) : (BASE_ADDR_TIMER + (m)))
+
+enum timer_reg {
+ CNTL_TIMER = 0x00,
+ LOAD_TIMER = 0x02,
+ READ_TIMER = 0x04,
+};
+
+enum timer_ctl {
+ CNTL_START = (1 << 0),
+ CNTL_AUTO_RELOAD = (1 << 1),
+ CNTL_CLOCK_ENABLE = (1 << 5),
+};
+
+/* Regular Timers (1 and 2) */
+
+void hwtimer_enable(int num, int on)
+{
+ uint8_t ctl;
+
+ if (num < 1 || num > 2) {
+ printf("Unknown timer %u\n", num);
+ return;
+ }
+
+ ctl = readb(TIMER_REG(num, CNTL_TIMER));
+ if (on)
+ ctl |= CNTL_START|CNTL_CLOCK_ENABLE;
+ else
+ ctl &= ~CNTL_START;
+ writeb(ctl, TIMER_REG(num, CNTL_TIMER));
+}
+
+void hwtimer_config(int num, uint8_t pre_scale, int auto_reload)
+{
+ uint8_t ctl;
+
+ ctl = (pre_scale & 0x7) << 2;
+ if (auto_reload)
+ ctl |= CNTL_AUTO_RELOAD;
+
+ writeb(ctl, TIMER_REG(num, CNTL_TIMER));
+}
+
+void hwtimer_load(int num, uint16_t val)
+{
+ writew(val, TIMER_REG(num, LOAD_TIMER));
+}
+
+uint16_t hwtimer_read(int num)
+{
+ uint8_t ctl = readb(TIMER_REG(num, CNTL_TIMER));
+
+ /* somehow a read results in an abort */
+ if ((ctl & (CNTL_START|CNTL_CLOCK_ENABLE)) != (CNTL_START|CNTL_CLOCK_ENABLE))
+ return 0xFFFF;
+ return readw(TIMER_REG(num, READ_TIMER));
+}
+
+void hwtimer_init(void)
+{
+ writeb(CNTL_CLOCK_ENABLE, TIMER_REG(1, CNTL_TIMER));
+ writeb(CNTL_CLOCK_ENABLE, TIMER_REG(2, CNTL_TIMER));
+}
+
+/* Watchdog Timer */
+
+#define BASE_ADDR_WDOG 0xfffff800
+#define WDOG_REG(m) (BASE_ADDR_WDOG + m)
+
+enum wdog_reg {
+ WD_CNTL_TIMER = CNTL_TIMER,
+ WD_LOAD_TIMER = LOAD_TIMER,
+ WD_READ_TIMER = 0x02,
+ WD_MODE = 0x04,
+};
+
+static void wdog_irq(enum irq_nr nr)
+{
+ puts("=> WATCHDOG\n");
+}
+
+void wdog_enable(int on)
+{
+ if (on) {
+ irq_config(IRQ_WATCHDOG, 0, 0, 0);
+ irq_register_handler(IRQ_WATCHDOG, &wdog_irq);
+ irq_enable(IRQ_WATCHDOG);
+ writew(0x8000, WDOG_REG(WD_MODE));
+ } else {
+ writew(0xF5, WDOG_REG(WD_MODE));
+ writew(0xA0, WDOG_REG(WD_MODE));
+ }
+}
+
diff --git a/src/target/firmware/calypso/tpu.c b/src/target/firmware/calypso/tpu.c
new file mode 100644
index 00000000..f0172e2e
--- /dev/null
+++ b/src/target/firmware/calypso/tpu.c
@@ -0,0 +1,288 @@
+/* Calypso DBB internal TPU (Time Processing Unit) Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+
+#define BASE_ADDR_TPU 0xffff1000
+#define TPU_REG(x) (BASE_ADDR_TPU+(x))
+
+#define BASE_ADDR_TPU_RAM 0xffff9000
+#define TPU_RAM_END 0xffff97ff
+
+enum tpu_reg_arm {
+ TPU_CTRL = 0x0, /* Control & Status Register */
+ INT_CTRL = 0x2, /* Interrupt Control Register */
+ INT_STAT = 0x4, /* Interrupt Status Register */
+ TPU_OFFSET = 0xC, /* Offset operand value register */
+ TPU_SYNCHRO = 0xE, /* synchro operand value register */
+ IT_DSP_PG = 0x20,
+};
+
+enum tpu_ctrl_bits {
+ TPU_CTRL_RESET = (1 << 0),
+ TPU_CTRL_PAGE = (1 << 1),
+ TPU_CTRL_EN = (1 << 2),
+ /* unused */
+ TPU_CTRL_DSP_EN = (1 << 4),
+ /* unused */
+ TPU_CTRL_MCU_RAM_ACC = (1 << 6),
+ TPU_CTRL_TSP_RESET = (1 << 7),
+ TPU_CTRL_IDLE = (1 << 8),
+ TPU_CTRL_WAIT = (1 << 9),
+ TPU_CTRL_CK_ENABLE = (1 << 10),
+ TPU_CTRL_FULL_WRITE = (1 << 11),
+};
+
+enum tpu_int_ctrl_bits {
+ ICTRL_MCU_FRAME = (1 << 0),
+ ICTRL_MCU_PAGE = (1 << 1),
+ ICTRL_DSP_FRAME = (1 << 2),
+ ICTRL_DSP_FRAME_FORCE = (1 << 3),
+};
+
+#define BIT_SET 1
+#define BIT_CLEAR 0
+
+/* wait for a certain control bit to be set */
+static int tpu_wait_ctrl_bit(uint16_t bit, int set)
+{
+ int timeout = 10*1000;
+
+ while (1) {
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+ if (set) {
+ if (reg & bit)
+ break;
+ } else {
+ if (!(reg & bit))
+ break;
+ }
+ timeout--;
+ if (timeout <= 0) {
+ puts("Timeout while waiting for TPU ctrl bit!\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* assert or de-assert TPU reset */
+void tpu_reset(int active)
+{
+ uint16_t reg;
+
+ printd("tpu_reset(%u)\n", active);
+ reg = readw(TPU_REG(TPU_CTRL));
+ if (active) {
+ reg |= (TPU_CTRL_RESET|TPU_CTRL_TSP_RESET);
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_RESET, BIT_SET);
+ } else {
+ reg &= ~(TPU_CTRL_RESET|TPU_CTRL_TSP_RESET);
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_RESET, BIT_CLEAR);
+ }
+}
+
+/* Enable or Disable a new scenario loaded into the TPU */
+void tpu_enable(int active)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+
+ printd("tpu_enable(%u)\n", active);
+ if (active)
+ reg |= TPU_CTRL_EN;
+ else
+ reg &= ~TPU_CTRL_EN;
+ writew(reg, TPU_REG(TPU_CTRL));
+
+ /* After the new scenario is loaded, TPU switches the MCU-visible memory
+ * page, i.e. we can write without any danger */
+ tpu_rewind();
+#if 0
+ {
+ int i;
+ uint16_t oldreg = 0;
+
+ for (i = 0; i < 100000; i++) {
+ reg = readw(TPU_REG(TPU_CTRL));
+ if (i == 0 || oldreg != reg) {
+ printd("%d TPU state: 0x%04x\n", i, reg);
+ }
+ oldreg = reg;
+ }
+ }
+#endif
+}
+
+/* Enable or Disable the clock of teh TPU Module */
+void tpu_clk_enable(int active)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+
+ printd("tpu_clk_enable(%u)\n", active);
+ if (active) {
+ reg |= TPU_CTRL_CK_ENABLE;
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_CK_ENABLE, BIT_SET);
+ } else {
+ reg &= ~TPU_CTRL_CK_ENABLE;
+ writew(reg, TPU_REG(TPU_CTRL));
+ tpu_wait_ctrl_bit(TPU_CTRL_CK_ENABLE, BIT_CLEAR);
+ }
+}
+
+/* Enable Frame Interrupt generation on next frame. DSP will reset it */
+void tpu_dsp_frameirq_enable(void)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+ reg |= TPU_CTRL_DSP_EN;
+ writew(reg, TPU_REG(TPU_CTRL));
+
+ tpu_wait_ctrl_bit(TPU_CTRL_DSP_EN, BIT_SET);
+}
+
+/* Is a Frame interrupt still pending for the DSP ? */
+int tpu_dsp_fameirq_pending(void)
+{
+ uint16_t reg = readw(TPU_REG(TPU_CTRL));
+
+ if (reg & TPU_CTRL_DSP_EN)
+ return 1;
+
+ return 0;
+}
+
+static uint16_t *tpu_ptr;
+
+void tpu_rewind(void)
+{
+ dputs("tpu_rewind()\n");
+ tpu_ptr = (uint16_t *) BASE_ADDR_TPU_RAM;
+}
+
+void tpu_enqueue(uint16_t instr)
+{
+ printd("tpu_enqueue(tpu_ptr=%p, instr=0x%04x\n", tpu_ptr, instr);
+ *tpu_ptr++ = instr;
+ if (tpu_ptr > (uint16_t *) TPU_RAM_END)
+ puts("TPU enqueue beyond end of TPU memory\n");
+}
+
+void tpu_init(void)
+{
+ /* Get TPU out of reset */
+ tpu_reset(1);
+ tpu_clk_enable(1);
+ tpu_reset(0);
+ /* Disable all interrupts */
+ writeb(0x7, TPU_REG(INT_CTRL));
+
+ tpu_rewind();
+ tpu_enq_offset(0);
+ tpu_enq_sync(0);
+}
+
+void tpu_test(void)
+{
+ int i;
+
+ /* program a sequence of TSPACT events into the TPU */
+ for (i = 0; i < 10; i++) {
+ puts("TSP ACT enable: ");
+ tsp_act_enable(0x0001);
+ tpu_enq_wait(10);
+ puts("TSP ACT disable: ");
+ tsp_act_disable(0x0001);
+ tpu_enq_wait(10);
+ }
+ tpu_enq_sleep();
+
+ /* tell the chip to execute the scenario */
+ tpu_enable(1);
+}
+
+void tpu_wait_idle(void)
+{
+ dputs("Waiting for TPU Idle ");
+ /* Wait until TPU is doing something */
+ delay_us(3);
+ /* Wait until TPU is idle */
+ while (readw(TPU_REG(TPU_CTRL)) & TPU_CTRL_IDLE)
+ dputchar('.');
+ dputs("Done!\n");
+}
+
+void tpu_frame_irq_en(int mcu, int dsp)
+{
+ uint8_t reg = readb(TPU_REG(INT_CTRL));
+ if (mcu)
+ reg &= ~ICTRL_MCU_FRAME;
+ else
+ reg |= ICTRL_MCU_FRAME;
+
+ if (dsp)
+ reg &= ~ICTRL_DSP_FRAME;
+ else
+ reg |= ICTRL_DSP_FRAME;
+
+ writeb(reg, TPU_REG(INT_CTRL));
+}
+
+void tpu_force_dsp_frame_irq(void)
+{
+ uint8_t reg = readb(TPU_REG(INT_CTRL));
+ reg |= ICTRL_DSP_FRAME_FORCE;
+ writeb(reg, TPU_REG(INT_CTRL));
+}
+
+uint16_t tpu_get_offset(void)
+{
+ return readw(TPU_REG(TPU_OFFSET));
+}
+
+uint16_t tpu_get_synchro(void)
+{
+ return readw(TPU_REG(TPU_SYNCHRO));
+}
+
+/* add two numbers, modulo 5000, and ensure the result is positive */
+uint16_t add_mod5000(uint16_t a, uint16_t b)
+{
+ int32_t sum = (uint32_t)a + (uint32_t)b;
+
+ sum %= 5000;
+
+ /* wrap around zero */
+ if (sum < 0)
+ sum += 5000;
+
+ return sum;
+}
diff --git a/src/target/firmware/calypso/tsp.c b/src/target/firmware/calypso/tsp.c
new file mode 100644
index 00000000..5d24f48e
--- /dev/null
+++ b/src/target/firmware/calypso/tsp.c
@@ -0,0 +1,121 @@
+/* Calypso DBB internal TSP (Time Serial Port) Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+
+static uint16_t tspact_state;
+
+/* initiate a TSP write through the TPU */
+void tsp_write(uint8_t dev_idx, uint8_t bitlen, uint32_t dout)
+{
+ if (bitlen <= 8) {
+ tpu_enq_move(TPUI_TX_1, dout & 0xff);
+ } else if (bitlen <= 16) {
+ tpu_enq_move(TPUI_TX_1, (dout >> 8) & 0xff);
+ tpu_enq_move(TPUI_TX_2, dout & 0xff);
+ } else if (bitlen <= 24) {
+ tpu_enq_move(TPUI_TX_1, (dout >> 16) & 0xff);
+ tpu_enq_move(TPUI_TX_2, (dout >> 8) & 0xff);
+ tpu_enq_move(TPUI_TX_3, dout & 0xff);
+ } else {
+ tpu_enq_move(TPUI_TX_1, (dout >> 24) & 0xff);
+ tpu_enq_move(TPUI_TX_2, (dout >> 16) & 0xff);
+ tpu_enq_move(TPUI_TX_3, (dout >> 8) & 0xff);
+ tpu_enq_move(TPUI_TX_4, dout & 0xff);
+ }
+ tpu_enq_move(TPUI_TSP_CTRL1, (dev_idx << 5) | (bitlen - 1));
+ tpu_enq_move(TPUI_TSP_CTRL2, TPUI_CTRL2_WR);
+}
+
+/* Configure clock edge and chip enable polarity for a device */
+void tsp_setup(uint8_t dev_idx, int clk_rising, int en_positive, int en_edge)
+{
+ uint8_t reg = TPUI_TSP_SET1 + (dev_idx / 2);
+ uint8_t val = 0;
+ uint8_t shift;
+
+ if (dev_idx & 1)
+ shift = 4;
+ else
+ shift = 0;
+
+ if (clk_rising)
+ val |= 1;
+ if (en_positive)
+ val |= 2;
+ if (en_edge)
+ val |= 4;
+
+ tpu_enq_move(reg, (val << shift));
+}
+
+/* Update the TSPACT state, including enable and disable */
+void tsp_act_update(uint16_t new_act)
+{
+ uint8_t low = new_act & 0xff;
+ uint8_t high = new_act >> 8;
+
+ if (low != (tspact_state & 0xff))
+ tpu_enq_move(TPUI_TSP_ACT_L, low);
+ if (high != (tspact_state >> 8))
+ tpu_enq_move(TPUI_TSP_ACT_U, high);
+
+ tspact_state = new_act;
+}
+
+/* Enable one or multiple TSPACT signals */
+void tsp_act_enable(uint16_t bitmask)
+{
+ uint16_t new_act = tspact_state | bitmask;
+ tsp_act_update(new_act);
+}
+
+/* Disable one or multiple TSPACT signals */
+void tsp_act_disable(uint16_t bitmask)
+{
+ uint16_t new_act = tspact_state & ~bitmask;
+ tsp_act_update(new_act);
+}
+
+/* Obtain the current tspact state */
+uint16_t tsp_act_state(void)
+{
+ return tspact_state;
+}
+
+/* Toggle one or multiple TSPACT signals */
+void tsp_act_toggle(uint16_t bitmask)
+{
+ uint16_t new_act = tspact_state ^ bitmask;
+ tsp_act_update(new_act);
+}
+
+void tsp_init(void)
+{
+ tsp_act_update(0);
+}
diff --git a/src/target/firmware/calypso/uart.c b/src/target/firmware/calypso/uart.c
new file mode 100644
index 00000000..7e68edc3
--- /dev/null
+++ b/src/target/firmware/calypso/uart.c
@@ -0,0 +1,396 @@
+/* Calypso DBB internal UART Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <debug.h>
+
+#include <memory.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <console.h>
+#include <comm/sercomm.h>
+
+#include <calypso/irq.h>
+#include <calypso/uart.h>
+
+#define BASE_ADDR_UART_MODEM 0xffff5000
+#define OFFSET_IRDA 0x800
+
+#define UART_REG(n,m) (BASE_ADDR_UART_MODEM + ((n)*OFFSET_IRDA)+(m))
+
+#define LCR7BIT 0x80
+#define LCRBFBIT 0x40
+#define MCR6BIT 0x20
+#define REG_OFFS(m) ((m) &= ~(LCR7BIT|LCRBFBIT|MCR6BIT))
+/* read access LCR[7] = 0 */
+enum uart_reg {
+ RHR = 0,
+ IER = 1,
+ IIR = 2,
+ LCR = 3,
+ MCR = 4,
+ LSR = 5,
+ MSR = 6,
+ SPR = 7,
+ MDR1 = 8,
+ DMR2 = 9,
+ SFLSR = 0x0a,
+ RESUME = 0x0b,
+ SFREGL = 0x0c,
+ SFREGH = 0x0d,
+ BLR = 0x0e,
+ ACREG = 0x0f,
+ SCR = 0x10,
+ SSR = 0x11,
+ EBLR = 0x12,
+/* read access LCR[7] = 1 */
+ DLL = RHR | LCR7BIT,
+ DLH = IER | LCR7BIT,
+ DIV1_6 = ACREG | LCR7BIT,
+/* read/write access LCR[7:0] = 0xbf */
+ EFR = IIR | LCRBFBIT,
+ XON1 = MCR | LCRBFBIT,
+ XON2 = LSR | LCRBFBIT,
+ XOFF1 = MSR | LCRBFBIT,
+ XOFF2 = SPR | LCRBFBIT,
+/* read/write access if EFR[4] = 1 and MCR[6] = 1 */
+ TCR = MSR | MCR6BIT,
+ TLR = SPR | MCR6BIT,
+};
+/* write access LCR[7] = 0 */
+#define THR RHR
+#define FCR IIR /* only if EFR[4] = 1 */
+#define TXFLL SFLSR
+#define TXFLH RESUME
+#define RXFLL SFREGL
+#define RXFLH SFREGH
+
+enum fcr_bits {
+ FIFO_EN = (1 << 0),
+ RX_FIFO_CLEAR = (1 << 1),
+ TX_FIFO_CLEAR = (1 << 2),
+ DMA_MODE = (1 << 3),
+};
+#define TX_FIFO_TRIG_SHIFT 4
+#define RX_FIFO_TRIG_SHIFT 6
+
+enum iir_bits {
+ IIR_INT_PENDING = 0x01,
+ IIR_INT_TYPE = 0x3E,
+ IIR_INT_TYPE_RX_STATUS_ERROR = 0x06,
+ IIR_INT_TYPE_RX_TIMEOUT = 0x0C,
+ IIR_INT_TYPE_RHR = 0x04,
+ IIR_INT_TYPE_THR = 0x02,
+ IIR_INT_TYPE_MSR = 0x00,
+ IIR_INT_TYPE_XOFF = 0x10,
+ IIR_INT_TYPE_FLOW = 0x20,
+ IIR_FCR0_MIRROR = 0xC0,
+};
+
+#define UART_REG_UIR 0xffff6000
+
+/* enable or disable the divisor latch for access to DLL, DLH */
+static void uart_set_lcr7bit(int uart, int on)
+{
+ uint8_t reg;
+
+ reg = readb(UART_REG(uart, LCR));
+ if (on)
+ reg |= (1 << 7);
+ else
+ reg &= ~(1 << 7);
+ writeb(reg, UART_REG(uart, LCR));
+}
+
+static uint8_t old_lcr;
+static void uart_set_lcr_bf(int uart, int on)
+{
+ old_lcr = readb(UART_REG(uart, LCR));
+
+ if (on)
+ writeb(0xBF, UART_REG(uart, LCR));
+ else
+ writeb(old_lcr, UART_REG(uart, LCR));
+}
+
+/* Enable or disable the TCR_TLR latch bit in MCR[6] */
+static void uart_set_mcr6bit(int uart, int on)
+{
+ uint8_t mcr;
+ /* we assume EFR[4] is always set to 1 */
+ mcr = readb(UART_REG(uart, MCR));
+ if (on)
+ mcr |= (1 << 6);
+ else
+ mcr &= ~(1 << 6);
+ writeb(mcr, UART_REG(uart, MCR));
+}
+
+static void uart_reg_write(int uart, enum uart_reg reg, uint8_t val)
+{
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ writeb(val, UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+}
+
+/* read from a UART register, applying any required latch bits */
+static uint8_t uart_reg_read(int uart, enum uart_reg reg)
+{
+ uint8_t ret;
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ ret = readb(UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+
+ return ret;
+}
+
+static void uart_irq_handler_cons(enum irq_nr irq)
+{
+ const uint8_t uart = CONS_UART_NR;
+ uint8_t iir;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RHR:
+ break;
+ case IIR_INT_TYPE_THR:
+ if (cons_rb_flush() == 1) {
+ /* everything was flushed, disable THR IRQ */
+ uint8_t ier = uart_reg_read(uart, IER);
+ ier &= ~(1 << 1);
+ uart_reg_write(uart, IER, ier);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ break;
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ break;
+ case IIR_INT_TYPE_XOFF:
+ break;
+ }
+}
+
+static void uart_irq_handler_sercomm(enum irq_nr irq)
+{
+ const uint8_t uart = SERCOMM_UART_NR;
+ uint8_t iir, ch;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ case IIR_INT_TYPE_RHR:
+ /* as long as we have rx data available */
+ while (uart_getchar_nb(uart, &ch)) {
+ if (sercomm_drv_rx_char(ch) < 0) {
+ /* sercomm cannot receive more data right now */
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 0);
+ }
+ }
+ break;
+ case IIR_INT_TYPE_THR:
+ /* as long as we have space in the FIFO */
+ while (!uart_tx_busy(uart)) {
+ /* get a byte from sercomm */
+ if (!sercomm_drv_pull(&ch)) {
+ /* no more bytes in sercomm, stop TX interrupts */
+ uart_irq_enable(uart, UART_IRQ_TX_EMPTY, 0);
+ break;
+ }
+ /* write the byte into the TX FIFO */
+ uart_putchar_nb(uart, ch);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ break;
+ case IIR_INT_TYPE_XOFF:
+ break;
+ }
+}
+
+static const uint8_t uart2irq[] = {
+ [0] = IRQ_UART_IRDA,
+ [1] = IRQ_UART_MODEM,
+};
+
+void uart_init(uint8_t uart)
+{
+ uint8_t irq = uart2irq[uart];
+
+ uart_reg_write(uart, IER, 0x00);
+ if (uart == CONS_UART_NR) {
+ cons_init();
+ irq_register_handler(irq, &uart_irq_handler_cons);
+ irq_config(irq, 0, 0, 0xff);
+ irq_enable(irq);
+ } else {
+ sercomm_init();
+ irq_register_handler(irq, &uart_irq_handler_sercomm);
+ irq_config(irq, 0, 0, 0xff);
+ irq_enable(irq);
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1);
+ }
+#if 0
+ if (uart == 1) {
+ /* assign UART to MCU and unmask interrupts*/
+ writeb(UART_REG_UIR, 0x00);
+ }
+#endif
+ /* select UART mode */
+ uart_reg_write(uart, MDR1, 0);
+ /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */
+ uart_reg_write(uart, EFR, (1 << 4));
+ /* enable Tx/Rx FIFO, Tx trigger at 56 spaces, Rx trigger at 60 chars */
+ uart_reg_write(uart, FCR, FIFO_EN | RX_FIFO_CLEAR | TX_FIFO_CLEAR |
+ (3 << TX_FIFO_TRIG_SHIFT) | (3 << RX_FIFO_TRIG_SHIFT));
+
+ /* THR interrupt only when TX FIFO and TX shift register are empty */
+ uart_reg_write(uart, SCR, (1 << 0));// | (1 << 3));
+
+ /* 8 bit, 1 stop bit, no parity, no break */
+ uart_reg_write(uart, LCR, 0x03);
+
+ uart_set_lcr7bit(uart, 0);
+}
+
+void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on)
+{
+ uint8_t ier = uart_reg_read(uart, IER);
+ uint8_t mask = 0;
+
+ switch (irq) {
+ case UART_IRQ_TX_EMPTY:
+ mask = (1 << 1);
+ break;
+ case UART_IRQ_RX_CHAR:
+ mask = (1 << 0);
+ break;
+ }
+
+ if (on)
+ ier |= mask;
+ else
+ ier &= ~mask;
+
+ uart_reg_write(uart, IER, ier);
+}
+
+
+void uart_putchar_wait(uint8_t uart, int c)
+{
+ /* wait while TX FIFO indicates full */
+ while (readb(UART_REG(uart, SSR)) & 0x01) { }
+
+ /* put character in TX FIFO */
+ writeb(c, UART_REG(uart, THR));
+}
+
+int uart_putchar_nb(uint8_t uart, int c)
+{
+ /* if TX FIFO indicates full, abort */
+ if (readb(UART_REG(uart, SSR)) & 0x01)
+ return 0;
+
+ writeb(c, UART_REG(uart, THR));
+ return 1;
+}
+
+int uart_getchar_nb(uint8_t uart, uint8_t *ch)
+{
+ if (!(readb(UART_REG(uart, LSR)) & 0x01))
+ return 0;
+
+ *ch = readb(UART_REG(uart, RHR));
+ return 1;
+}
+
+int uart_tx_busy(uint8_t uart)
+{
+ if (readb(UART_REG(uart, SSR)) & 0x01)
+ return 1;
+ return 0;
+}
+
+static const uint16_t divider[] = {
+ [UART_38400] = 21, /* 38,690 */
+ [UART_57600] = 14, /* 58,035 */
+ [UART_115200] = 7, /* 116,071 */
+ [UART_230400] = 4, /* 203,125! (-3% would be 223,488) */
+ [UART_460800] = 2, /* 406,250! (-3% would be 446,976) */
+ [UART_921600] = 1, /* 812,500! (-3% would be 893,952) */
+};
+
+int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt)
+{
+ uint16_t div;
+
+ if (bdrt > ARRAY_SIZE(divider))
+ return -1;
+
+ div = divider[bdrt];
+ uart_set_lcr7bit(uart, 1);
+ writeb(div & 0xff, UART_REG(uart, DLL));
+ writeb(div >> 8, UART_REG(uart, DLH));
+ uart_set_lcr7bit(uart, 0);
+
+ return 0;
+}
diff --git a/src/target/firmware/comm/Makefile b/src/target/firmware/comm/Makefile
new file mode 100644
index 00000000..c2c6fcf0
--- /dev/null
+++ b/src/target/firmware/comm/Makefile
@@ -0,0 +1,26 @@
+INCLUDES=-I../include/
+-include ../Makefile.inc
+
+LIBNAME=comm
+CSRCS=msgb.c sercomm.c sercomm_cons.c
+SSRCS=
+
+COBJS=$(CSRCS:.c=.o)
+SOBJS=$(SSRCS:.S=.o)
+OBJS=$(COBJS) $(SOBJS)
+
+LST=$(OBJS:.o=.lst)
+
+all: lib$(LIBNAME).a
+
+$(COBJS): %.o : %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
+
+$(SOBJS): %.o : %.S
+ $(CROSS_COMPILE)$(CC) $(ASFLAGS) -c -o $@ $^
+
+lib$(LIBNAME).a: $(OBJS)
+ $(CROSS_COMPILE)$(AR) cru $@ $^
+
+clean:
+ rm -f *.a $(OBJS) $(LST)
diff --git a/src/target/firmware/comm/msgb.c b/src/target/firmware/comm/msgb.c
new file mode 100644
index 00000000..8245ed20
--- /dev/null
+++ b/src/target/firmware/comm/msgb.c
@@ -0,0 +1,134 @@
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <debug.h>
+
+#include <comm/msgb.h>
+
+#include <calypso/backlight.h>
+
+#define NO_TALLOC
+
+void *tall_msgb_ctx;
+
+#ifdef NO_TALLOC
+/* This is a poor mans static allocator for msgb objects */
+#define MSGB_DATA_SIZE 256
+#define MSGB_NUM 16
+struct supermsg {
+ uint8_t allocated;
+ struct msgb msg;
+ uint8_t buf[MSGB_DATA_SIZE];
+};
+static struct supermsg msgs[MSGB_NUM];
+static void *_talloc_zero(void *ctx, unsigned int size, const char *name)
+{
+ unsigned int i;
+ if (size > sizeof(struct msgb) + MSGB_DATA_SIZE)
+ goto panic;
+ for (i = 0; i < ARRAY_SIZE(msgs); i++) {
+ if (!msgs[i].allocated) {
+ msgs[i].allocated = 1;
+ memset(&msgs[i].msg, 0, sizeof(&msgs[i].msg));
+ memset(&msgs[i].buf, 0, sizeof(&msgs[i].buf));
+ return &msgs[i].msg;
+ }
+ }
+
+panic:
+ while (1) {
+ bl_level(++i % 50);
+ delay_ms(50);
+ }
+ return NULL;
+}
+static void talloc_free(void *msg)
+{
+ struct supermsg *smsg = container_of(msg, struct supermsg, msg);
+ smsg->allocated = 0;
+}
+#endif
+
+struct msgb *msgb_alloc(uint16_t size, const char *name)
+{
+ struct msgb *msg;
+
+ msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name);
+
+ if (!msg) {
+ cons_puts("unable to allocate msgb\n");
+ return NULL;
+ }
+
+ msg->data_len = size;
+ msg->len = 0;
+ msg->data = msg->_data;
+
+ msg->head = msg->data;
+ msg->data = msg->data;
+ /* reset tail pointer */
+ msg->tail = msg->data;
+
+ return msg;
+}
+
+void msgb_free(struct msgb *m)
+{
+ talloc_free(m);
+}
+
+void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
+{
+ llist_add_tail(&msg->list, queue);
+}
+
+struct msgb *msgb_dequeue(struct llist_head *queue)
+{
+ struct llist_head *lh;
+
+ if (llist_empty(queue))
+ return NULL;
+
+ lh = queue->next;
+ llist_del(lh);
+
+ return llist_entry(lh, struct msgb, list);
+}
+
+void msgb_reset(struct msgb *msg)
+{
+ msg->len = 0;
+ msg->len = 0;
+ msg->data = msg->_data;
+
+ msg->head = msg->data;
+ msg->data = msg->data;
+ /* reset tail pointer */
+ msg->tail = msg->data;
+
+ /* reset pointers */
+ msg->l2h = NULL;
+ msg->l3h = NULL;
+}
diff --git a/src/target/firmware/comm/sercomm.c b/src/target/firmware/comm/sercomm.c
new file mode 100644
index 00000000..d852eb99
--- /dev/null
+++ b/src/target/firmware/comm/sercomm.c
@@ -0,0 +1,244 @@
+/* Serial communications layer, based on HDLC */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef HOST_BUILD
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#endif
+#include <osmocom/msgb.h>
+#include <sercomm.h>
+
+#else
+#include <debug.h>
+#include <linuxlist.h>
+
+#include <comm/msgb.h>
+#include <comm/sercomm.h>
+#include <calypso/uart.h>
+#endif
+
+#define SERCOMM_RX_MSG_SIZE 256
+
+enum rx_state {
+ RX_ST_WAIT_START,
+ RX_ST_ADDR,
+ RX_ST_CTRL,
+ RX_ST_DATA,
+ RX_ST_ESCAPE,
+};
+
+static struct {
+ int initialized;
+
+ /* transmit side */
+ struct {
+ struct llist_head dlci_queues[_SC_DLCI_MAX];
+ struct msgb *msg;
+ uint8_t *next_char;
+ } tx;
+
+ /* receive side */
+ struct {
+ dlci_cb_t dlci_handler[_SC_DLCI_MAX];
+ struct msgb *msg;
+ enum rx_state state;
+ uint8_t dlci;
+ uint8_t ctrl;
+ } rx;
+
+} sercomm;
+
+void sercomm_init(void)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++)
+ INIT_LLIST_HEAD(&sercomm.tx.dlci_queues[i]);
+
+ sercomm.rx.msg = NULL;
+ sercomm.initialized = 1;
+}
+
+int sercomm_initialized(void)
+{
+ return sercomm.initialized;
+}
+
+/* user interface for transmitting messages for a given DLCI */
+void sercomm_sendmsg(uint8_t dlci, struct msgb *msg)
+{
+ uint8_t *hdr;
+
+ /* prepend address + control octet */
+ hdr = msgb_push(msg, 2);
+ hdr[0] = dlci;
+ hdr[1] = HDLC_C_UI;
+ msgb_enqueue(&sercomm.tx.dlci_queues[dlci], msg);
+
+#ifndef HOST_BUILD
+ /* tell UART that we have something to send */
+ uart_irq_enable(SERCOMM_UART_NR, UART_IRQ_TX_EMPTY, 1);
+#endif
+}
+
+/* how deep is the Tx queue for a given DLCI */
+unsigned int sercomm_tx_queue_depth(uint8_t dlci)
+{
+ struct llist_head *le;
+ unsigned int num = 0;
+
+ llist_for_each(le, &sercomm.tx.dlci_queues[dlci]) {
+ num++;
+ }
+
+ return num;
+}
+
+/* fetch one octet of to-be-transmitted serial data */
+int sercomm_drv_pull(uint8_t *ch)
+{
+ if (!sercomm.tx.msg) {
+ unsigned int i;
+ /* dequeue a new message from the queues */
+ for (i = 0; i < ARRAY_SIZE(sercomm.tx.dlci_queues); i++) {
+ sercomm.tx.msg = msgb_dequeue(&sercomm.tx.dlci_queues[i]);
+ if (sercomm.tx.msg)
+ break;
+ }
+ if (sercomm.tx.msg) {
+ /* start of a new message, send start flag octet */
+ *ch = HDLC_FLAG;
+ sercomm.tx.next_char = sercomm.tx.msg->data;
+ return 1;
+ } else {
+ /* no more data avilable */
+ return 0;
+ }
+ }
+
+ /* escaping for the two control octets */
+ if (*sercomm.tx.next_char == HDLC_FLAG ||
+ *sercomm.tx.next_char == HDLC_ESCAPE) {
+ /* send an escape octet */
+ *ch = HDLC_ESCAPE;
+ /* invert bit 5 of the next octet to be sent */
+ *sercomm.tx.next_char ^= (1 << 5);
+ } else if (sercomm.tx.next_char == sercomm.tx.msg->tail) {
+ /* last character has already been transmitted,
+ * send end-of-message octet */
+ *ch = HDLC_FLAG;
+ /* we've reached the end of the message buffer */
+ msgb_free(sercomm.tx.msg);
+ sercomm.tx.msg = NULL;
+ sercomm.tx.next_char = NULL;
+ } else {
+ /* standard case, simply send next octet */
+ *ch = *sercomm.tx.next_char++;
+ }
+ return 1;
+}
+
+/* register a handler for a given DLCI */
+int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb)
+{
+ if (dlci >= ARRAY_SIZE(sercomm.rx.dlci_handler))
+ return -EINVAL;
+
+ if (sercomm.rx.dlci_handler[dlci])
+ return -EBUSY;
+
+ sercomm.rx.dlci_handler[dlci] = cb;
+ return 0;
+}
+
+/* dispatch an incomnig message once it is completely received */
+static void dispatch_rx_msg(uint8_t dlci, struct msgb *msg)
+{
+ if (sercomm.rx.dlci_handler[dlci])
+ sercomm.rx.dlci_handler[dlci](dlci, msg);
+ else
+ msgb_free(msg);
+}
+
+/* the driver has received one byte, pass it into sercomm layer */
+int sercomm_drv_rx_char(uint8_t ch)
+{
+ uint8_t *ptr;
+
+ if (!sercomm.rx.msg)
+ sercomm.rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
+
+ if (msgb_tailroom(sercomm.rx.msg) == 0) {
+ msgb_free(sercomm.rx.msg);
+ sercomm.rx.msg = sercomm_alloc_msgb(SERCOMM_RX_MSG_SIZE);
+ sercomm.rx.state = RX_ST_WAIT_START;
+ return 0;
+ }
+
+ switch (sercomm.rx.state) {
+ case RX_ST_WAIT_START:
+ if (ch != HDLC_FLAG)
+ return 0;
+ sercomm.rx.state = RX_ST_ADDR;
+ break;
+ case RX_ST_ADDR:
+ sercomm.rx.dlci = ch;
+ sercomm.rx.state = RX_ST_CTRL;
+ break;
+ case RX_ST_CTRL:
+ sercomm.rx.ctrl = ch;
+ sercomm.rx.state = RX_ST_DATA;
+ break;
+ case RX_ST_DATA:
+ if (ch == HDLC_ESCAPE) {
+ /* drop the escape octet, but change state */
+ sercomm.rx.state = RX_ST_ESCAPE;
+ break;
+ } else if (ch == HDLC_FLAG) {
+ /* message is finished */
+ dispatch_rx_msg(sercomm.rx.dlci, sercomm.rx.msg);
+ /* allocate new buffer */
+ sercomm.rx.msg = NULL;
+ /* start all over again */
+ sercomm.rx.state = RX_ST_WAIT_START;
+
+ /* do not add the control char */
+ break;
+ }
+ /* default case: store the octet */
+ ptr = msgb_put(sercomm.rx.msg, 1);
+ *ptr = ch;
+ break;
+ case RX_ST_ESCAPE:
+ /* store bif-5-inverted octet in buffer */
+ ch ^= (1 << 5);
+ ptr = msgb_put(sercomm.rx.msg, 1);
+ *ptr = ch;
+ /* transition back to nromal DATA state */
+ sercomm.rx.state = RX_ST_DATA;
+ break;
+ }
+ return 1;
+}
diff --git a/src/target/firmware/comm/sercomm_cons.c b/src/target/firmware/comm/sercomm_cons.c
new file mode 100644
index 00000000..fa08b50e
--- /dev/null
+++ b/src/target/firmware/comm/sercomm_cons.c
@@ -0,0 +1,126 @@
+/* Serial console layer, layered on top of sercomm HDLC */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+
+#include <calypso/uart.h>
+
+#include <console.h>
+#include <comm/msgb.h>
+#include <comm/sercomm.h>
+#include <comm/sercomm_cons.h>
+
+static struct {
+ struct msgb *cur_msg;
+} scons;
+
+static void raw_puts(const char *s)
+{
+ int i = strlen(s);
+ while (i--)
+ uart_putchar_wait(SERCOMM_UART_NR, *s++);
+}
+
+#ifdef DEBUG
+#define raw_putd(x) raw_puts(x)
+#else
+#define raw_putd(x)
+#endif
+
+int sercomm_puts(const char *s)
+{
+ const int len = strlen(s) + 1;
+ unsigned int bytes_left = len;
+
+ if (!sercomm_initialized()) {
+ raw_putd("sercomm not initialized: ");
+ raw_puts(s);
+ return len - 1;
+ }
+
+ while (bytes_left > 0) {
+ unsigned int write_num, space_left, flush;
+ uint8_t *data;
+
+ if (!scons.cur_msg)
+ scons.cur_msg = sercomm_alloc_msgb(SERCOMM_CONS_ALLOC);
+
+ if (!scons.cur_msg) {
+ raw_putd("cannot allocate sercomm msgb: ");
+ raw_puts(s);
+ return -ENOMEM;
+ }
+
+ /* space left in the current msgb */
+ space_left = msgb_tailroom(scons.cur_msg);
+
+ if (space_left <= bytes_left) {
+ write_num = space_left;
+ /* flush buffer when it is full */
+ flush = 1;
+ } else {
+ write_num = bytes_left;
+ flush = 0;
+ }
+
+ /* obtain pointer where to copy the data */
+ data = msgb_put(scons.cur_msg, write_num);
+
+ /* copy data while looking for \n line termination */
+ {
+ unsigned int i;
+ for (i = 0; i < write_num; i++) {
+ /* flush buffer at end of line */
+ if (*s == '\n')
+ flush = 1;
+ *data++ = *s++;
+ }
+ }
+ bytes_left -= write_num;
+
+ if (flush) {
+ sercomm_sendmsg(SC_DLCI_CONSOLE, scons.cur_msg);
+ /* reset scons.cur_msg pointer to ensure we allocate
+ * a new one next round */
+ scons.cur_msg = NULL;
+ }
+ }
+
+ return len - 1;
+}
+
+int sercomm_putchar(int c)
+{
+ char s[2];
+ int rc;
+
+ s[0] = c & 0xff;
+ s[1] = '\0';
+
+ rc = sercomm_puts(s);
+ if (rc < 0)
+ return rc;
+
+ return c;
+}
diff --git a/src/target/firmware/display/font_r8x8.c b/src/target/firmware/display/font_r8x8.c
new file mode 100644
index 00000000..f6a8a820
--- /dev/null
+++ b/src/target/firmware/display/font_r8x8.c
Binary files differ
diff --git a/src/target/firmware/display/st7558.c b/src/target/firmware/display/st7558.c
new file mode 100644
index 00000000..daba94bd
--- /dev/null
+++ b/src/target/firmware/display/st7558.c
@@ -0,0 +1,122 @@
+/* Sitronix ST7558 LCD Driver */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <delay.h>
+#include <memory.h>
+#include <i2c.h>
+#include <display/st7558.h>
+#include <calypso/clock.h>
+
+#define MORE_CONTROL 0x80
+#define CONTROL_RS_RAM 0x40
+#define CONTROL_RS_CMD 0x00
+#define Y_ADDR(n) (0x40|((n)&0xf))
+#define X_ADDR(n) (0x80|((n)&0x3f))
+
+static const uint8_t setup[] = { CONTROL_RS_CMD, 0x2e, 0x21, 0x12, 0xc0, 0x0b, 0x20, 0x11, 0x00, 0x40, 0x80 };
+static const uint8_t home[] = { CONTROL_RS_CMD, Y_ADDR(0), X_ADDR(0) };
+
+/* video modes */
+static const uint8_t invert[] = { CONTROL_RS_CMD, 0x20, 0x0d };
+static const uint8_t normal[] = { CONTROL_RS_CMD, 0x20, 0x0c };
+static const uint8_t off[] = { CONTROL_RS_CMD, 0x20, 0x08 };
+
+#define ST7558_SLAVE_ADDR 0x3c
+static int st7558_write(const uint8_t *data, int len)
+{
+ int rc = i2c_write(ST7558_SLAVE_ADDR, data[0], 1, data+1, len-1);
+ /* FIXME: find out why this is needed! */
+ delay_ms(10);
+ return rc;
+}
+
+void st7558_init(void)
+{
+ /* Release nRESET */
+ calypso_reset_set(RESET_EXT, 0);
+
+ i2c_init(0,0);
+ delay_ms(10);
+
+ st7558_write(setup, sizeof(setup));
+ st7558_clrscr();
+}
+
+void st7558_set_attr(unsigned long attr)
+{
+ if (attr & DISP_ATTR_INVERT)
+ st7558_write(invert, sizeof(invert));
+}
+
+void st7558_unset_attr(unsigned long attr)
+{
+ if (attr & DISP_ATTR_INVERT)
+ st7558_write(normal, sizeof(normal));
+}
+
+static const uint8_t zero16[] = { CONTROL_RS_RAM,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+void st7558_clrscr(void)
+{
+ int i;
+
+ st7558_write(home, sizeof(home));
+
+ for (i = 0; i < 102*9; i += 16)
+ st7558_write(zero16, sizeof(zero16));
+
+ st7558_write(home, sizeof(home));
+}
+
+/* FIXME: we need a mini-libc */
+static void *mcpy(uint8_t *dst, const uint8_t *src, int len)
+{
+ while (len--)
+ *dst++ = *src++;
+
+ return dst;
+}
+
+extern const unsigned char fontdata_r8x8[];
+
+void st7558_putchar(unsigned char c)
+{
+ uint8_t putc_buf[16];
+ uint8_t bytes_per_char = 8;
+
+ putc_buf[0] = CONTROL_RS_RAM;
+ mcpy(putc_buf+1, fontdata_r8x8+(c*bytes_per_char), bytes_per_char);
+ st7558_write(putc_buf, 1+bytes_per_char);
+}
+
+void st7558_puts(const char *str)
+{
+ char c;
+
+ while ((c = *str++))
+ st7558_putchar(c);
+}
diff --git a/src/target/firmware/flash/cfi_flash.c b/src/target/firmware/flash/cfi_flash.c
new file mode 100644
index 00000000..faf44cbe
--- /dev/null
+++ b/src/target/firmware/flash/cfi_flash.c
@@ -0,0 +1,435 @@
+/* NOR Flash Driver for Intel 28F160C3 NOR flash */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <memory.h>
+#include <cfi_flash.h>
+
+/* XXX: memdump_range() */
+#include <calypso/misc.h>
+
+enum flash_cmd {
+ FLASH_CMD_RESET = 0xff,
+ FLASH_CMD_READ_ID = 0x90,
+ FLASH_CMD_CFI = 0x98,
+ FLASH_CMD_READ_STATUS = 0x70,
+ FLASH_CMD_CLEAR_STATUS = 0x50,
+ FLASH_CMD_WRITE = 0x40,
+ FLASH_CMD_BLOCK_ERASE = 0x20,
+ FLASH_CMD_ERASE_CONFIRM = 0xD0,
+ FLASH_CMD_PROTECT = 0x60,
+};
+
+enum flash_prot_cmd {
+ FLASH_PROT_LOCK = 0x01,
+ FLASH_PROT_UNLOCK = 0xD0,
+ FLASH_PROT_LOCKDOWN = 0x2F
+};
+
+enum flash_offset {
+ FLASH_OFFSET_MANUFACTURER_ID = 0x00,
+ FLASH_OFFSET_DEVICE_ID = 0x01,
+ FLASH_OFFSET_INTEL_PROTECTION = 0x81,
+ FLASH_OFFSET_CFI_RESP = 0x10
+};
+
+enum flash_block_offset {
+ FLASH_OFFSET_BLOCK_LOCKSTATE = 0x02
+};
+
+enum flash_status {
+ FLASH_STATUS_READY = 0x80,
+ FLASH_STATUS_ERASE_SUSPENDED = 0x40,
+ FLASH_STATUS_ERASE_ERROR = 0x20,
+ FLASH_STATUS_PROGRAM_ERROR = 0x10,
+ FLASH_STATUS_VPP_LOW = 0x08,
+ FLASH_STATUS_PROGRAM_SUSPENDED = 0x04,
+ FLASH_STATUS_LOCKED_ERROR = 0x02,
+ FLASH_STATUS_RESERVED = 0x01
+};
+
+static inline void flash_write_cmd(const void *base_addr, uint16_t cmd)
+{
+ writew(cmd, base_addr);
+}
+
+static inline uint16_t flash_read16(const void *base_addr, uint32_t offset)
+{
+ return readw(base_addr + (offset << 1));
+}
+
+static char flash_protected(uint32_t block_offset) {
+ return block_offset < 64*1024;
+}
+
+uint8_t flash_block_getlock(cfi_flash_t *flash, uint32_t block_offset) {
+ const void *base_addr = flash->f_base;
+ uint8_t lockstate;
+ flash_write_cmd(base_addr, FLASH_CMD_READ_ID);
+ lockstate = flash_read16(base_addr, block_offset + FLASH_OFFSET_BLOCK_LOCKSTATE);
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+ return lockstate;
+}
+
+void flash_block_unlock(cfi_flash_t *flash, uint32_t block_offset) {
+ const void *base_addr = flash->f_base;
+ printf("Unlocking block at 0x%08x\n", block_offset);
+
+ if(flash_protected(block_offset)) {
+ puts("error: block is soft-protected\n");
+ return;
+ }
+
+ flash_write_cmd(base_addr, FLASH_CMD_PROTECT);
+ flash_write_cmd(base_addr + block_offset, FLASH_PROT_UNLOCK);
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+void flash_block_lock(cfi_flash_t *flash, uint32_t block_offset) {
+ const void *base_addr = flash->f_base;
+ printf("Locking block at 0x%08x\n", block_offset);
+ flash_write_cmd(base_addr, FLASH_CMD_PROTECT);
+ flash_write_cmd(base_addr + block_offset, FLASH_PROT_LOCK);
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+void flash_block_lockdown(cfi_flash_t *flash, uint32_t block_offset) {
+ const void *base_addr = flash->f_base;
+ printf("Locking down block at 0x%08x\n", block_offset);
+ flash_write_cmd(base_addr, FLASH_CMD_PROTECT);
+ flash_write_cmd(base_addr + block_offset, FLASH_PROT_LOCKDOWN);
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+void flash_block_erase(cfi_flash_t *flash, uint32_t block_offset) {
+ const void *base_addr = flash->f_base;
+ printf("Erasing block 0x%08x...", block_offset);
+
+ if(flash_protected(block_offset)) {
+ puts("error: block is soft-protected\n");
+ return;
+ }
+
+ void *block_addr = ((uint8_t*)base_addr) + block_offset;
+
+ flash_write_cmd(base_addr, FLASH_CMD_CLEAR_STATUS);
+
+ flash_write_cmd(block_addr, FLASH_CMD_BLOCK_ERASE);
+ flash_write_cmd(block_addr, FLASH_CMD_ERASE_CONFIRM);
+
+ flash_write_cmd(base_addr, FLASH_CMD_READ_STATUS);
+ uint16_t status;
+ do {
+ status = flash_read16(base_addr, 0);
+ } while(!(status&FLASH_STATUS_READY));
+
+ if(status&FLASH_STATUS_ERASE_ERROR) {
+ puts("error: ");
+ if(status&FLASH_STATUS_VPP_LOW) {
+ puts("vpp insufficient\n");
+ }
+ if(status&FLASH_STATUS_LOCKED_ERROR) {
+ puts("block is lock-protected\n");
+ }
+ } else {
+ puts("done\n");
+ }
+
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+void flash_program(cfi_flash_t *flash, uint32_t dst, void *src, uint32_t nbytes) {
+ const void *base_addr = flash->f_base;
+ uint32_t i;
+
+ printf("Programming %u bytes to 0x%08x from 0x%p...", nbytes, dst, src);
+
+ if(dst%2) {
+ puts("error: unaligned destination\n");
+ return;
+ }
+
+ if(nbytes%2) {
+ puts("error: unaligned count\n");
+ return;
+ }
+
+ if(flash_protected(dst)) {
+ puts("error: block is soft-protected\n");
+ return;
+ }
+
+ flash_write_cmd(base_addr, FLASH_CMD_CLEAR_STATUS);
+
+ puts("writing...");
+ for(i = 0; i < nbytes; i += 2) {
+ uint16_t *src_addr = (uint16_t*)(src + i);
+ uint16_t *dst_addr = (uint16_t*)(base_addr + dst + i);
+
+ uint16_t data = *src_addr;
+
+ flash_write_cmd(dst_addr, FLASH_CMD_WRITE);
+ flash_write_cmd(dst_addr, data);
+
+ flash_write_cmd(base_addr, FLASH_CMD_READ_STATUS);
+ uint16_t status;
+ do {
+ status = flash_read16(base_addr, 0);
+ } while(!(status&FLASH_STATUS_READY));
+
+ if(status&FLASH_STATUS_PROGRAM_ERROR) {
+ puts("error: ");
+ if(status&FLASH_STATUS_VPP_LOW) {
+ puts("vpp insufficient");
+ }
+ if(status&FLASH_STATUS_LOCKED_ERROR) {
+ puts("block is lock-protected");
+ }
+ goto err_reset;
+ }
+ }
+
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+
+ puts("verifying...");
+ for(i = 0; i < nbytes; i += 2) {
+ uint16_t *src_addr = (uint16_t*)(src + i);
+ uint16_t *dst_addr = (uint16_t*)(base_addr + dst + i);
+ if(*src_addr != *dst_addr) {
+ puts("error: verification failed");
+ goto err;
+ }
+ }
+
+ puts("done\n");
+
+ return;
+
+ err_reset:
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+
+ err:
+ printf(" at offset 0x%x\n", i);
+}
+
+typedef void (*flash_block_cb_t)(cfi_flash_t *flash,
+ uint32_t block_offset,
+ uint32_t block_size);
+
+void flash_iterate_blocks(cfi_flash_t *flash, struct cfi_query *qry,
+ uint32_t start_offset, uint32_t end_offset,
+ flash_block_cb_t callback)
+{
+ int region, block;
+
+ uint32_t block_start = 0;
+ for(region = 0; region < qry->num_erase_regions; region++) {
+ uint16_t actual_count = qry->erase_regions[region].b_count + 1;
+ uint32_t actual_size = qry->erase_regions[region].b_size * 256;
+ for(block = 0; block < actual_count; block++) {
+ uint32_t block_end = block_start + actual_size;
+ if(block_start >= start_offset && block_end-1 <= end_offset) {
+ callback(flash, block_start, actual_size);
+ }
+ block_start = block_end;
+ }
+ }
+}
+
+static void get_id(void *base_addr, uint16_t *manufacturer_id, uint16_t *device_id) {
+ flash_write_cmd(base_addr, FLASH_CMD_READ_ID);
+
+ *manufacturer_id = flash_read16(base_addr, FLASH_OFFSET_MANUFACTURER_ID);
+ *device_id = flash_read16(base_addr, FLASH_OFFSET_DEVICE_ID);
+
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+static void get_query(void *base_addr, struct cfi_query *query) {
+ unsigned int i;
+
+ flash_write_cmd(base_addr, FLASH_CMD_CFI);
+
+ for(i = 0; i < sizeof(struct cfi_query); i++) {
+ uint16_t byte = flash_read16(base_addr, FLASH_OFFSET_CFI_RESP+i);
+ *(((unsigned char*)query)+i) = byte;
+ }
+
+ if(query->qry[0] != 'Q' || query->qry[1] != 'R' || query->qry[2] != 'Y') {
+ puts("Error: CFI query signature not found\n");
+ }
+
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+static void dump_query(void *base_addr, struct cfi_query *query) {
+ unsigned int i;
+
+ flash_write_cmd(base_addr, FLASH_CMD_CFI);
+
+ for(i = 0; i < sizeof(struct cfi_query); i++) {
+ uint8_t byte = *(((uint8_t*)query)+i);
+ printf("%04X: %02X\n", FLASH_OFFSET_CFI_RESP+i, byte);
+ }
+
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+static void dump_layout(void *base_addr, const struct cfi_query *qry) {
+ int region;
+
+ flash_write_cmd(base_addr, FLASH_CMD_READ_ID);
+ for(region = 0; region < qry->num_erase_regions; region++) {
+ uint16_t actual_count = qry->erase_regions[region].b_count + 1;
+ uint32_t actual_size = qry->erase_regions[region].b_size * 256;
+ printf("Region of 0x%04x times 0x%6x bytes\n", actual_count,
+ actual_size);
+ }
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+static void dump_locks(void *base_addr, const struct cfi_query *qry) {
+ int region, block;
+
+ uint32_t block_addr = 0;
+ flash_write_cmd(base_addr, FLASH_CMD_READ_ID);
+ for(region = 0; region < qry->num_erase_regions; region++) {
+ uint16_t actual_count = qry->erase_regions[region].b_count + 1;
+ uint32_t actual_size = qry->erase_regions[region].b_size * 256;
+ for(block = 0; block < actual_count; block++) {
+ uint8_t lock = flash_read16(base_addr, block_addr+2);
+ printf("Block 0x%08x lock 0x%02x\n", block_addr*2, lock);
+ block_addr += actual_size / 2;
+ }
+ }
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+static void dump_protection(void *base_addr) {
+ flash_write_cmd(base_addr, FLASH_CMD_READ_ID);
+
+ uint16_t lock = flash_read16(base_addr, FLASH_OFFSET_INTEL_PROTECTION);
+ printf("Protection Lock: 0x%04x\n", lock);
+
+ puts("Protection Data: ");
+ int i;
+ for(i = 0; i < 8; i++) {
+ printf("%04x", flash_read16(base_addr, FLASH_OFFSET_INTEL_PROTECTION + 1 + i));
+ }
+ putchar('\n');
+
+ flash_write_cmd(base_addr, FLASH_CMD_RESET);
+}
+
+static void dump_timing(void *base_addr, struct cfi_query *qry) {
+ uint32_t block_erase_typ = 1<<qry->block_erase_timeout_typ;
+ uint32_t block_erase_max = (1<<qry->block_erase_timeout_max) * block_erase_typ;
+ uint32_t word_program_typ = 1<<qry->word_write_timeout_typ;
+ uint32_t word_program_max = (1<<qry->word_write_timeout_max) * word_program_typ;
+ printf("Block Erase Typical: %u ms\n", block_erase_typ);
+ printf("Block Erase Maximum: %u ms\n", block_erase_max);
+ printf("Word Program Typical: %u us\n", word_program_typ);
+ printf("Word Program Maximum: %u us\n", word_program_max);
+}
+
+static void dump_algorithms(void *base_addr, struct cfi_query *qry) {
+ printf("Primary Algorithm ID: %04x\n", qry->p_id);
+ printf("Primary Extended Query: %04x\n", qry->p_adr);
+
+ printf("Alternate Algorithm ID: %04x\n", qry->a_id);
+ printf("Alternate Extended Query: %04x\n", qry->a_adr);
+}
+
+void
+lockdown_block_cb(cfi_flash_t *flash,
+ uint32_t block_offset,
+ uint32_t block_size)
+{
+ flash_block_lockdown(flash, block_offset);
+}
+
+void
+print_block_cb(cfi_flash_t *flash,
+ uint32_t block_offset,
+ uint32_t block_size)
+{
+ printf("%08x size %08x\n", block_offset, block_size);
+}
+
+void flash_dump_info(cfi_flash_t *flash) {
+ void *base_addr = flash->f_base;
+ struct cfi_query *qry = &flash->f_query;
+
+ printf("Flash Manufacturer ID: %04x\n", flash->f_manuf_id);
+ printf("Flash Device ID: %04x\n", flash->f_dev_id);
+
+ printf("Flash Size: 0x%08x bytes\n", flash->f_size);
+
+ dump_algorithms(base_addr, qry);
+
+ dump_timing(base_addr, qry);
+
+ dump_protection(base_addr);
+
+ dump_layout(base_addr, qry);
+
+ dump_locks(base_addr, qry);
+}
+
+void flash_init(cfi_flash_t *flash, void *base_addr) {
+ printf("Initializing CFI flash at 0x%p\n", base_addr);
+
+ flash->f_base = base_addr;
+
+ get_id(base_addr, &flash->f_manuf_id, &flash->f_dev_id);
+
+ get_query(base_addr, &flash->f_query);
+
+ flash->f_size = 1<<flash->f_query.dev_size;
+}
+
+void flash_test() {
+ /* block iterator test */
+#if 0
+ flash_iterate_blocks(flash, qry, 0x0000, 0xFFFF, &lockdown_block_cb);
+#endif
+
+ /* programming test */
+#if 0
+ static uint8_t magic[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xDE, 0xAD, 0xBE, 0xEF};
+
+ memdump_range(&magic, sizeof(magic));
+
+#if 0
+#define ADDR 0x001E0000
+ flash_block_unlock(flash, ADDR);
+ memdump_range(ADDR, 16);
+ flash_block_erase(flash, ADDR);
+ memdump_range(ADDR, 16);
+ flash_program(flash, ADDR, &magic, sizeof(magic));
+ memdump_range(ADDR, 16);
+#undef ADDR
+#endif
+
+#endif
+}
diff --git a/src/target/firmware/include/abb/twl3025.h b/src/target/firmware/include/abb/twl3025.h
new file mode 100644
index 00000000..c6c30aac
--- /dev/null
+++ b/src/target/firmware/include/abb/twl3025.h
@@ -0,0 +1,128 @@
+#ifndef _TWL3025_H
+#define _TWL3025_H
+
+#define PAGE(n) (n << 7)
+enum twl3025_reg {
+ VRPCCFG = PAGE(1) | 30,
+ VRPCDEV = PAGE(0) | 30,
+ VRPCMSK = PAGE(1) | 31,
+ VRPCMSKABB = PAGE(1) | 29,
+ VRPCSTS = PAGE(0) | 31,
+ /* Monitoring ADC Registers */
+ MADCTRL = PAGE(0) | 13,
+ MADCSTAT = PAGE(0) | 24,
+ VBATREG = PAGE(0) | 15,
+ VCHGREG = PAGE(0) | 16,
+ ICHGREG = PAGE(0) | 17,
+ VBKPREG = PAGE(0) | 18,
+ ADIN1REG = PAGE(0) | 19,
+ ADIN2REG = PAGE(0) | 20,
+ ADIN3REG = PAGE(0) | 21,
+ ADIN4REG = PAGE(0) | 22,
+ /* Clock Generator Registers */
+ TOGBR1 = PAGE(0) | 4,
+ TOGBR2 = PAGE(0) | 5,
+ PWDNRG = PAGE(1) | 9,
+ TAPCTRL = PAGE(1) | 19,
+ TAPREG = PAGE(1) | 20,
+ /* Automatic Frequency Control (AFC) Registers */
+ AUXAFC1 = PAGE(0) | 7,
+ AUXAFC2 = PAGE(0) | 8,
+ AFCCTLADD = PAGE(1) | 21,
+ AFCOUT = PAGE(1) | 22,
+ /* Automatic Power Control (APC) Registers */
+ APCDEL1 = PAGE(0) | 2,
+ APCDEL2 = PAGE(1) | 26,
+ AUXAPC = PAGE(0) | 9,
+ APCRAM = PAGE(0) | 10,
+ APCOFF = PAGE(0) | 11,
+ APCOUT = PAGE(1) | 12,
+ /* Auxiliary DAC Control Register */
+ AUXDAC = PAGE(0) | 12,
+ /* SimCard Control Register */
+ VRPCSIM = PAGE(1) | 23,
+ /* LED Driver Register */
+ AUXLED = PAGE(1) | 24,
+ /* Battery Charger Interface (BCI) Registers */
+ CHGREG = PAGE(0) | 25,
+ BCICTL1 = PAGE(0) | 28,
+ BCICTL2 = PAGE(0) | 29,
+ BCICONF = PAGE(1) | 13,
+ /* Interrupt and Bus Control (IBIC) Registers */
+ ITMASK = PAGE(0) | 28,
+ ITSTATREG = PAGE(0) | 27, /* both pages! */
+ PAGEREG = PAGE(0) | 1, /* both pages! */
+ /* Baseband Codec (BBC) Registers */
+ BULIOFF = PAGE(1) | 2,
+ BULQOFF = PAGE(1) | 3,
+ BULIDAC = PAGE(1) | 5,
+ BULQDAC = PAGE(1) | 4,
+ BULGCAL = PAGE(1) | 14,
+ BULDATA1 = PAGE(0) | 3, /* 16 words */
+ BBCTRL = PAGE(1) | 6,
+ /* Voiceband Codec (VBC) Registers */
+ VBCTRL1 = PAGE(1) | 8,
+ VBCTRL2 = PAGE(1) | 11,
+ VBPOP = PAGE(1) | 10,
+ VBUCTRL = PAGE(1) | 7,
+ VBDCTRL = PAGE(0) | 6,
+};
+#define BULDATA2 BULDATA1
+
+enum togbr2_bits {
+ TOGBR2_KEEPR = (1 << 0), /* Clear KEEPON bit */
+ TOGBR2_KEEPS = (1 << 1), /* Set KEEPON bit */
+ TOGBR2_ACTR = (1 << 2), /* Dectivate MCLK */
+ TOGBR2_ACTS = (1 << 3), /* Activate MCLK */
+ TOGBR2_IBUFPTR1 = (1 << 4), /* Initialize pointer of burst buffer 1 */
+ TOGBR2_IBUFPTR2 = (1 << 5), /* Initialize pointer of burst buffer 2 */
+ TOGBR2_IAPCPTR = (1 << 6), /* Initialize pointer of APC RAM */
+};
+
+enum twl3025_unit {
+ TWL3025_UNIT_AFC,
+ TWL3025_UNIT_MAD,
+ TWL3025_UNIT_ADA,
+ TWL3025_UNIT_VDL,
+ TWL3025_UNIT_VUL,
+};
+
+void twl3025_init(void);
+void twl3025_reg_write(uint8_t reg, uint16_t data);
+uint16_t twl3025_reg_read(uint8_t reg);
+
+void twl3025_power_off(void);
+
+void twl3025_clk13m(int enable);
+
+void twl3025_unit_enable(enum twl3025_unit unit, int on);
+
+enum twl3025_tsp_bits {
+ BULON = 0x80,
+ BULCAL = 0x40,
+ BULENA = 0x20,
+ BDLON = 0x10,
+ BDLCAL = 0x08,
+ BDLENA = 0x04,
+ STARTADC = 0x02,
+};
+
+/* Enqueue a TSP signal change via the TPU */
+void twl3025_tsp_write(uint8_t data);
+
+/* Enqueue a series of TSP commands in the TPU to (de)activate the downlink path */
+void twl3025_downlink(int on, int16_t at);
+
+/* Update the AFC DAC value */
+void twl3025_afc_set(int16_t val);
+
+/* Get the AFC DAC value */
+int16_t twl3025_afc_get(void);
+
+/* Get the AFC DAC output value */
+uint8_t twl3025_afcout_get(void);
+
+/* Force a certain static AFC DAC output value */
+void twl3025_afcout_set(uint8_t val);
+
+#endif
diff --git a/src/target/firmware/include/arm.h b/src/target/firmware/include/arm.h
new file mode 100644
index 00000000..272c9c39
--- /dev/null
+++ b/src/target/firmware/include/arm.h
@@ -0,0 +1,7 @@
+#ifndef _ARM_H
+#define _ARM_H
+
+void arm_enable_interrupts(void);
+int arm_disable_interrupts(void);
+
+#endif
diff --git a/src/target/firmware/include/asm/assembler.h b/src/target/firmware/include/asm/assembler.h
new file mode 100644
index 00000000..b43f9d17
--- /dev/null
+++ b/src/target/firmware/include/asm/assembler.h
@@ -0,0 +1,97 @@
+/*
+ * linux/include/asm-arm/assembler.h
+ *
+ * Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains arm architecture specific defines
+ * for the different processors.
+ *
+ * Do not include any C declarations in this file - it is included by
+ * assembler source.
+ */
+#ifndef __ASSEMBLY__
+#error "Only include this from assembly code"
+#endif
+
+#include <asm/ptrace.h>
+
+#define pull lsl
+#define push lsr
+#define get_byte_0 lsr #24
+#define get_byte_1 lsr #16
+#define get_byte_2 lsr #8
+#define get_byte_3 lsl #0
+#define put_byte_0 lsl #24
+#define put_byte_1 lsl #16
+#define put_byte_2 lsl #8
+#define put_byte_3 lsl #0
+
+#define PLD(code...)
+
+#define MODE_USR USR_MODE
+#define MODE_FIQ FIQ_MODE
+#define MODE_IRQ IRQ_MODE
+#define MODE_SVC SVC_MODE
+
+#define DEFAULT_FIQ MODE_FIQ
+
+/*
+ * LOADREGS - ldm with PC in register list (eg, ldmfd sp!, {pc})
+ */
+#ifdef __STDC__
+#define LOADREGS(cond, base, reglist...)\
+ ldm##cond base,reglist
+#else
+#define LOADREGS(cond, base, reglist...)\
+ ldm/**/cond base,reglist
+#endif
+
+/*
+ * Build a return instruction for this processor type.
+ */
+#define RETINSTR(instr, regs...)\
+ instr regs
+
+/*
+ * Enable and disable interrupts
+ */
+ .macro disable_irq
+ msr cpsr_c, #PSR_I_BIT | SVC_MODE
+ .endm
+
+ .macro enable_irq
+ msr cpsr_c, #SVC_MODE
+ .endm
+
+/*
+ * Save the current IRQ state and disable IRQs. Note that this macro
+ * assumes FIQs are enabled, and that the processor is in SVC mode.
+ */
+ .macro save_and_disable_irqs, oldcpsr
+ mrs \oldcpsr, cpsr
+ disable_irq
+ .endm
+
+/*
+ * Restore interrupt state previously stored in a register. We don't
+ * guarantee that this will preserve the flags.
+ */
+ .macro restore_irqs, oldcpsr
+ msr cpsr_c, \oldcpsr
+ .endm
+
+/*
+ * These two are used to save LR/restore PC over a user-based access.
+ * The old 26-bit architecture requires that we do. On 32-bit
+ * architecture, we can safely ignore this requirement.
+ */
+ .macro save_lr
+ .endm
+
+ .macro restore_pc
+ mov pc, lr
+ .endm
diff --git a/src/target/firmware/include/asm/atomic.h b/src/target/firmware/include/asm/atomic.h
new file mode 100644
index 00000000..19e8ce6f
--- /dev/null
+++ b/src/target/firmware/include/asm/atomic.h
@@ -0,0 +1,106 @@
+/*
+ * linux/include/asm-arm/atomic.h
+ *
+ * Copyright (C) 1996 Russell King.
+ * Copyright (C) 2002 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_ATOMIC_H
+#define __ASM_ARM_ATOMIC_H
+
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ((v)->counter)
+
+#include <asm/system.h>
+#include <asm/compiler.h>
+
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ unsigned long flags;
+ int val;
+
+ local_irq_save(flags);
+ val = v->counter;
+ v->counter = val += i;
+ local_irq_restore(flags);
+
+ return val;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+ unsigned long flags;
+ int val;
+
+ local_irq_save(flags);
+ val = v->counter;
+ v->counter = val -= i;
+ local_irq_restore(flags);
+
+ return val;
+}
+
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *addr &= ~mask;
+ local_irq_restore(flags);
+}
+
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+
+ c = atomic_read(v);
+ while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+ c = old;
+ return c != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+#define atomic_add(i, v) (void) atomic_add_return(i, v)
+#define atomic_inc(v) (void) atomic_add_return(1, v)
+#define atomic_sub(i, v) (void) atomic_sub_return(i, v)
+#define atomic_dec(v) (void) atomic_sub_return(1, v)
+
+#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
+#define atomic_inc_return(v) (atomic_add_return(1, v))
+#define atomic_dec_return(v) (atomic_sub_return(1, v))
+#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+
+#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
+
+/* Atomic operations are already serializing on ARM */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#endif
diff --git a/src/target/firmware/include/asm/bitops.h b/src/target/firmware/include/asm/bitops.h
new file mode 100644
index 00000000..337d800d
--- /dev/null
+++ b/src/target/firmware/include/asm/bitops.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright 1995, Russell King.
+ * Various bits and pieces copyrights include:
+ * Linus Torvalds (test_bit).
+ * Big endian support: Copyright 2001, Nicolas Pitre
+ * reworked by rmk.
+ *
+ * bit 0 is the LSB of an "unsigned long" quantity.
+ *
+ * Please note that the code in this file should never be included
+ * from user space. Many of these are not implemented in assembler
+ * since they would be too costly. Also, they require privileged
+ * instructions (which are not available from user mode) to ensure
+ * that they are atomic.
+ */
+
+#ifndef __ASM_ARM_BITOPS_H
+#define __ASM_ARM_BITOPS_H
+
+#include <asm/system.h>
+
+#define smp_mb__before_clear_bit() mb()
+#define smp_mb__after_clear_bit() mb()
+
+/*
+ * These functions are the basis of our bit ops.
+ *
+ * First, the atomic bitops. These use native endian.
+ */
+static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ *p |= mask;
+ local_irq_restore(flags);
+}
+
+static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ *p &= ~mask;
+ local_irq_restore(flags);
+}
+
+static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ *p ^= mask;
+ local_irq_restore(flags);
+}
+
+static inline int
+____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned int res;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ res = *p;
+ *p = res | mask;
+ local_irq_restore(flags);
+
+ return res & mask;
+}
+
+static inline int
+____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned int res;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ res = *p;
+ *p = res & ~mask;
+ local_irq_restore(flags);
+
+ return res & mask;
+}
+
+static inline int
+____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+ unsigned long flags;
+ unsigned int res;
+ unsigned long mask = 1UL << (bit & 31);
+
+ p += bit >> 5;
+
+ local_irq_save(flags);
+ res = *p;
+ *p = res ^ mask;
+ local_irq_restore(flags);
+
+ return res & mask;
+}
+
+//#include <asm-generic/bitops/non-atomic.h>
+
+/*
+ * A note about Endian-ness.
+ * -------------------------
+ *
+ * When the ARM is put into big endian mode via CR15, the processor
+ * merely swaps the order of bytes within words, thus:
+ *
+ * ------------ physical data bus bits -----------
+ * D31 ... D24 D23 ... D16 D15 ... D8 D7 ... D0
+ * little byte 3 byte 2 byte 1 byte 0
+ * big byte 0 byte 1 byte 2 byte 3
+ *
+ * This means that reading a 32-bit word at address 0 returns the same
+ * value irrespective of the endian mode bit.
+ *
+ * Peripheral devices should be connected with the data bus reversed in
+ * "Big Endian" mode. ARM Application Note 61 is applicable, and is
+ * available from http://www.arm.com/.
+ *
+ * The following assumes that the data bus connectivity for big endian
+ * mode has been followed.
+ *
+ * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0.
+ */
+
+/*
+ * Little endian assembly bitops. nr = 0 -> byte 0 bit 0.
+ */
+extern void _set_bit_le(int nr, volatile unsigned long * p);
+extern void _clear_bit_le(int nr, volatile unsigned long * p);
+extern void _change_bit_le(int nr, volatile unsigned long * p);
+extern int _test_and_set_bit_le(int nr, volatile unsigned long * p);
+extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p);
+extern int _test_and_change_bit_le(int nr, volatile unsigned long * p);
+extern int _find_first_zero_bit_le(const void * p, unsigned size);
+extern int _find_next_zero_bit_le(const void * p, int size, int offset);
+extern int _find_first_bit_le(const unsigned long *p, unsigned size);
+extern int _find_next_bit_le(const unsigned long *p, int size, int offset);
+
+/*
+ * Big endian assembly bitops. nr = 0 -> byte 3 bit 0.
+ */
+extern void _set_bit_be(int nr, volatile unsigned long * p);
+extern void _clear_bit_be(int nr, volatile unsigned long * p);
+extern void _change_bit_be(int nr, volatile unsigned long * p);
+extern int _test_and_set_bit_be(int nr, volatile unsigned long * p);
+extern int _test_and_clear_bit_be(int nr, volatile unsigned long * p);
+extern int _test_and_change_bit_be(int nr, volatile unsigned long * p);
+extern int _find_first_zero_bit_be(const void * p, unsigned size);
+extern int _find_next_zero_bit_be(const void * p, int size, int offset);
+extern int _find_first_bit_be(const unsigned long *p, unsigned size);
+extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
+
+/*
+ * The __* form of bitops are non-atomic and may be reordered.
+ */
+#define ATOMIC_BITOP_LE(name,nr,p) \
+ (__builtin_constant_p(nr) ? \
+ ____atomic_##name(nr, p) : \
+ _##name##_le(nr,p))
+
+#define ATOMIC_BITOP_BE(name,nr,p) \
+ (__builtin_constant_p(nr) ? \
+ ____atomic_##name(nr, p) : \
+ _##name##_be(nr,p))
+
+#define NONATOMIC_BITOP(name,nr,p) \
+ (____nonatomic_##name(nr, p))
+
+/*
+ * These are the little endian, atomic definitions.
+ */
+#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p)
+#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p)
+#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p)
+#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p)
+#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
+#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p)
+#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz)
+#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off)
+#define find_first_bit(p,sz) _find_first_bit_le(p,sz)
+#define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
+
+#define WORD_BITOFF_TO_LE(x) ((x))
+
+#if 0
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/ffs.h>
+
+#include <asm-generic/bitops/fls64.h>
+
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#endif
+
+#define BITS_PER_LONG 32
+#define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
+#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
+
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+ return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+#endif /* _ARM_BITOPS_H */
diff --git a/src/target/firmware/include/asm/ctype.h b/src/target/firmware/include/asm/ctype.h
new file mode 100644
index 00000000..afa36392
--- /dev/null
+++ b/src/target/firmware/include/asm/ctype.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_CTYPE_H
+#define _LINUX_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U 0x01 /* upper */
+#define _L 0x02 /* lower */
+#define _D 0x04 /* digit */
+#define _C 0x08 /* cntrl */
+#define _P 0x10 /* punct */
+#define _S 0x20 /* white space (space/lf/tab) */
+#define _X 0x40 /* hex digit */
+#define _SP 0x80 /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
+#define isdigit(c) ((__ismask(c)&(_D)) != 0)
+#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c) ((__ismask(c)&(_L)) != 0)
+#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c) ((__ismask(c)&(_P)) != 0)
+#define isspace(c) ((__ismask(c)&(_S)) != 0)
+#define isupper(c) ((__ismask(c)&(_U)) != 0)
+#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+ if (isupper(c))
+ c -= 'A'-'a';
+ return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+ if (islower(c))
+ c -= 'a'-'A';
+ return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
diff --git a/src/target/firmware/include/asm/div64.h b/src/target/firmware/include/asm/div64.h
new file mode 100644
index 00000000..36826168
--- /dev/null
+++ b/src/target/firmware/include/asm/div64.h
@@ -0,0 +1,48 @@
+#ifndef __ASM_ARM_DIV64
+#define __ASM_ARM_DIV64
+
+#include <asm/system.h>
+
+/*
+ * The semantics of do_div() are:
+ *
+ * uint32_t do_div(uint64_t *n, uint32_t base)
+ * {
+ * uint32_t remainder = *n % base;
+ * *n = *n / base;
+ * return remainder;
+ * }
+ *
+ * In other words, a 64-bit dividend with a 32-bit divisor producing
+ * a 64-bit result and a 32-bit remainder. To accomplish this optimally
+ * we call a special __do_div64 helper with completely non standard
+ * calling convention for arguments and results (beware).
+ */
+
+#ifdef __ARMEB__
+#define __xh "r0"
+#define __xl "r1"
+#else
+#define __xl "r0"
+#define __xh "r1"
+#endif
+
+#define do_div(n,base) \
+({ \
+ register unsigned int __base asm("r4") = base; \
+ register unsigned long long __n asm("r0") = n; \
+ register unsigned long long __res asm("r2"); \
+ register unsigned int __rem asm(__xh); \
+ asm( __asmeq("%0", __xh) \
+ __asmeq("%1", "r2") \
+ __asmeq("%2", "r0") \
+ __asmeq("%3", "r4") \
+ "bl __do_div64" \
+ : "=r" (__rem), "=r" (__res) \
+ : "r" (__n), "r" (__base) \
+ : "ip", "lr", "cc"); \
+ n = __res; \
+ __rem; \
+})
+
+#endif
diff --git a/src/target/firmware/include/asm/linkage.h b/src/target/firmware/include/asm/linkage.h
new file mode 100644
index 00000000..ac1c900f
--- /dev/null
+++ b/src/target/firmware/include/asm/linkage.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+/* asm-arm/linkage.h */
+
+#define __ALIGN .align 0
+#define __ALIGN_STR ".align 0"
+
+/* linux/linkage.h */
+
+#define ALIGN __ALIGN
+
+#define ENTRY(name) \
+ .globl name; \
+ ALIGN; \
+ name:
+
+#endif
diff --git a/src/target/firmware/include/asm/ptrace.h b/src/target/firmware/include/asm/ptrace.h
new file mode 100644
index 00000000..f3a654e3
--- /dev/null
+++ b/src/target/firmware/include/asm/ptrace.h
@@ -0,0 +1,128 @@
+/*
+ * linux/include/asm-arm/ptrace.h
+ *
+ * Copyright (C) 1996-2003 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_PTRACE_H
+#define __ASM_ARM_PTRACE_H
+
+/*
+ * PSR bits
+ */
+#define USR26_MODE 0x00000000
+#define FIQ26_MODE 0x00000001
+#define IRQ26_MODE 0x00000002
+#define SVC26_MODE 0x00000003
+#define USR_MODE 0x00000010
+#define FIQ_MODE 0x00000011
+#define IRQ_MODE 0x00000012
+#define SVC_MODE 0x00000013
+#define ABT_MODE 0x00000017
+#define UND_MODE 0x0000001b
+#define SYSTEM_MODE 0x0000001f
+#define MODE32_BIT 0x00000010
+#define MODE_MASK 0x0000001f
+#define PSR_T_BIT 0x00000020
+#define PSR_F_BIT 0x00000040
+#define PSR_I_BIT 0x00000080
+#define PSR_J_BIT 0x01000000
+#define PSR_Q_BIT 0x08000000
+#define PSR_V_BIT 0x10000000
+#define PSR_C_BIT 0x20000000
+#define PSR_Z_BIT 0x40000000
+#define PSR_N_BIT 0x80000000
+#define PCMASK 0
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f 0xff000000 /* Flags */
+#define PSR_s 0x00ff0000 /* Status */
+#define PSR_x 0x0000ff00 /* Extension */
+#define PSR_c 0x000000ff /* Control */
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This struct defines the way the registers are stored on the
+ * stack during a system call. Note that sizeof(struct pt_regs)
+ * has to be a multiple of 8.
+ */
+struct pt_regs {
+ long uregs[18];
+};
+
+#define ARM_cpsr uregs[16]
+#define ARM_pc uregs[15]
+#define ARM_lr uregs[14]
+#define ARM_sp uregs[13]
+#define ARM_ip uregs[12]
+#define ARM_fp uregs[11]
+#define ARM_r10 uregs[10]
+#define ARM_r9 uregs[9]
+#define ARM_r8 uregs[8]
+#define ARM_r7 uregs[7]
+#define ARM_r6 uregs[6]
+#define ARM_r5 uregs[5]
+#define ARM_r4 uregs[4]
+#define ARM_r3 uregs[3]
+#define ARM_r2 uregs[2]
+#define ARM_r1 uregs[1]
+#define ARM_r0 uregs[0]
+#define ARM_ORIG_r0 uregs[17]
+
+#define user_mode(regs) \
+ (((regs)->ARM_cpsr & 0xf) == 0)
+
+#ifdef CONFIG_ARM_THUMB
+#define thumb_mode(regs) \
+ (((regs)->ARM_cpsr & PSR_T_BIT))
+#else
+#define thumb_mode(regs) (0)
+#endif
+
+#define processor_mode(regs) \
+ ((regs)->ARM_cpsr & MODE_MASK)
+
+#define interrupts_enabled(regs) \
+ (!((regs)->ARM_cpsr & PSR_I_BIT))
+
+#define fast_interrupts_enabled(regs) \
+ (!((regs)->ARM_cpsr & PSR_F_BIT))
+
+#define condition_codes(regs) \
+ ((regs)->ARM_cpsr & (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT))
+
+/* Are the current registers suitable for user mode?
+ * (used to maintain security in signal handlers)
+ */
+static inline int valid_user_regs(struct pt_regs *regs)
+{
+ if (user_mode(regs) &&
+ (regs->ARM_cpsr & (PSR_F_BIT|PSR_I_BIT)) == 0)
+ return 1;
+
+ /*
+ * Force CPSR to something logical...
+ */
+ regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT;
+
+ return 0;
+}
+
+#define pc_pointer(v) \
+ ((v) & ~PCMASK)
+
+#define instruction_pointer(regs) \
+ (pc_pointer((regs)->ARM_pc))
+
+#define profile_pc(regs) instruction_pointer(regs)
+
+#endif /* __ASSEMBLY__ */
+
+#endif
+
diff --git a/src/target/firmware/include/asm/system.h b/src/target/firmware/include/asm/system.h
new file mode 100644
index 00000000..2bf0cc51
--- /dev/null
+++ b/src/target/firmware/include/asm/system.h
@@ -0,0 +1,109 @@
+#ifndef __ASM_ARM_SYSTEM_H
+#define __ASM_ARM_SYSTEM_H
+
+/* Generic ARM7TDMI (ARMv4T) synchronisation primitives, mostly
+ * taken from Linux kernel source, licensed under GPL */
+
+#define local_irq_save(x) \
+ ({ \
+ unsigned long temp; \
+ (void) (&temp == &x); \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_save\n" \
+" orr %1, %0, #128\n" \
+" msr cpsr_c, %1" \
+ : "=r" (x), "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Enable IRQs
+ */
+#define local_irq_enable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_enable\n" \
+" bic %0, %0, #128\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Disable IRQs
+ */
+#define local_irq_disable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_disable\n" \
+" orr %0, %0, #128\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Enable FIQs
+ */
+#define local_fiq_enable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ stf\n" \
+" bic %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Disable FIQs
+ */
+#define local_fiq_disable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ clf\n" \
+" orr %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Save the current interrupt enable state.
+ */
+#define local_save_flags(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_save_flags" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+
+/*
+ * restore saved IRQ & FIQ state
+ */
+#define local_irq_restore(x) \
+ __asm__ __volatile__( \
+ "msr cpsr_c, %0 @ local_irq_restore\n" \
+ : \
+ : "r" (x) \
+ : "memory", "cc")
+
+#define irqs_disabled() \
+({ \
+ unsigned long flags; \
+ local_save_flags(flags); \
+ (int)(flags & PSR_I_BIT); \
+})
+
+#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+
+#endif
diff --git a/src/target/firmware/include/board.h b/src/target/firmware/include/board.h
new file mode 100644
index 00000000..558b636f
--- /dev/null
+++ b/src/target/firmware/include/board.h
@@ -0,0 +1,6 @@
+#ifndef _BOARD_H
+#define _BOARD_H
+
+void board_init(void);
+
+#endif /* _BOARD_H */
diff --git a/src/target/firmware/include/calypso/backlight.h b/src/target/firmware/include/calypso/backlight.h
new file mode 100644
index 00000000..3a6abd55
--- /dev/null
+++ b/src/target/firmware/include/calypso/backlight.h
@@ -0,0 +1,10 @@
+#ifndef _CAL_BACKLIGHT_H
+#define _CAL_BACKLIGHT_H
+
+/* Switch backlight to PWL mode (or back) */
+void bl_mode_pwl(int on);
+
+/* Set the backlight level */
+void bl_level(uint8_t level);
+
+#endif /* CAL_BACKLIGHT_H */
diff --git a/src/target/firmware/include/calypso/clock.h b/src/target/firmware/include/calypso/clock.h
new file mode 100644
index 00000000..abcfde1d
--- /dev/null
+++ b/src/target/firmware/include/calypso/clock.h
@@ -0,0 +1,67 @@
+#ifndef _CALYPSO_CLK_H
+#define _CALYPSO_CLK_H
+
+#include <stdint.h>
+
+#define CALYPSO_PLL26_52_MHZ ((2 << 8) | 0)
+#define CALYPSO_PLL26_86_7_MHZ ((10 << 8) | 2)
+#define CALYPSO_PLL26_87_MHZ ((3 << 8) | 0)
+#define CALYPSO_PLL13_104_MHZ ((8 << 8) | 0)
+
+enum mclk_div {
+ _ARM_MCLK_DIV_1 = 0,
+ ARM_MCLK_DIV_1 = 1,
+ ARM_MCLK_DIV_2 = 2,
+ ARM_MCLK_DIV_3 = 3,
+ ARM_MCLK_DIV_4 = 4,
+ ARM_MCLK_DIV_5 = 5,
+ ARM_MCLK_DIV_6 = 6,
+ ARM_MCLK_DIV_7 = 7,
+ ARM_MCLK_DIV_1_5 = 0x80 | 1,
+ ARM_MCLK_DIV_2_5 = 0x80 | 2,
+};
+
+void calypso_clock_set(uint8_t vtcxo_div2, uint16_t inp, enum mclk_div mclk_div);
+void calypso_pll_set(uint16_t inp);
+void calypso_clk_dump(void);
+
+/* CNTL_RST */
+enum calypso_rst {
+ RESET_DSP = (1 << 1),
+ RESET_EXT = (1 << 2),
+ RESET_WDOG = (1 << 3),
+};
+
+void calypso_reset_set(enum calypso_rst calypso_rst, int active);
+int calypso_reset_get(enum calypso_rst);
+
+enum calypso_bank {
+ CALYPSO_nCS0 = 0,
+ CALYPSO_nCS1 = 2,
+ CALYPSO_nCS2 = 4,
+ CALYPSO_nCS3 = 6,
+ CALYPSO_nCS7 = 8,
+ CALYPSO_CS4 = 0xa,
+ CALYPSO_nCS6 = 0xc,
+};
+
+enum calypso_mem_width {
+ CALYPSO_MEM_8bit = 0,
+ CALYPSO_MEM_16bit = 1,
+ CALYPSO_MEM_32bit = 2,
+};
+
+void calypso_mem_cfg(enum calypso_bank bank, uint8_t ws,
+ enum calypso_mem_width width, int we);
+
+/* Enable or disable the internal bootrom mapped to 0x0000'0000 */
+void calypso_bootrom(int enable);
+
+/* Enable or disable the debug unit */
+void calypso_debugunit(int enable);
+
+/* configure the RHEA bus bridge[s] */
+void calypso_rhea_cfg(uint8_t fac0, uint8_t fac1, uint8_t timeout,
+ uint8_t ws_h, uint8_t ws_l, uint8_t w_en0, uint8_t w_en1);
+
+#endif /* _CALYPSO_CLK_H */
diff --git a/src/target/firmware/include/calypso/dma.h b/src/target/firmware/include/calypso/dma.h
new file mode 100644
index 00000000..00b9bde7
--- /dev/null
+++ b/src/target/firmware/include/calypso/dma.h
@@ -0,0 +1,6 @@
+#ifndef _CALYPSO_DMA_H
+#define _CALYPSO_DMA_H
+
+void dma_init(void);
+
+#endif /* _CALYPSO_DMA_H */
diff --git a/src/target/firmware/include/calypso/dsp.h b/src/target/firmware/include/calypso/dsp.h
new file mode 100644
index 00000000..24779a62
--- /dev/null
+++ b/src/target/firmware/include/calypso/dsp.h
@@ -0,0 +1,31 @@
+#ifndef _CALYPSO_DSP_H
+#define _CALYPSO_DSP_H
+
+#include <calypso/dsp_api.h>
+
+struct dsp_api {
+ T_NDB_MCU_DSP *ndb;
+ T_DB_DSP_TO_MCU *db_r;
+ T_DB_MCU_TO_DSP *db_w;
+ T_PARAM_MCU_DSP *param;
+ int r_page;
+ int w_page;
+ int r_page_used;
+ int frame_ctr;
+};
+
+extern struct dsp_api dsp_api;
+
+void dsp_power_on(void);
+void dsp_dump_version(void);
+void dsp_dump(void);
+void dsp_checksum_task(void);
+void dsp_api_memset(uint16_t *ptr, int octets);
+void dsp_load_afc_dac(uint16_t afc);
+void dsp_load_apc_dac(uint16_t apc);
+void dsp_end_scenario(void);
+
+void dsp_load_rx_task(uint16_t task, uint8_t burst_id, uint8_t tsc);
+void dsp_load_tx_task(uint16_t task, uint8_t burst_id, uint8_t tsc);
+
+#endif
diff --git a/src/target/firmware/include/calypso/dsp_api.h b/src/target/firmware/include/calypso/dsp_api.h
new file mode 100644
index 00000000..5444ec1d
--- /dev/null
+++ b/src/target/firmware/include/calypso/dsp_api.h
@@ -0,0 +1,1554 @@
+#ifndef _CAL_DSP_API_H
+#define _CAL_DSP_API_H
+
+/* This is a header file with structures imported from the TSM30 source code (l1_defty.h)
+ *
+ * As this header file only is a list of definitions and data structures, it is
+ * not ocnsidered to be a copyrightable work itself.
+ *
+ * Nonetheless, it might be good to rewrite it (without ugly typedefs!) */
+
+#if(L1_DYN_DSP_DWNLD == 1)
+ #include "l1_dyn_dwl_defty.h"
+#endif
+
+/* Include a header file that defines everything this l1_defty.h needs */
+#include "l1_environment.h"
+
+#define BASE_API_NDB 0xFFD001A8L /* 268 words */
+#define BASE_API_PARAM 0xFFD00862L /* 57 words */
+#define BASE_API_R_PAGE_0 0xFFD00050L /* 20 words */
+#define BASE_API_R_PAGE_1 0xFFD00078L /* 20 words */
+#define BASE_API_W_PAGE_0 0xFFD00000L /* 20 words */
+#define BASE_API_W_PAGE_1 0xFFD00028L /* 20 words */
+
+
+/***********************************************************/
+/* */
+/* Data structure for global info components. */
+/* */
+/***********************************************************/
+
+typedef struct
+{
+ API d_task_d; // (0) Downlink task command.
+ API d_burst_d; // (1) Downlink burst identifier.
+ API d_task_u; // (2) Uplink task command.
+ API d_burst_u; // (3) Uplink burst identifier.
+ API d_task_md; // (4) Downlink Monitoring (FB/SB) command.
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ API d_background; // (5) Background tasks
+#else
+ API d_reserved; // (5) Reserved
+#endif
+ API d_debug; // (6) Debug/Acknowledge/general purpose word.
+ API d_task_ra; // (7) RA task command.
+ API d_fn; // (8) FN, in Rep. period and FN%104, used for TRAFFIC/TCH only.
+ // bit [0..7] -> b_fn_report, FN in the normalized reporting period.
+ // bit [8..15] -> b_fn_sid, FN % 104, used for SID positionning.
+ API d_ctrl_tch; // (9) Tch channel description.
+ // bit [0..3] -> b_chan_mode, channel mode.
+ // bit [4..5] -> b_chan_type, channel type.
+ // bit [6] -> reset SACCH
+ // bit [7] -> vocoder ON
+ // bit [8] -> b_sync_tch_ul, synchro. TCH/UL.
+ // bit [9] -> b_sync_tch_dl, synchro. TCH/DL.
+ // bit [10] -> b_stop_tch_ul, stop TCH/UL.
+ // bit [11] -> b_stop_tch_dl, stop TCH/DL.
+ // bit [12.13] -> b_tch_loop, tch loops A/B/C.
+ API hole; // (10) unused hole.
+
+#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
+ API d_ctrl_abb; // (11) Bit field indicating the analog baseband register to send.
+ // bit [0] -> b_ramp: the ramp information(a_ramp[]) is located in NDB
+ // bit [1.2] -> unused
+ // bit [3] -> b_apcdel: delays-register in NDB
+ // bit [4] -> b_afc: freq control register in DB
+ // bit [5..15] -> unused
+#endif
+ API a_a5fn[2]; // (12..13) Encryption Frame number.
+ // word 0, bit [0..4] -> T2.
+ // word 0, bit [5..10] -> T3.
+ // word 1, bit [0..11] -> T1.
+ API d_power_ctl; // (14) Power level control.
+ API d_afc; // (15) AFC value (enabled by "b_afc" in "d_ctrl_TCM4400 or in d_ctrl_abb").
+ API d_ctrl_system; // (16) Controle Register for RESET/RESUME.
+ // bit [0..2] -> b_tsq, training sequence.
+ // bit [3] -> b_bcch_freq_ind, BCCH frequency indication.
+ // bit [15] -> b_task_abort, DSP task abort command.
+}
+T_DB_MCU_TO_DSP;
+
+typedef struct
+{
+ API d_task_d; // (0) Downlink task command.
+ API d_burst_d; // (1) Downlink burst identifier.
+ API d_task_u; // (2) Uplink task command.
+ API d_burst_u; // (3) Uplink burst identifier.
+ API d_task_md; // (4) Downlink Monitoring (FB/SB) task command.
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ API d_background; // (5) Background tasks
+#else
+ API d_reserved; // (5) Reserved
+#endif
+ API d_debug; // (6) Debug/Acknowledge/general purpose word.
+ API d_task_ra; // (7) RA task command.
+
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ API a_serv_demod[4]; // ( 8..11) Serv. cell demod. result, array of 4 words (D_TOA,D_PM,D_ANGLE,D_SNR).
+ API a_pm[3]; // (12..14) Power measurement results, array of 3 words.
+ API a_sch[5]; // (15..19) Header + SB information, array of 5 words.
+#else
+ API a_pm[3]; // ( 8..10) Power measurement results, array of 3 words.
+ API a_serv_demod[4]; // (11..14) Serv. cell demod. result, array of 4 words (D_TOA,D_PM,D_ANGLE,D_SNR).
+ API a_sch[5]; // (15..19) Header + SB information, array of 5 words.
+#endif
+}
+T_DB_DSP_TO_MCU;
+
+#if (DSP == 34) || (DSP == 35) || (DSP == 36) // NDB GSM
+ typedef struct
+ {
+ // MISC Tasks
+ API d_dsp_page;
+
+ // DSP status returned (DSP --> MCU).
+ API d_error_status;
+
+ // RIF control (MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+
+ API d_dsp_test;
+
+ // Words dedicated to Software version (DSP code + Patch)
+ API d_version_number1;
+ API d_version_number2;
+
+ API d_debug_ptr;
+ API d_debug_bk;
+
+ API d_pll_config;
+
+ // GSM/GPRS DSP Debug trace support
+ API p_debug_buffer;
+ API d_debug_buffer_size;
+ API d_debug_trace_type;
+
+ #if (W_A_DSP_IDLE3 == 1)
+ // DSP report its state: 0 run, 1 Idle1, 2 Idle2, 3 Idle3.
+ API d_dsp_state;
+ // 5 words are reserved for any possible mapping modification
+ API d_hole1_ndb[2];
+ #else
+ // 6 words are reserved for any possible mapping modification
+ API d_hole1_ndb[3];
+ #endif
+
+ #if (AMR == 1)
+ API p_debug_amr;
+ #else
+ API d_hole_debug_amr;
+ #endif
+
+ #if (CHIPSET == 12)
+ #if (DSP == 35) || (DSP == 36)
+ API d_hole2_ndb[1];
+ API d_mcsi_select;
+ #else
+ API d_hole2_ndb[2];
+ #endif
+ #else
+ API d_hole2_ndb[2];
+ #endif
+
+ // New words APCDEL1 and APCDEL2 for 2TX: TX/PRACH combinations
+ API d_apcdel1_bis;
+ API d_apcdel2_bis;
+
+
+ // New registers due to IOTA analog base band
+ API d_apcdel2;
+ API d_vbctrl2;
+ API d_bulgcal;
+
+ // Analog Based Band
+ API d_afcctladd;
+
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
+ API d_vbctrl1;
+ #endif
+
+ API d_bbctrl;
+
+ // Monitoring tasks control (MCU <- DSP)
+ // FB task
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // SB Task
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ API d_audio_gain_ul;
+ API d_audio_gain_dl;
+
+ // Controller of the melody E2 audio compressor
+ API d_audio_compressor_ctrl;
+
+ // AUDIO module
+ API d_audio_init;
+ API d_audio_status;
+
+ // Audio tasks
+ // TONES (MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+ API d_shiftdl;
+ API d_shiftul;
+
+ API d_aec_ctrl;
+
+ API d_es_level_api;
+ API d_mu_api;
+
+ // Melody Ringer module
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+
+ // selection of the melody format
+ API d_melody_selection;
+
+ // Holes due to the format melody E1
+ API a_melo_holes[3];
+
+ // Speech Recognition module
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+
+ // Audio buffer
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+
+ // V42bis module
+ API d_v42b_nego0;
+ API d_v42b_nego1;
+ API d_v42b_control;
+ API d_v42b_ratio_ind;
+ API d_mcu_control;
+ API d_mcu_control_sema;
+
+ // Background tasks
+ API d_background_enable;
+ API d_background_abort;
+ API d_background_state;
+ API d_max_background;
+ API a_background_tasks[16];
+ API a_back_task_io[16];
+
+ // GEA module defined in l1p_deft.h (the following section is overlaid with GPRS NDB memory)
+ API d_gea_mode_ovly;
+ API a_gea_kc_ovly[4];
+
+#if (ANLG_FAM == 3)
+ // SYREN specific registers
+ API d_vbpop;
+ API d_vau_delay_init;
+ API d_vaud_cfg;
+ API d_vauo_onoff;
+ API d_vaus_vol;
+ API d_vaud_pll;
+ API d_hole3_ndb[1];
+#elif ((ANLG_FAM == 1) || (ANLG_FAM == 2))
+
+ API d_hole3_ndb[7];
+
+#endif
+
+ // word used for the init of USF threshold
+ API d_thr_usf_detect;
+
+ // Encryption module
+ API d_a5mode; // Encryption Mode.
+
+ API d_sched_mode_gprs_ovly;
+
+ // 7 words are reserved for any possible mapping modification
+ API d_hole4_ndb[5];
+
+ // Ramp definition for Omega device
+ API a_ramp[16];
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+
+ // Traffic downlink data frames......(!!)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API a_kc[4]; // Encryption Key Code.
+
+ // Integrated Data Services module
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ // GTT API mapping for DSP code 34 (for test only)
+ #if (L1_GTT == 1)
+ API d_tty_status;
+ API d_tty_detect_thres;
+ API d_ctm_detect_shift;
+ API d_tty_fa_thres;
+ API d_tty_mod_norm;
+ API d_tty_reset_buffer_ul;
+ API d_tty_loop_ctrl;
+ API p_tty_loop_buffer;
+ #else
+ API a_tty_holes[8];
+ #endif
+
+ API a_sr_holes0[414];
+
+ #if (L1_NEW_AEC)
+ // new AEC
+ API d_cont_filter;
+ API d_granularity_att;
+ API d_coef_smooth;
+ API d_es_level_max;
+ API d_fact_vad;
+ API d_thrs_abs;
+ API d_fact_asd_fil;
+ API d_fact_asd_mut;
+ API d_far_end_pow_h;
+ API d_far_end_pow_l;
+ API d_far_end_noise_h;
+ API d_far_end_noise_l;
+ #else
+ API a_new_aec_holes[12];
+ #endif // L1_NEW_AEC
+
+ // Speech recognition model
+ API a_sr_holes1[145];
+ API d_cport_init;
+ API d_cport_ctrl;
+ API a_cport_cfr[2];
+ API d_cport_tcl_tadt;
+ API d_cport_tdat;
+ API d_cport_tvs;
+ API d_cport_status;
+ API d_cport_reg_value;
+
+ API a_cport_holes[1011];
+
+ API a_model[1041];
+
+ // EOTD buffer
+#if (L1_EOTD==1)
+ API d_eotd_first;
+ API d_eotd_max;
+ API d_eotd_nrj_high;
+ API d_eotd_nrj_low;
+ API a_eotd_crosscor[18];
+#else
+ API a_eotd_holes[22];
+#endif
+ // AMR ver 1.0 buffers
+ API a_amr_config[4];
+ API a_ratscch_ul[6];
+ API a_ratscch_dl[6];
+ API d_amr_snr_est; // estimation of the SNR of the AMR speech block
+ #if (L1_VOICE_MEMO_AMR)
+ API d_amms_ul_voc;
+ #else
+ API a_voice_memo_amr_holes[1];
+ #endif
+ API d_thr_onset_afs; // thresh detection ONSET AFS
+ API d_thr_sid_first_afs; // thresh detection SID_FIRST AFS
+ API d_thr_ratscch_afs; // thresh detection RATSCCH AFS
+ API d_thr_update_afs; // thresh detection SID_UPDATE AFS
+ API d_thr_onset_ahs; // thresh detection ONSET AHS
+ API d_thr_sid_ahs; // thresh detection SID frames AHS
+ API d_thr_ratscch_marker;// thresh detection RATSCCH MARKER
+ API d_thr_sp_dgr; // thresh detection SPEECH DEGRADED/NO_DATA
+ API d_thr_soft_bits;
+ #if (MELODY_E2)
+ API d_melody_e2_osc_stop;
+ API d_melody_e2_osc_active;
+ API d_melody_e2_semaphore;
+ API a_melody_e2_osc[16][3];
+ API d_melody_e2_globaltimefactor;
+ API a_melody_e2_instrument_ptr[8];
+ API d_melody_e2_deltatime;
+
+ #if (AMR_THRESHOLDS_WORKAROUND)
+ API a_d_macc_thr_afs[8];
+ API a_d_macc_thr_ahs[6];
+ #else
+ API a_melody_e2_holes0[14];
+ #endif
+
+ API a_melody_e2_holes1[693];
+ API a_dsp_trace[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_DSP_TRACE];
+ API a_melody_e2_instrument_wave[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_INSTRUMENT];
+ #else
+ API d_holes[61];
+ #if (AMR_THRESHOLDS_WORKAROUND)
+ API a_d_macc_thr_afs[8];
+ API a_d_macc_thr_ahs[6];
+ #endif
+ #endif
+
+ }
+ T_NDB_MCU_DSP;
+#elif (DSP == 33) // NDB GSM
+ typedef struct
+ {
+ // MISC Tasks
+ API d_dsp_page;
+
+ // DSP status returned (DSP --> MCU).
+ API d_error_status;
+
+ // RIF control (MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+
+ API d_dsp_test;
+
+ // Words dedicated to Software version (DSP code + Patch)
+ API d_version_number1;
+ API d_version_number2;
+
+ API d_debug_ptr;
+ API d_debug_bk;
+
+ API d_pll_config;
+
+ // GSM/GPRS DSP Debug trace support
+ API p_debug_buffer;
+ API d_debug_buffer_size;
+ API d_debug_trace_type;
+
+ #if (W_A_DSP_IDLE3 == 1)
+ // DSP report its state: 0 run, 1 Idle1, 2 Idle2, 3 Idle3.
+ API d_dsp_state;
+ // 10 words are reserved for any possible mapping modification
+ API d_hole1_ndb[5];
+ #else
+ // 11 words are reserved for any possible mapping modification
+ API d_hole1_ndb[6];
+ #endif
+
+ // New words APCDEL1 and APCDEL2 for 2TX: TX/PRACH combinations
+ API d_apcdel1_bis;
+ API d_apcdel2_bis;
+
+
+ // New registers due to IOTA analog base band
+ API d_apcdel2;
+ API d_vbctrl2;
+ API d_bulgcal;
+
+ // Analog Based Band
+ API d_afcctladd;
+
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif ((ANLG_FAM == 2) || (ANLG_FAM == 3))
+ API d_vbctrl1;
+ #endif
+
+ API d_bbctrl;
+
+ // Monitoring tasks control (MCU <- DSP)
+ // FB task
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // SB Task
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ API d_audio_gain_ul;
+ API d_audio_gain_dl;
+
+ // Controller of the melody E2 audio compressor
+ API d_audio_compressor_ctrl;
+
+ // AUDIO module
+ API d_audio_init;
+ API d_audio_status;
+
+ // Audio tasks
+ // TONES (MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+ API d_shiftdl;
+ API d_shiftul;
+
+ API d_aec_ctrl;
+
+ API d_es_level_api;
+ API d_mu_api;
+
+ // Melody Ringer module
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+
+ // selection of the melody format
+ API d_melody_selection;
+
+ // Holes due to the format melody E1
+ API a_melo_holes[3];
+
+ // Speech Recognition module
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+
+ // Audio buffer
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+
+ // V42bis module
+ API d_v42b_nego0;
+ API d_v42b_nego1;
+ API d_v42b_control;
+ API d_v42b_ratio_ind;
+ API d_mcu_control;
+ API d_mcu_control_sema;
+
+ // Background tasks
+ API d_background_enable;
+ API d_background_abort;
+ API d_background_state;
+ API d_max_background;
+ API a_background_tasks[16];
+ API a_back_task_io[16];
+
+ // GEA module defined in l1p_deft.h (the following section is overlaid with GPRS NDB memory)
+ API d_gea_mode_ovly;
+ API a_gea_kc_ovly[4];
+
+ API d_hole3_ndb[8];
+
+ // Encryption module
+ API d_a5mode; // Encryption Mode.
+
+ API d_sched_mode_gprs_ovly;
+
+ // 7 words are reserved for any possible mapping modification
+ API d_hole4_ndb[5];
+
+ // Ramp definition for Omega device
+ API a_ramp[16];
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+
+ // Traffic downlink data frames......(!!)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API a_kc[4]; // Encryption Key Code.
+
+ // Integrated Data Services module
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ #if (L1_NEW_AEC)
+ // new AEC
+ API a_new_aec_holes[422];
+ API d_cont_filter;
+ API d_granularity_att;
+ API d_coef_smooth;
+ API d_es_level_max;
+ API d_fact_vad;
+ API d_thrs_abs;
+ API d_fact_asd_fil;
+ API d_fact_asd_mut;
+ API d_far_end_pow_h;
+ API d_far_end_pow_l;
+ API d_far_end_noise_h;
+ API d_far_end_noise_l;
+ #endif
+
+ // Speech recognition model
+ #if (L1_NEW_AEC)
+ API a_sr_holes[1165];
+ #else
+ API a_sr_holes[1599];
+ #endif // L1_NEW_AEC
+ API a_model[1041];
+
+ // EOTD buffer
+ #if (L1_EOTD==1)
+ API d_eotd_first;
+ API d_eotd_max;
+ API d_eotd_nrj_high;
+ API d_eotd_nrj_low;
+ API a_eotd_crosscor[18];
+ #else
+ API a_eotd_holes[22];
+ #endif
+
+ #if (MELODY_E2)
+ API a_melody_e2_holes0[27];
+ API d_melody_e2_osc_used;
+ API d_melody_e2_osc_active;
+ API d_melody_e2_semaphore;
+ API a_melody_e2_osc[16][3];
+ API d_melody_e2_globaltimefactor;
+ API a_melody_e2_instrument_ptr[8];
+ API a_melody_e2_holes1[708];
+ API a_dsp_trace[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_DSP_TRACE];
+ API a_melody_e2_instrument_wave[SC_AUDIO_MELODY_E2_MAX_SIZE_OF_INSTRUMENT];
+ #endif
+ }
+ T_NDB_MCU_DSP;
+
+#elif ((DSP == 32) || (DSP == 31))
+ typedef struct
+ {
+ // Monitoring tasks control..........(MCU <- DSP)
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ #if (SPEECH_RECO)
+ // FACCH downlink information........(!!)
+ API a_fu[3]; // Header + FACCH uplink information
+ // The size of this buffer is 15 word but some speech reco words
+ // are overlayer with this buffer. This is the reason why the size is 3 instead of 15.
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API sr_hole1; // hole
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API sr_holes_1[4]; // hole
+ #else
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+ #endif
+
+ // Traffic uplink data frames........(!!)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API d_a5mode; // Encryption Mode.
+ API a_kc[4]; // Encryption Key Code.
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ // OMEGA...........................(MCU -> DSP).
+ #if ((ANLG_FAM == 1) || (ANLG_FAM == 2))
+ API a_ramp[16];
+ #if (MELODY_E1)
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+ #if (DSP==31)
+ // selection of the melody format
+ API d_melody_selection;
+ API holes[9];
+ #else // DSP==32
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4];
+ #endif // DSP 32
+
+ #else // NO MELODY E1
+ #if (DSP==31)
+ // selection of the melody format
+ API d_melody_selection;
+ API holes[43]; // 43 unused holes.
+ #else // DSP==32
+ API holes[34]; // 34 unused holes.
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4];
+ #endif //DSP == 32
+ #endif // NO MELODY E1
+
+ API d_debug3;
+ API d_debug2;
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+ API d_afcctladd;
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_aec_ctrl;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif (ANLG_FAM == 2)
+ API d_vbctrl1;
+ #endif
+
+ API d_bbctrl;
+ #else
+ #error DSPCODE not supported with given ANALOG
+ #endif //(ANALOG)1, 2
+ //...................................(MCU -> DSP).
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ // TONES.............................(MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+
+ // PLL...............................(MCU -> DSP).
+ API d_pll_clkmod1;
+ API d_pll_clkmod2;
+
+ // DSP status returned..........(DSP --> MCU).
+ API d_error_status;
+
+ // RIF control.......................(MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_shiftdl;
+ API d_shiftul;
+
+ API p_saec_prog;
+ API p_aec_prog;
+ API p_spenh_prog;
+
+ API a_ovly[75];
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ #if (SPEECH_RECO)
+ API a_data_buf_ul[3];
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+ API sr_holes_2[6];
+ API a_data_buf_dl[37];
+
+ API a_hole[24];
+
+ API d_sched_mode_gprs_ovly;
+
+ API fir_holes1[384];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+
+ API a_model[1041]; // array of the speech reco model
+ #else
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ API a_hole[24];
+
+ API d_sched_mode_gprs_ovly;
+
+ API fir_holes1[384];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+
+#if (L1_EOTD ==1)
+ API a_eotd_hole[369];
+
+ API d_eotd_first;
+ API d_eotd_max;
+ API d_eotd_nrj_high;
+ API d_eotd_nrj_low;
+ API a_eotd_crosscor[18];
+#endif
+ #endif
+ }
+ T_NDB_MCU_DSP;
+
+
+#else // OTHER DSP CODE like 17
+
+typedef struct
+{
+ // Monitoring tasks control..........(MCU <- DSP)
+ API d_fb_det; // FB detection result. (1 for FOUND).
+ API d_fb_mode; // Mode for FB detection algorithm.
+ API a_sync_demod[4]; // FB/SB demod. result, (D_TOA,D_PM,D_ANGLE,D_SNR).
+
+ // CCCH/SACCH downlink information...(!!)
+ API a_cd[15]; // Header + CCCH/SACCH downlink information.
+
+ // FACCH downlink information........(!!)
+ API a_fd[15]; // Header + FACCH downlink information.
+
+ // Traffic downlink data frames......(!!)
+ #if (DATA14_4 == 0)
+ API a_dd_0[20]; // Header + DATA traffic downlink information, sub. chan. 0.
+ API a_dd_1[20]; // Header + DATA traffic downlink information, sub. chan. 1.
+ #endif
+ #if (DATA14_4 == 1)
+ API a_dd_0[22]; // Header + DATA traffic downlink information, sub. chan. 0.
+ API a_dd_1[22]; // Header + DATA traffic downlink information, sub. chan. 1.
+ #endif
+
+ // CCCH/SACCH uplink information.....(!!)
+ API a_cu[15]; // Header + CCCH/SACCH uplink information.
+
+ #if (SPEECH_RECO)
+ // FACCH downlink information........(!!)
+ API a_fu[3]; // Header + FACCH uplink information
+ // The size of this buffer is 15 word but some speech reco words
+ // are overlayer with this buffer. This is the reason why the size is 3 instead of 15.
+ API d_sr_status; // status of the DSP speech reco task
+ API d_sr_param; // paramters for the DSP speech reco task: OOV threshold.
+ API sr_hole1; // hole
+ API d_sr_bit_exact_test; // bit exact test
+ API d_sr_nb_words; // number of words used in the speech recognition task
+ API d_sr_db_level; // estimate voice level in dB
+ API d_sr_db_noise; // estimate noise in dB
+ API d_sr_mod_size; // size of the model
+ API sr_holes_1[4]; // hole
+ #else
+ // FACCH downlink information........(!!)
+ API a_fu[15]; // Header + FACCH uplink information
+ #endif
+
+ // Traffic uplink data frames........(!!)
+ #if (DATA14_4 == 0)
+ API a_du_0[20]; // Header + DATA traffic uplink information, sub. chan. 0.
+ API a_du_1[20]; // Header + DATA traffic uplink information, sub. chan. 1.
+ #endif
+ #if (DATA14_4 == 1)
+ API a_du_0[22]; // Header + DATA traffic uplink information, sub. chan. 0.
+ API a_du_1[22]; // Header + DATA traffic uplink information, sub. chan. 1.
+ #endif
+
+ // Random access.....................(MCU -> DSP).
+ API d_rach; // RACH information.
+
+ //...................................(MCU -> DSP).
+ API d_a5mode; // Encryption Mode.
+ API a_kc[4]; // Encryption Key Code.
+ API d_tch_mode; // TCH mode register.
+ // bit [0..1] -> b_dai_mode.
+ // bit [2] -> b_dtx.
+
+ // OMEGA...........................(MCU -> DSP).
+
+#if ((ANLG_FAM == 1) || (ANLG_FAM == 2))
+ API a_ramp[16];
+ #if (MELODY_E1)
+ API d_melo_osc_used;
+ API d_melo_osc_active;
+ API a_melo_note0[4];
+ API a_melo_note1[4];
+ API a_melo_note2[4];
+ API a_melo_note3[4];
+ API a_melo_note4[4];
+ API a_melo_note5[4];
+ API a_melo_note6[4];
+ API a_melo_note7[4];
+ #if (DSP == 17)
+ // selection of the melody format
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4];
+ #else
+ API d_melody_selection;
+ API holes[9];
+ #endif
+ #else // NO MELODY E1
+ // selection of the melody format
+ #if (DSP == 17)
+ API holes[34]; // 34 unused holes.
+ API d_dco_type; // Tide
+ API p_start_IQ;
+ API d_level_off;
+ API d_dco_dbg;
+ API d_tide_resa;
+ API d_asynch_margin; // Perseus Asynch Audio Workaround
+ API hole[4]
+ #else
+ // selection of the melody format
+ API d_melody_selection;
+ API holes[43]; // 43 unused holes.
+ #endif
+ #endif
+ API d_debug3;
+ API d_debug2;
+ API d_debug1; // bit 0 at 1 enable dsp f_tx delay for Omega
+ API d_afcctladd;
+ API d_vbuctrl;
+ API d_vbdctrl;
+ API d_apcdel1;
+ API d_aec_ctrl;
+ API d_apcoff;
+ API d_bulioff;
+ API d_bulqoff;
+ API d_dai_onoff;
+ API d_auxdac;
+ #if (ANLG_FAM == 1)
+ API d_vbctrl;
+ #elif (ANLG_FAM == 2)
+ API d_vbctrl1;
+ #endif
+ API d_bbctrl;
+
+ #else
+ #error DSPCODE not supported with given ANALOG
+ #endif //(ANALOG)1, 2
+ //...................................(MCU -> DSP).
+ API a_sch26[5]; // Header + SB information, array of 5 words.
+
+ // TONES.............................(MCU -> DSP)
+ API d_toneskb_init;
+ API d_toneskb_status;
+ API d_k_x1_t0;
+ API d_k_x1_t1;
+ API d_k_x1_t2;
+ API d_pe_rep;
+ API d_pe_off;
+ API d_se_off;
+ API d_bu_off;
+ API d_t0_on;
+ API d_t0_off;
+ API d_t1_on;
+ API d_t1_off;
+ API d_t2_on;
+ API d_t2_off;
+ API d_k_x1_kt0;
+ API d_k_x1_kt1;
+ API d_dur_kb;
+
+ // PLL...............................(MCU -> DSP).
+ API d_pll_clkmod1;
+ API d_pll_clkmod2;
+
+ // DSP status returned..........(DSP --> MCU).
+ API d_error_status;
+
+ // RIF control.......................(MCU -> DSP).
+ API d_spcx_rif;
+
+ API d_shiftdl;
+ API d_shiftul;
+
+ #if (AEC == 1)
+ // AEC control.......................(MCU -> DSP).
+ #if (VOC == FR_EFR)
+ API p_aec_init;
+ API p_aec_prog;
+ API p_spenh_init;
+ API p_spenh_prog;
+ #endif
+
+ #if (VOC == FR_HR_EFR)
+ API p_saec_prog;
+ API p_aec_prog;
+ API p_spenh_prog;
+ #endif
+ #endif
+
+ API a_ovly[75];
+ API d_ra_conf;
+ API d_ra_act;
+ API d_ra_test;
+ API d_ra_statu;
+ API d_ra_statd;
+ API d_fax;
+ #if (SPEECH_RECO)
+ API a_data_buf_ul[3];
+ API a_n_best_words[4]; // array of the 4 best words
+ API a_n_best_score[8]; // array of the 4 best scores (each score is 32 bits length)
+ API sr_holes_2[6];
+ API a_data_buf_dl[37];
+
+ API fir_holes1[409];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+ API a_model[1041]; // array of the speech reco model
+ #else
+ API a_data_buf_ul[21];
+ API a_data_buf_dl[37];
+
+ API fir_holes1[409];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+ API d_audio_init;
+ API d_audio_status;
+ #endif
+}
+T_NDB_MCU_DSP;
+#endif
+
+#if (DSP == 34) || (DSP == 35) || (DSP == 36)
+typedef struct
+{
+ API_SIGNED d_transfer_rate;
+
+ // Common GSM/GPRS
+ // These words specified the latencies to applies on some peripherics
+ API_SIGNED d_lat_mcu_bridge;
+ API_SIGNED d_lat_mcu_hom2sam;
+ API_SIGNED d_lat_mcu_bef_fast_access;
+ API_SIGNED d_lat_dsp_after_sam;
+
+ // DSP Start address
+ API_SIGNED d_gprs_install_address;
+
+ API_SIGNED d_misc_config;
+
+ API_SIGNED d_cn_sw_workaround;
+
+ API_SIGNED d_hole2_param[4];
+
+ //...................................Frequency Burst.
+ API_SIGNED d_fb_margin_beg;
+ API_SIGNED d_fb_margin_end;
+ API_SIGNED d_nsubb_idle;
+ API_SIGNED d_nsubb_dedic;
+ API_SIGNED d_fb_thr_det_iacq;
+ API_SIGNED d_fb_thr_det_track;
+ //...................................Demodulation.
+ API_SIGNED d_dc_off_thres;
+ API_SIGNED d_dummy_thres;
+ API_SIGNED d_dem_pond_gewl;
+ API_SIGNED d_dem_pond_red;
+
+ //...................................TCH Full Speech.
+ API_SIGNED d_maccthresh1;
+ API_SIGNED d_mldt;
+ API_SIGNED d_maccthresh;
+ API_SIGNED d_gu;
+ API_SIGNED d_go;
+ API_SIGNED d_attmax;
+ API_SIGNED d_sm;
+ API_SIGNED d_b;
+
+ // V42Bis module
+ API_SIGNED d_v42b_switch_hyst;
+ API_SIGNED d_v42b_switch_min;
+ API_SIGNED d_v42b_switch_max;
+ API_SIGNED d_v42b_reset_delay;
+
+ //...................................TCH Half Speech.
+ API_SIGNED d_ldT_hr;
+ API_SIGNED d_maccthresh_hr;
+ API_SIGNED d_maccthresh1_hr;
+ API_SIGNED d_gu_hr;
+ API_SIGNED d_go_hr;
+ API_SIGNED d_b_hr;
+ API_SIGNED d_sm_hr;
+ API_SIGNED d_attmax_hr;
+
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED c_mldt_efr;
+ API_SIGNED c_maccthresh_efr;
+ API_SIGNED c_maccthresh1_efr;
+ API_SIGNED c_gu_efr;
+ API_SIGNED c_go_efr;
+ API_SIGNED c_b_efr;
+ API_SIGNED c_sm_efr;
+ API_SIGNED c_attmax_efr;
+
+ //...................................CHED
+ API_SIGNED d_sd_min_thr_tchfs;
+ API_SIGNED d_ma_min_thr_tchfs;
+ API_SIGNED d_md_max_thr_tchfs;
+ API_SIGNED d_md1_max_thr_tchfs;
+
+ API_SIGNED d_sd_min_thr_tchhs;
+ API_SIGNED d_ma_min_thr_tchhs;
+ API_SIGNED d_sd_av_thr_tchhs;
+ API_SIGNED d_md_max_thr_tchhs;
+ API_SIGNED d_md1_max_thr_tchhs;
+
+ API_SIGNED d_sd_min_thr_tchefs;
+ API_SIGNED d_ma_min_thr_tchefs;
+ API_SIGNED d_md_max_thr_tchefs;
+ API_SIGNED d_md1_max_thr_tchefs;
+
+ API_SIGNED d_wed_fil_ini;
+ API_SIGNED d_wed_fil_tc;
+ API_SIGNED d_x_min;
+ API_SIGNED d_x_max;
+ API_SIGNED d_slope;
+ API_SIGNED d_y_min;
+ API_SIGNED d_y_max;
+ API_SIGNED d_wed_diff_threshold;
+ API_SIGNED d_mabfi_min_thr_tchhs;
+
+ // FACCH module
+ API_SIGNED d_facch_thr;
+
+ // IDS module
+ API_SIGNED d_max_ovsp_ul;
+ API_SIGNED d_sync_thres;
+ API_SIGNED d_idle_thres;
+ API_SIGNED d_m1_thres;
+ API_SIGNED d_max_ovsp_dl;
+ API_SIGNED d_gsm_bgd_mgt;
+
+ // FIR coefficients
+ API a_fir_holes[4];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+}
+T_PARAM_MCU_DSP;
+#elif (DSP == 33)
+typedef struct
+{
+ API_SIGNED d_transfer_rate;
+
+ // Common GSM/GPRS
+ // These words specified the latencies to applies on some peripherics
+ API_SIGNED d_lat_mcu_bridge;
+ API_SIGNED d_lat_mcu_hom2sam;
+ API_SIGNED d_lat_mcu_bef_fast_access;
+ API_SIGNED d_lat_dsp_after_sam;
+
+ // DSP Start address
+ API_SIGNED d_gprs_install_address;
+
+ API_SIGNED d_misc_config;
+
+ API_SIGNED d_cn_sw_workaround;
+
+ #if DCO_ALGO
+ API_SIGNED d_cn_dco_param;
+
+ API_SIGNED d_hole2_param[3];
+ #else
+ API_SIGNED d_hole2_param[4];
+ #endif
+
+ //...................................Frequency Burst.
+ API_SIGNED d_fb_margin_beg;
+ API_SIGNED d_fb_margin_end;
+ API_SIGNED d_nsubb_idle;
+ API_SIGNED d_nsubb_dedic;
+ API_SIGNED d_fb_thr_det_iacq;
+ API_SIGNED d_fb_thr_det_track;
+ //...................................Demodulation.
+ API_SIGNED d_dc_off_thres;
+ API_SIGNED d_dummy_thres;
+ API_SIGNED d_dem_pond_gewl;
+ API_SIGNED d_dem_pond_red;
+
+ //...................................TCH Full Speech.
+ API_SIGNED d_maccthresh1;
+ API_SIGNED d_mldt;
+ API_SIGNED d_maccthresh;
+ API_SIGNED d_gu;
+ API_SIGNED d_go;
+ API_SIGNED d_attmax;
+ API_SIGNED d_sm;
+ API_SIGNED d_b;
+
+ // V42Bis module
+ API_SIGNED d_v42b_switch_hyst;
+ API_SIGNED d_v42b_switch_min;
+ API_SIGNED d_v42b_switch_max;
+ API_SIGNED d_v42b_reset_delay;
+
+ //...................................TCH Half Speech.
+ API_SIGNED d_ldT_hr;
+ API_SIGNED d_maccthresh_hr;
+ API_SIGNED d_maccthresh1_hr;
+ API_SIGNED d_gu_hr;
+ API_SIGNED d_go_hr;
+ API_SIGNED d_b_hr;
+ API_SIGNED d_sm_hr;
+ API_SIGNED d_attmax_hr;
+
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED c_mldt_efr;
+ API_SIGNED c_maccthresh_efr;
+ API_SIGNED c_maccthresh1_efr;
+ API_SIGNED c_gu_efr;
+ API_SIGNED c_go_efr;
+ API_SIGNED c_b_efr;
+ API_SIGNED c_sm_efr;
+ API_SIGNED c_attmax_efr;
+
+ //...................................CHED
+ API_SIGNED d_sd_min_thr_tchfs;
+ API_SIGNED d_ma_min_thr_tchfs;
+ API_SIGNED d_md_max_thr_tchfs;
+ API_SIGNED d_md1_max_thr_tchfs;
+
+ API_SIGNED d_sd_min_thr_tchhs;
+ API_SIGNED d_ma_min_thr_tchhs;
+ API_SIGNED d_sd_av_thr_tchhs;
+ API_SIGNED d_md_max_thr_tchhs;
+ API_SIGNED d_md1_max_thr_tchhs;
+
+ API_SIGNED d_sd_min_thr_tchefs;
+ API_SIGNED d_ma_min_thr_tchefs;
+ API_SIGNED d_md_max_thr_tchefs;
+ API_SIGNED d_md1_max_thr_tchefs;
+
+ API_SIGNED d_wed_fil_ini;
+ API_SIGNED d_wed_fil_tc;
+ API_SIGNED d_x_min;
+ API_SIGNED d_x_max;
+ API_SIGNED d_slope;
+ API_SIGNED d_y_min;
+ API_SIGNED d_y_max;
+ API_SIGNED d_wed_diff_threshold;
+ API_SIGNED d_mabfi_min_thr_tchhs;
+
+ // FACCH module
+ API_SIGNED d_facch_thr;
+
+ // IDS module
+ API_SIGNED d_max_ovsp_ul;
+ API_SIGNED d_sync_thres;
+ API_SIGNED d_idle_thres;
+ API_SIGNED d_m1_thres;
+ API_SIGNED d_max_ovsp_dl;
+ API_SIGNED d_gsm_bgd_mgt;
+
+ // FIR coefficients
+ API a_fir_holes[4];
+ API a_fir31_uplink[31];
+ API a_fir31_downlink[31];
+}
+T_PARAM_MCU_DSP;
+
+#else
+
+typedef struct
+{
+ //...................................Frequency Burst.
+ API_SIGNED d_nsubb_idle;
+ API_SIGNED d_nsubb_dedic;
+ API_SIGNED d_fb_thr_det_iacq;
+ API_SIGNED d_fb_thr_det_track;
+ //...................................Demodulation.
+ API_SIGNED d_dc_off_thres;
+ API_SIGNED d_dummy_thres;
+ API_SIGNED d_dem_pond_gewl;
+ API_SIGNED d_dem_pond_red;
+ API_SIGNED hole[1];
+ API_SIGNED d_transfer_rate;
+ //...................................TCH Full Speech.
+ API_SIGNED d_maccthresh1;
+ API_SIGNED d_mldt;
+ API_SIGNED d_maccthresh;
+ API_SIGNED d_gu;
+ API_SIGNED d_go;
+ API_SIGNED d_attmax;
+ API_SIGNED d_sm;
+ API_SIGNED d_b;
+
+ #if (VOC == FR_HR) || (VOC == FR_HR_EFR)
+ //...................................TCH Half Speech.
+ API_SIGNED d_ldT_hr;
+ API_SIGNED d_maccthresh_hr;
+ API_SIGNED d_maccthresh1_hr;
+ API_SIGNED d_gu_hr;
+ API_SIGNED d_go_hr;
+ API_SIGNED d_b_hr;
+ API_SIGNED d_sm_hr;
+ API_SIGNED d_attmax_hr;
+ #endif
+
+ #if (VOC == FR_EFR) || (VOC == FR_HR_EFR)
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED c_mldt_efr;
+ API_SIGNED c_maccthresh_efr;
+ API_SIGNED c_maccthresh1_efr;
+ API_SIGNED c_gu_efr;
+ API_SIGNED c_go_efr;
+ API_SIGNED c_b_efr;
+ API_SIGNED c_sm_efr;
+ API_SIGNED c_attmax_efr;
+ #endif
+
+ //...................................TCH Full Speech.
+ API_SIGNED d_sd_min_thr_tchfs;
+ API_SIGNED d_ma_min_thr_tchfs;
+ API_SIGNED d_md_max_thr_tchfs;
+ API_SIGNED d_md1_max_thr_tchfs;
+
+ #if (VOC == FR) || (VOC == FR_HR) || (VOC == FR_HR_EFR)
+ //...................................TCH Half Speech.
+ API_SIGNED d_sd_min_thr_tchhs;
+ API_SIGNED d_ma_min_thr_tchhs;
+ API_SIGNED d_sd_av_thr_tchhs;
+ API_SIGNED d_md_max_thr_tchhs;
+ API_SIGNED d_md1_max_thr_tchhs;
+ #endif
+
+ #if (VOC == FR_EFR) || (VOC == FR_HR_EFR)
+ //...................................TCH Enhanced FR Speech.
+ API_SIGNED d_sd_min_thr_tchefs; //(24L *C_POND_RED)
+ API_SIGNED d_ma_min_thr_tchefs; //(1200L *C_POND_RED)
+ API_SIGNED d_md_max_thr_tchefs; //(2000L *C_POND_RED)
+ API_SIGNED d_md1_max_thr_tchefs; //(160L *C_POND_RED)
+ API_SIGNED d_hole1;
+ #endif
+
+ API_SIGNED d_wed_fil_ini;
+ API_SIGNED d_wed_fil_tc;
+ API_SIGNED d_x_min;
+ API_SIGNED d_x_max;
+ API_SIGNED d_slope;
+ API_SIGNED d_y_min;
+ API_SIGNED d_y_max;
+ API_SIGNED d_wed_diff_threshold;
+ API_SIGNED d_mabfi_min_thr_tchhs;
+ API_SIGNED d_facch_thr;
+ API_SIGNED d_dsp_test;
+
+
+ #if (DATA14_4 == 0 ) || (VOC == FR_HR_EFR)
+ API_SIGNED d_patch_addr1;
+ API_SIGNED d_patch_data1;
+ API_SIGNED d_patch_addr2;
+ API_SIGNED d_patch_data2;
+ API_SIGNED d_patch_addr3;
+ API_SIGNED d_patch_data3;
+ API_SIGNED d_patch_addr4;
+ API_SIGNED d_patch_data4;
+ #endif
+
+ //...................................
+ API_SIGNED d_version_number; // DSP patch version
+ API_SIGNED d_ti_version; // customer number. No more used since 1.5
+
+ API_SIGNED d_dsp_page;
+
+ #if IDS
+ API_SIGNED d_max_ovsp_ul;
+ API_SIGNED d_sync_thres;
+ API_SIGNED d_idle_thres;
+ API_SIGNED d_m1_thres;
+ API_SIGNED d_max_ovsp_dl;
+ #endif
+
+
+}
+T_PARAM_MCU_DSP;
+#endif
+
+#if (DSP_DEBUG_TRACE_ENABLE == 1)
+typedef struct
+{
+ API d_debug_ptr_begin;
+ API d_debug_ptr_end;
+}
+T_DB2_DSP_TO_MCU;
+#endif
+
+/* DSP error as per ndb->d_error_status */
+enum dsp_error {
+ DSP_ERR_RHEA = 0x0001,
+ DSP_ERR_IQ_SAMPLES = 0x0004,
+ DSP_ERR_DMA_PROG = 0x0008,
+ DSP_ERR_DMA_TASK = 0x0010,
+ DSP_ERR_DMA_PEND = 0x0020,
+ DSP_ERR_VM = 0x0080,
+ DSP_ERR_DMA_UL_TASK = 0x0100,
+ DSP_ERR_DMA_UL_PROG = 0x0200,
+ DSP_ERR_DMA_UL_PEND = 0x0400,
+ DSP_ERR_STACK_OV = 0x0800,
+};
+
+#endif /* _CAL_DSP_API_H */
diff --git a/src/target/firmware/include/calypso/du.h b/src/target/firmware/include/calypso/du.h
new file mode 100644
index 00000000..f2eae091
--- /dev/null
+++ b/src/target/firmware/include/calypso/du.h
@@ -0,0 +1,32 @@
+/* Calypso DU (Debug Unit) Driver */
+
+/* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _CALYPSO_DU_H
+#define _CALYPSO_DU_H
+
+#include <calypso/clock.h>
+
+void calypso_du_init();
+void calypso_du_stop();
+void calypsu_du_dump();
+
+#endif /* _CALYPSO_DU_H */
diff --git a/src/target/firmware/include/calypso/irq.h b/src/target/firmware/include/calypso/irq.h
new file mode 100644
index 00000000..5ea59797
--- /dev/null
+++ b/src/target/firmware/include/calypso/irq.h
@@ -0,0 +1,49 @@
+#ifndef _CALYPSO_IRQ_H
+#define _CALYPSO_IRQ_H
+
+enum irq_nr {
+ IRQ_WATCHDOG = 0,
+ IRQ_TIMER1 = 1,
+ IRQ_TIMER2 = 2,
+ IRQ_TSP_RX = 3,
+ IRQ_TPU_FRAME = 4,
+ IRQ_TPU_PAGE = 5,
+ IRQ_SIMCARD = 6,
+ IRQ_UART_MODEM = 7,
+ IRQ_KEYPAD_GPIO = 8,
+ IRQ_RTC_TIMER = 9,
+ IRQ_RTC_ALARM_I2C = 10,
+ IRQ_ULPD_GAUGING = 11,
+ IRQ_EXTERNAL = 12,
+ IRQ_SPI = 13,
+ IRQ_DMA = 14,
+ IRQ_API = 15,
+ IRQ_SIM_DETECT = 16,
+ IRQ_EXTERNAL_FIQ = 17,
+ IRQ_UART_IRDA = 18,
+ IRQ_ULPD_GSM_TIMER = 19,
+ IRQ_GEA = 20,
+ _NR_IRQ
+};
+
+typedef void irq_handler(enum irq_nr nr);
+
+/* initialize IRQ driver and enable interrupts */
+void irq_init(void);
+
+/* enable a certain interrupt */
+void irq_enable(enum irq_nr nr);
+
+/* disable a certain interrupt */
+void irq_disable(enum irq_nr nr);
+
+/* configure a certain interrupt */
+void irq_config(enum irq_nr nr, int fiq, int edge, int8_t prio);
+
+/* register an interrupt handler */
+void irq_register_handler(enum irq_nr nr, irq_handler *handler);
+
+/* Install the exception handlers to where the ROM loader jumps */
+void calypso_exceptions_install(void);
+
+#endif /* _CALYPSO_IRQ_H */
diff --git a/src/target/firmware/include/calypso/l1_environment.h b/src/target/firmware/include/calypso/l1_environment.h
new file mode 100644
index 00000000..2d1f8d97
--- /dev/null
+++ b/src/target/firmware/include/calypso/l1_environment.h
@@ -0,0 +1,365 @@
+#include <stdint.h>
+
+typedef unsigned short API;
+typedef signed short API_SIGNED;
+
+#define FAR
+
+#define CHIPSET 12
+#define DSP 36
+#define ANLG_FAM 2 /* Iota */
+
+/* MFTAB */
+#define L1_MAX_FCT 5 /* Max number of fctions in a frame */
+#define MFTAB_SIZE 20
+
+#define NBMAX_CARRIER 174+374 /* Number of carriers (GSM-Ext + DCS */
+
+#define DPAGC_FIFO_LEN 4
+
+#define SIZE_HIST 10
+
+#if !L1_GPRS
+# define NBR_DL_L1S_TASKS 32
+#else
+# define NBR_DL_L1S_TASKS 45
+#endif
+
+#define NBR_L1A_PROCESSES 46
+
+#define W_A_DSP_IDLE3 1
+
+
+
+// Identifier for all DSP tasks.
+// ...RX & TX tasks identifiers.
+#define NO_DSP_TASK 0 // No task.
+#define NP_DSP_TASK 21 // Normal Paging reading task.
+#define EP_DSP_TASK 22 // Extended Paging reading task.
+#define NBS_DSP_TASK 19 // Normal BCCH serving reading task.
+#define EBS_DSP_TASK 20 // Extended BCCH serving reading task.
+#define NBN_DSP_TASK 17 // Normal BCCH neighbour reading task.
+#define EBN_DSP_TASK 18 // Extended BCCH neighbour reading task.
+#define ALLC_DSP_TASK 24 // CCCH reading task while performing FULL BCCH/CCCH reading task.
+#define CB_DSP_TASK 25 // CBCH reading task.
+#define DDL_DSP_TASK 26 // SDCCH/D (data) reading task.
+#define ADL_DSP_TASK 27 // SDCCH/A (SACCH) reading task.
+#define DUL_DSP_TASK 12 // SDCCH/D (data) transmit task.
+#define AUL_DSP_TASK 11 // SDCCH/A (SACCH) transmit task.
+#define RACH_DSP_TASK 10 // RACH transmit task.
+#define TCHT_DSP_TASK 13 // TCH Traffic data DSP task id (RX or TX)
+#define TCHA_DSP_TASK 14 // TCH SACCH data DSP task id (RX or TX)
+#define TCHD_DSP_TASK 28 // TCH Traffic data DSP task id (RX or TX)
+
+#define TCH_DTX_UL 15 // Replace UL task in DSP->MCU com. to say "burst not transmitted".
+
+#if (L1_GPRS)
+ // Identifier for DSP tasks Packet dedicated.
+ // ...RX & TX tasks identifiers.
+ //------------------------------------------------------------------------
+ // WARNING ... Need to aligned following macro with MCU/DSP GPRS Interface
+ //------------------------------------------------------------------------
+ #define PNP_DSP_TASK 30
+ #define PEP_DSP_TASK 31
+ #define PALLC_DSP_TASK 32
+ #define PBS_DSP_TASK 33
+
+ #define PTCCH_DSP_TASK 33
+
+#endif
+
+// Identifier for measurement, FB / SB search tasks.
+// Values 1,2,3 reserved for "number of measurements".
+#define FB_DSP_TASK 5 // Freq. Burst reading task in Idle mode.
+#define SB_DSP_TASK 6 // Sync. Burst reading task in Idle mode.
+#define TCH_FB_DSP_TASK 8 // Freq. Burst reading task in Dedicated mode.
+#define TCH_SB_DSP_TASK 9 // Sync. Burst reading task in Dedicated mode.
+#define IDLE1 1
+
+// Debug tasks
+#define CHECKSUM_DSP_TASK 33
+#define TST_NDB 35 // Checksum DSP->MCU
+#define TST_DB 36 // DB communication check
+#define INIT_VEGA 37
+#define DSP_LOOP_C 38
+
+// Identifier for measurement, FB / SB search tasks.
+// Values 1,2,3 reserved for "number of measurements".
+#define TCH_LOOP_A 31
+#define TCH_LOOP_B 32
+
+// bits in d_gsm_bgd_mgt - background task management
+#define B_DSPBGD_RECO 1 // start of reco in dsp background
+#define B_DSPBGD_UPD 2 // start of alignement update in dsp background
+#define B_DSPBGD_STOP_RECO 256 // stop of reco in dsp background
+#define B_DSPBGD_STOP_UPD 512 // stop of alignement update in dsp background
+
+// bit in d_pll_config
+#define B_32KHZ_CALIB (1 << 14) // force DSP in Idle1 during 32 khz calibration
+// ****************************************************************
+// NDB AREA (PARAM) MCU<->DSP COMMUNICATION DEFINITIONS
+// ****************************************************************
+// bits in d_tch_mode
+#define B_EOTD (1 << 0) // EOTD mode
+#define B_PLAY_UL (1 << 3) // Play UL
+#define B_DCO_ON (1 << 4) // DCO ON/OFF
+#define B_AUDIO_ASYNC (1 << 1) // WCP reserved
+
+// ****************************************************************
+// PARAMETER AREA (PARAM) MCU<->DSP COMMUNICATION DEFINITIONS
+// ****************************************************************
+#define C_POND_RED 1L
+// below values are defined in the file l1_time.h
+//#define D_NSUBB_IDLE 296L
+//#define D_NSUBB_DEDIC 30L
+#define D_FB_THR_DET_IACQ 0x3333L
+#define D_FB_THR_DET_TRACK 0x28f6L
+#define D_DC_OFF_THRES 0x7fffL
+#define D_DUMMY_THRES 17408L
+#define D_DEM_POND_GEWL 26624L
+#define D_DEM_POND_RED 20152L
+#define D_HOLE 0L
+#define D_TRANSFER_RATE 0x6666L
+
+// Full Rate vocoder definitions.
+#define D_MACCTHRESH1 7872L
+#define D_MLDT -4L
+#define D_MACCTHRESH 7872L
+#define D_GU 5772L
+#define D_GO 7872L
+#define D_ATTMAX 53L
+#define D_SM -892L
+#define D_B 208L
+#define D_SD_MIN_THR_TCHFS 15L //(24L *C_POND_RED)
+#define D_MA_MIN_THR_TCHFS 738L //(1200L *C_POND_RED)
+#define D_MD_MAX_THR_TCHFS 1700L //(2000L *C_POND_RED)
+#define D_MD1_MAX_THR_TCHFS 99L //(160L *C_POND_RED)
+
+#if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ // Frequency burst definitions
+ #define D_FB_MARGIN_BEG 24
+ #define D_FB_MARGIN_END 22
+
+ // V42bis definitions
+ #define D_V42B_SWITCH_HYST 16L
+ #define D_V42B_SWITCH_MIN 64L
+ #define D_V42B_SWITCH_MAX 250L
+ #define D_V42B_RESET_DELAY 10L
+
+ // Latencies definitions
+ #if (DSP == 33) || (DSP == 34) || (DSP == 35) || (DSP == 36)
+ // C.f. BUG1404
+ #define D_LAT_MCU_BRIDGE 0x000FL
+ #else
+ #define D_LAT_MCU_BRIDGE 0x0009L
+ #endif
+
+ #define D_LAT_MCU_HOM2SAM 0x000CL
+
+ #define D_LAT_MCU_BEF_FAST_ACCESS 0x0005L
+ #define D_LAT_DSP_AFTER_SAM 0x0004L
+
+ // Background Task in GSM mode: Initialization.
+ #define D_GSM_BGD_MGT 0L
+
+#if (CHIPSET == 4)
+ #define D_MISC_CONFIG 0L
+#elif (CHIPSET == 7) || (CHIPSET == 8) || (CHIPSET == 10) || (CHIPSET == 11) || (CHIPSET == 12)
+ #define D_MISC_CONFIG 1L
+#else
+ #define D_MISC_CONFIG 0L
+#endif
+
+#endif
+
+// Hall Rate vocoder and ched definitions.
+
+#define D_SD_MIN_THR_TCHHS 37L
+#define D_MA_MIN_THR_TCHHS 344L
+#define D_MD_MAX_THR_TCHHS 2175L
+#define D_MD1_MAX_THR_TCHHS 138L
+#define D_SD_AV_THR_TCHHS 1845L
+#define D_WED_FIL_TC 0x7c00L
+#define D_WED_FIL_INI 4650L
+#define D_X_MIN 15L
+#define D_X_MAX 23L
+#define D_Y_MIN 703L
+#define D_Y_MAX 2460L
+#define D_SLOPE 135L
+#define D_WED_DIFF_THRESHOLD 406L
+#define D_MABFI_MIN_THR_TCHHS 5320L
+#define D_LDT_HR -5
+#define D_MACCTRESH_HR 6500
+#define D_MACCTRESH1_HR 6500
+#define D_GU_HR 2620
+#define D_GO_HR 3700
+#define D_B_HR 182
+#define D_SM_HR -1608
+#define D_ATTMAX_HR 53
+
+// Enhanced Full Rate vocoder and ched definitions.
+
+#define C_MLDT_EFR -4
+#define C_MACCTHRESH_EFR 8000
+#define C_MACCTHRESH1_EFR 8000
+#define C_GU_EFR 4522
+#define C_GO_EFR 6500
+#define C_B_EFR 174
+#define C_SM_EFR -878
+#define C_ATTMAX_EFR 53
+#define D_SD_MIN_THR_TCHEFS 15L //(24L *C_POND_RED)
+#define D_MA_MIN_THR_TCHEFS 738L //(1200L *C_POND_RED)
+#define D_MD_MAX_THR_TCHEFS 1230L //(2000L *C_POND_RED)
+#define D_MD1_MAX_THR_TCHEFS 99L //(160L *C_POND_RED)
+
+
+// Integrated Data Services definitions.
+#define D_MAX_OVSPD_UL 8
+// Detect frames containing 90% of 1s as synchro frames
+#define D_SYNC_THRES 0x3f50
+// IDLE frames are only frames with 100 % of 1s
+#define D_IDLE_THRES 0x4000
+#define D_M1_THRES 5
+#define D_MAX_OVSP_DL 8
+
+// d_ra_act: bit field definition
+#define B_F48BLK 5
+
+// Mask for b_itc information (d_ra_conf)
+#define CE_MASK 0x04
+
+#define D_FACCH_THR 0
+#define D_DSP_TEST 0
+#define D_VERSION_NUMBER 0
+#define D_TI_VERSION 0
+
+
+/*------------------------------------------------------------------------------*/
+/* */
+/* DEFINITIONS FOR DSP <-> MCU COMMUNICATION. */
+/* ++++++++++++++++++++++++++++++++++++++++++ */
+/* */
+/*------------------------------------------------------------------------------*/
+// COMMUNICATION Interrupt definition
+//------------------------------------
+#define ALL_16BIT 0xffffL
+#define B_GSM_PAGE (1 << 0)
+#define B_GSM_TASK (1 << 1)
+#define B_MISC_PAGE (1 << 2)
+#define B_MISC_TASK (1 << 3)
+
+#define B_GSM_PAGE_MASK (ALL_16BIT ^ B_GSM_PAGE)
+#define B_GSM_TASK_MASK (ALL_16BIT ^ B_GSM_TASK)
+#define B_MISC_PAGE_MASK (ALL_16BIT ^ B_MISC_PAGE)
+#define B_MISC_TASK_MASK (ALL_16BIT ^ B_MISC_TASK)
+
+// Common definition
+//----------------------------------
+// Index to *_DEMOD* arrays.
+#define D_TOA 0 // Time Of Arrival.
+#define D_PM 1 // Power Measurement.
+#define D_ANGLE 2 // Angle (AFC correction)
+#define D_SNR 3 // Signal / Noise Ratio.
+
+// Bit name/position definitions.
+#define B_FIRE0 5 // Fire result bit 0. (00 -> NO ERROR) (01 -> ERROR CORRECTED)
+#define B_FIRE1 6 // Fire result bit 1. (10 -> ERROR) (11 -> unused)
+#define B_SCH_CRC 8 // CRC result for SB decoding. (1 for ERROR).
+#define B_BLUD 15 // Uplink,Downlink data block Present. (1 for PRESENT).
+#define B_AF 14 // Activity bit: 1 if data block is valid.
+#define B_BFI 2 // Bad Frame Indicator
+#define B_UFI 0 // UNRELIABLE FRAME Indicator
+#define B_ECRC 9 // Enhanced full rate CRC bit
+#define B_EMPTY_BLOCK 10 // for voice memo purpose, this bit is used to determine
+
+#if (DEBUG_DEDIC_TCH_BLOCK_STAT == 1)
+ #define FACCH_GOOD 10
+ #define FACCH_BAD 11
+#endif
+
+#if (AMR == 1)
+ // Place of the RX type in the AMR block header
+ #define RX_TYPE_SHIFT 3
+ #define RX_TYPE_MASK 0x0038
+
+ // Place of the vocoder type in the AMR block header
+ #define VOCODER_TYPE_SHIFT 0
+ #define VOCODER_TYPE_MASK 0x0007
+
+ // List of the possible RX types in a_dd block
+ #define SPEECH_GOOD 0
+ #define SPEECH_DEGRADED 1
+ #define ONSET 2
+ #define SPEECH_BAD 3
+ #define SID_FIRST 4
+ #define SID_UPDATE 5
+ #define SID_BAD 6
+ #define AMR_NO_DATA 7
+ #define AMR_INHIBIT 8
+
+ // List of possible RX types in RATSCCH block
+ #define C_RATSCCH_GOOD 5
+
+ // List of the possible AMR channel rate
+ #define AMR_CHANNEL_4_75 0
+ #define AMR_CHANNEL_5_15 1
+ #define AMR_CHANNEL_5_9 2
+ #define AMR_CHANNEL_6_7 3
+ #define AMR_CHANNEL_7_4 4
+ #define AMR_CHANNEL_7_95 5
+ #define AMR_CHANNEL_10_2 6
+ #define AMR_CHANNEL_12_2 7
+
+ // Types of RATSCCH blocks
+ #define C_RATSCCH_UNKNOWN 0
+ #define C_RATSCCH_CMI_PHASE_REQ 1
+ #define C_RATSCCH_AMR_CONFIG_REQ_MAIN 2
+ #define C_RATSCCH_AMR_CONFIG_REQ_ALT 3
+ #define C_RATSCCH_AMR_CONFIG_REQ_ALT_IGNORE 4 // Alternative AMR_CONFIG_REQ with updates coming in the next THRES_REQ block
+ #define C_RATSCCH_THRES_REQ 5
+
+ // These flags define a bitmap that indicates which AMR parameters are being modified by a RATSCCH
+ #define C_AMR_CHANGE_CMIP 0
+ #define C_AMR_CHANGE_ACS 1
+ #define C_AMR_CHANGE_ICM 2
+ #define C_AMR_CHANGE_THR1 3
+ #define C_AMR_CHANGE_THR2 4
+ #define C_AMR_CHANGE_THR3 5
+ #define C_AMR_CHANGE_HYST1 6
+ #define C_AMR_CHANGE_HYST2 7
+ #define C_AMR_CHANGE_HYST3 8
+
+ // CMIP default value
+ #define C_AMR_CMIP_DEFAULT 1 // According to ETSI specification 05.09, cmip is always 1 by default (new channel, handover...)
+
+#endif
+// "d_ctrl_tch" bits positions for TCH configuration.
+#define B_CHAN_MODE 0
+#define B_CHAN_TYPE 4
+#define B_RESET_SACCH 6
+#define B_VOCODER_ON 7
+#define B_SYNC_TCH_UL 8
+#if (AMR == 1)
+ #define B_SYNC_AMR 9
+#else
+#define B_SYNC_TCH_DL 9
+#endif
+#define B_STOP_TCH_UL 10
+#define B_STOP_TCH_DL 11
+#define B_TCH_LOOP 12
+#define B_SUBCHANNEL 15
+
+// "d_ctrl_abb" bits positions for conditionnal loading of abb registers.
+#define B_RAMP 0
+#if ((ANLG_FAM == 1) || (ANLG_FAM == 2) || (ANLG_FAM == 3))
+ #define B_BULRAMPDEL 3 // Note: this name is changed
+ #define B_BULRAMPDEL2 2 // Note: this name is changed
+ #define B_BULRAMPDEL_BIS 9
+ #define B_BULRAMPDEL2_BIS 10
+#endif
+#define B_AFC 4
+
+// "d_ctrl_system" bits positions.
+#define B_TSQ 0
+#define B_BCCH_FREQ_IND 3
+#define B_TASK_ABORT 15 // Abort RF tasks for DSP.
diff --git a/src/target/firmware/include/calypso/misc.h b/src/target/firmware/include/calypso/misc.h
new file mode 100644
index 00000000..3bd81d22
--- /dev/null
+++ b/src/target/firmware/include/calypso/misc.h
@@ -0,0 +1,7 @@
+#ifndef _CAL_MISC_H
+
+void memdump_range(unsigned int *ptr, unsigned int len);
+void dump_mem(void);
+void dump_dev_id(void);
+
+#endif /* _CAL_MISC_H */
diff --git a/src/target/firmware/include/calypso/rtc.h b/src/target/firmware/include/calypso/rtc.h
new file mode 100644
index 00000000..17528d00
--- /dev/null
+++ b/src/target/firmware/include/calypso/rtc.h
@@ -0,0 +1,6 @@
+#ifndef _CALYPSO_RTC_H
+#define _CALYPSO_RTC_H
+
+void rtc_init(void);
+
+#endif /* _CALYPSO_RTC_H */
diff --git a/src/target/firmware/include/calypso/timer.h b/src/target/firmware/include/calypso/timer.h
new file mode 100644
index 00000000..96587d5a
--- /dev/null
+++ b/src/target/firmware/include/calypso/timer.h
@@ -0,0 +1,22 @@
+#ifndef _CAL_TIMER_H
+#define _CAL_TIMER_H
+
+/* Enable or Disable a timer */
+void hwtimer_enable(int num, int on);
+
+/* Configure pre-scaler and if timer is auto-reload */
+void hwtimer_config(int num, uint8_t pre_scale, int auto_reload);
+
+/* Load a timer with the given value */
+void hwtimer_load(int num, uint16_t val);
+
+/* Read the current timer value */
+uint16_t hwtimer_read(int num);
+
+/* Enable or disable the watchdog */
+void wdog_enable(int on);
+
+/* power up the timers */
+void hwtimer_init(void);
+
+#endif /* _CAL_TIMER_H */
diff --git a/src/target/firmware/include/calypso/tpu.h b/src/target/firmware/include/calypso/tpu.h
new file mode 100644
index 00000000..f0226e63
--- /dev/null
+++ b/src/target/firmware/include/calypso/tpu.h
@@ -0,0 +1,117 @@
+#ifndef _CALYPSO_TPU_H
+#define _CALYPSO_TPU_H
+
+/* Assert or de-assert TPU reset */
+void tpu_reset(int active);
+/* Enable or Disable a new scenario loaded into the TPU */
+void tpu_enable(int active);
+/* Enable or Disable the clock of teh TPU Module */
+void tpu_clk_enable(int active);
+/* Enable Frame Interrupt generation on next frame. DSP will reset it */
+void tpu_dsp_frameirq_enable(void);
+/* Is a Frame interrupt still pending for the DSP ? */
+int tpu_dsp_fameirq_pending(void);
+/* Rewind the TPU, i.e. restart enqueueing instructions at the base addr */
+void tpu_rewind(void);
+/* Enqueue a raw TPU instruction */
+void tpu_enqueue(uint16_t instr);
+/* Initialize TPU and TPU driver */
+void tpu_init(void);
+/* (Busy)Wait until TPU is idle */
+void tpu_wait_idle(void);
+/* Enable FRAME interrupt generation */
+void tpu_frame_irq_en(int mcu, int dsp);
+/* Force the generation of a DSP interrupt */
+void tpu_force_dsp_frame_irq(void);
+
+/* Get the current TPU SYNCHRO register */
+uint16_t tpu_get_synchro(void);
+/* Get the current TPU OFFSET register */
+uint16_t tpu_get_offset(void);
+
+enum tpu_instr {
+ TPU_INSTR_AT = (1 << 13),
+ TPU_INSTR_OFFSET = (2 << 13),
+ TPU_INSTR_SYNCHRO = (3 << 13), /* Loading delta synchro value in TPU synchro register */
+ TPU_INSTR_WAIT = (5 << 13), /* Wait a certain period (in GSM qbits) */
+ TPU_INSTR_SLEEP = (0 << 13), /* Stop the sequencer by disabling TPU ENABLE bit in ctrl reg */
+ /* data processing */
+ TPU_INSTR_MOVE = (4 << 13),
+};
+
+/* Addresses internal to the TPU, only accessible via MOVE */
+enum tpu_reg_int {
+ TPUI_TSP_CTRL1 = 0x00,
+ TPUI_TSP_CTRL2 = 0x01,
+ TPUI_TX_1 = 0x04,
+ TPUI_TX_2 = 0x03,
+ TPUI_TX_3 = 0x03,
+ TPUI_TX_4 = 0x05,
+ TPUI_TSP_ACT_L = 0x06,
+ TPUI_TSP_ACT_U = 0x07,
+ TPUI_TSP_SET1 = 0x09,
+ TPUI_TSP_SET2 = 0x0a,
+ TPUI_TSP_SET3 = 0x0b,
+ TPUI_DSP_INT_PG = 0x10,
+ TPUI_GAUGING_EN = 0x11,
+};
+
+enum tpui_ctrl2_bits {
+ TPUI_CTRL2_RD = (1 << 0),
+ TPUI_CTRL2_WR = (1 << 1),
+};
+
+static inline uint16_t tpu_mod5000(int16_t time)
+{
+ if (time < 0)
+ return time + 5000;
+ if (time >= 5000)
+ return time - 5000;
+ return time;
+}
+
+/* Enqueue a SLEEP operation (stop sequencer by disabling TPU ENABLE bit) */
+static inline void tpu_enq_sleep(void)
+{
+ tpu_enqueue(TPU_INSTR_SLEEP);
+}
+
+/* Enqueue a MOVE operation */
+static inline void tpu_enq_move(uint8_t addr, uint8_t data)
+{
+ tpu_enqueue(TPU_INSTR_MOVE | (data << 5) | (addr & 0x1f));
+}
+
+/* Enqueue an AT operation */
+static inline void tpu_enq_at(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_AT | tpu_mod5000(time));
+}
+
+/* Enqueue a SYNC operation */
+static inline void tpu_enq_sync(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_SYNCHRO | time);
+}
+
+/* Enqueue a WAIT operation */
+static inline void tpu_enq_wait(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_WAIT | time);
+}
+
+/* Enqueue an OFFSET operation */
+static inline void tpu_enq_offset(int16_t time)
+{
+ tpu_enqueue(TPU_INSTR_OFFSET | time);
+}
+
+static inline void tpu_enq_dsp_irq(void)
+{
+ tpu_enq_move(TPUI_DSP_INT_PG, 0x0001);
+}
+
+/* add two numbers, modulo 5000, and ensure the result is positive */
+uint16_t add_mod5000(uint16_t a, uint16_t b);
+
+#endif /* _CALYPSO_TPU_H */
diff --git a/src/target/firmware/include/calypso/tsp.h b/src/target/firmware/include/calypso/tsp.h
new file mode 100644
index 00000000..0252f36e
--- /dev/null
+++ b/src/target/firmware/include/calypso/tsp.h
@@ -0,0 +1,30 @@
+#ifndef _CALYPSO_TSP_H
+#define _CALYPSO_TSP_H
+
+#define TSPACT(x) (1 << x)
+
+/* initiate a TSP write through the TPU */
+void tsp_write(uint8_t dev_idx, uint8_t bitlen, uint32_t dout);
+
+/* Configure clock edge and chip enable polarity for a device */
+void tsp_setup(uint8_t dev_idx, int clk_rising, int en_positive, int en_edge);
+
+/* Obtain the current tspact state */
+uint16_t tsp_act_state(void);
+
+/* Update the TSPACT state, including enable and disable */
+void tsp_act_update(uint16_t new_act);
+
+/* Enable one or multiple TSPACT signals */
+void tsp_act_enable(uint16_t bitmask);
+
+/* Disable one or multiple TSPACT signals */
+void tsp_act_disable(uint16_t bitmask);
+
+/* Toggle one or multiple TSPACT signals */
+void tsp_act_toggle(uint16_t bitmask);
+
+/* Initialize TSP driver */
+void tsp_init(void);
+
+#endif /* _CALYPSO_TSP_H */
diff --git a/src/target/firmware/include/calypso/uart.h b/src/target/firmware/include/calypso/uart.h
new file mode 100644
index 00000000..845612f0
--- /dev/null
+++ b/src/target/firmware/include/calypso/uart.h
@@ -0,0 +1,30 @@
+#ifndef _CAL_UART_H
+#define _CAL_UART_H
+
+#include <stdint.h>
+
+enum uart_baudrate {
+ UART_38400,
+ UART_57600,
+ UART_115200,
+ UART_230400,
+ UART_460800,
+ UART_614400,
+ UART_921600,
+};
+
+void uart_init(uint8_t uart);
+void uart_putchar_wait(uint8_t uart, int c);
+int uart_putchar_nb(uint8_t uart, int c);
+int uart_getchar_nb(uint8_t uart, uint8_t *ch);
+int uart_tx_busy(uint8_t uart);
+int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt);
+
+enum uart_irq {
+ UART_IRQ_TX_EMPTY,
+ UART_IRQ_RX_CHAR,
+};
+
+void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on);
+
+#endif /* _CAL_UART_H */
diff --git a/src/target/firmware/include/cfi_flash.h b/src/target/firmware/include/cfi_flash.h
new file mode 100644
index 00000000..2ab8842a
--- /dev/null
+++ b/src/target/firmware/include/cfi_flash.h
@@ -0,0 +1,68 @@
+
+#ifndef _CFI_FLASH_H
+#define _CFI_FLASH_H
+
+#include <stdint.h>
+
+
+#define CFI_FLASH_MAX_ERASE_REGIONS 4
+
+/* structure of erase region descriptor */
+struct cfi_region {
+ uint16_t b_count;
+ uint16_t b_size;
+} __attribute__((packed));
+
+
+/* structure of cfi query response */
+struct cfi_query {
+ uint8_t qry[3];
+ uint16_t p_id;
+ uint16_t p_adr;
+ uint16_t a_id;
+ uint16_t a_adr;
+ uint8_t vcc_min;
+ uint8_t vcc_max;
+ uint8_t vpp_min;
+ uint8_t vpp_max;
+ uint8_t word_write_timeout_typ;
+ uint8_t buf_write_timeout_typ;
+ uint8_t block_erase_timeout_typ;
+ uint8_t chip_erase_timeout_typ;
+ uint8_t word_write_timeout_max;
+ uint8_t buf_write_timeout_max;
+ uint8_t block_erase_timeout_max;
+ uint8_t chip_erase_timeout_max;
+ uint8_t dev_size;
+ uint16_t interface_desc;
+ uint16_t max_buf_write_size;
+ uint8_t num_erase_regions;
+ struct cfi_region erase_regions[CFI_FLASH_MAX_ERASE_REGIONS];
+} __attribute__((packed));
+
+typedef struct {
+ void *f_base;
+
+ uint32_t f_size;
+
+ uint16_t f_manuf_id;
+ uint16_t f_dev_id;
+
+ struct cfi_query f_query;
+} cfi_flash_t;
+
+typedef uint8_t flash_lock;
+
+void flash_init(cfi_flash_t *flash, void *base_addr);
+
+void flash_dump_info(cfi_flash_t *flash);
+
+flash_lock flash_block_getlock(cfi_flash_t *base_addr, uint32_t block_offset);
+
+void flash_block_unlock(cfi_flash_t *base_addr, uint32_t block_offset);
+void flash_block_lock(cfi_flash_t *base_addr, uint32_t block_offset);
+void flash_block_lockdown(cfi_flash_t *base_addr, uint32_t block_offset);
+
+void flash_block_erase(cfi_flash_t *base_addr, uint32_t block_addr);
+
+#endif
diff --git a/src/target/firmware/include/comm/msgb.h b/src/target/firmware/include/comm/msgb.h
new file mode 100644
index 00000000..f7c9d147
--- /dev/null
+++ b/src/target/firmware/include/comm/msgb.h
@@ -0,0 +1,104 @@
+#ifndef _MSGB_H
+#define _MSGB_H
+
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linuxlist.h>
+
+struct msgb {
+ struct llist_head list;
+
+ /* the A-bis layer 2 header: OML, RSL(RLL), NS */
+ unsigned char *l2h;
+ /* the layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */
+ unsigned char *l3h;
+
+ uint16_t data_len;
+ uint16_t len;
+
+ unsigned char *head; /* start of buffer */
+ unsigned char *tail; /* end of message */
+ unsigned char *data; /* start of message */
+ unsigned char _data[0];
+};
+
+extern struct msgb *msgb_alloc(uint16_t size, const char *name);
+extern void msgb_free(struct msgb *m);
+extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
+extern struct msgb *msgb_dequeue(struct llist_head *queue);
+extern void msgb_reset(struct msgb *m);
+
+#define msgb_l2(m) ((void *)(m->l2h))
+#define msgb_l3(m) ((void *)(m->l3h))
+
+static inline unsigned int msgb_l2len(const struct msgb *msgb)
+{
+ return msgb->tail - (uint8_t *)msgb_l2(msgb);
+}
+
+static inline unsigned int msgb_l3len(const struct msgb *msgb)
+{
+ return msgb->tail - (uint8_t *)msgb_l3(msgb);
+}
+
+static inline unsigned int msgb_headlen(const struct msgb *msgb)
+{
+ return msgb->len - msgb->data_len;
+}
+static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
+{
+ unsigned char *tmp = msgb->tail;
+ msgb->tail += len;
+ msgb->len += len;
+ return tmp;
+}
+static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
+{
+ msgb->data -= len;
+ msgb->len += len;
+ return msgb->data;
+}
+static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
+{
+ msgb->len -= len;
+ return msgb->data += len;
+}
+static inline int msgb_tailroom(const struct msgb *msgb)
+{
+ return (msgb->data + msgb->data_len) - msgb->tail;
+}
+
+/* increase the headroom of an empty msgb, reducing the tailroom */
+static inline void msgb_reserve(struct msgb *msg, int len)
+{
+ msg->data += len;
+ msg->tail += len;
+}
+
+static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
+ const char *name)
+{
+ struct msgb *msg = msgb_alloc(size, name);
+ if (msg)
+ msgb_reserve(msg, headroom);
+ return msg;
+}
+
+#endif /* _MSGB_H */
diff --git a/src/target/firmware/include/comm/sercomm.h b/src/target/firmware/include/comm/sercomm.h
new file mode 100644
index 00000000..24ad865c
--- /dev/null
+++ b/src/target/firmware/include/comm/sercomm.h
@@ -0,0 +1,57 @@
+#ifndef _SERCOMM_H
+#define _SERCOMM_H
+
+/* SERCOMM layer on UART1 (modem UART) */
+
+#ifdef HOST_BUILD
+#include <osmocom/msgb.h>
+#else
+#include <comm/msgb.h>
+#define SERCOMM_UART_NR 1
+#endif
+
+#define HDLC_FLAG 0x7E
+#define HDLC_ESCAPE 0x7D
+
+#define HDLC_C_UI 0x03
+#define HDLC_C_P_BIT (1 << 4)
+#define HDLC_C_F_BIT (1 << 4)
+
+/* a low sercomm_dlci means high priority. A high DLCI means low priority */
+enum sercomm_dlci {
+ SC_DLCI_HIGHEST = 0,
+ SC_DLCI_L1A_L23 = 5,
+ SC_DLCI_CONSOLE = 10,
+ _SC_DLCI_MAX
+};
+
+void sercomm_init(void);
+int sercomm_initialized(void);
+
+/* User Interface: Tx */
+
+/* user interface for transmitting messages for a given DLCI */
+void sercomm_sendmsg(uint8_t dlci, struct msgb *msg);
+/* how deep is the Tx queue for a given DLCI */
+unsigned int sercomm_tx_queue_depth(uint8_t dlci);
+
+/* User Interface: Rx */
+
+/* receiving messages for a given DLCI */
+typedef void (*dlci_cb_t)(uint8_t dlci, struct msgb *msg);
+int sercomm_register_rx_cb(uint8_t dlci, dlci_cb_t cb);
+
+/* Driver Interface */
+
+/* fetch one octet of to-be-transmitted serial data. returns 0 if no more data */
+int sercomm_drv_pull(uint8_t *ch);
+/* the driver has received one byte, pass it into sercomm layer.
+ returns 1 in case of success, 0 in case of unrecognized char */
+int sercomm_drv_rx_char(uint8_t ch);
+
+static inline struct msgb *sercomm_alloc_msgb(unsigned int len)
+{
+ return msgb_alloc_headroom(len, 4, "sercomm_tx");
+}
+
+#endif /* _SERCOMM_H */
diff --git a/src/target/firmware/include/comm/sercomm_cons.h b/src/target/firmware/include/comm/sercomm_cons.h
new file mode 100644
index 00000000..11f66545
--- /dev/null
+++ b/src/target/firmware/include/comm/sercomm_cons.h
@@ -0,0 +1,10 @@
+#ifndef _SERCOMM_CONS_H
+#define _SERCOMM_CONS_H
+
+/* how large buffers do we allocate? */
+#define SERCOMM_CONS_ALLOC 256
+
+int sercomm_puts(const char *s);
+int sercomm_putchar(int c);
+
+#endif /* _SERCOMM_CONS_H */
diff --git a/src/target/firmware/include/console.h b/src/target/firmware/include/console.h
new file mode 100644
index 00000000..7146e990
--- /dev/null
+++ b/src/target/firmware/include/console.h
@@ -0,0 +1,20 @@
+#ifndef _CONSOLE_H
+#define _CONSOLE_H
+
+/* This is the direct (IRQ driven) UART console, bypassing the HDLC layer.
+ * You should not need to call those functions unless you've decided to
+ * not use the HLDC layer or have a device with two UARTs */
+
+int cons_rb_append(const char *data, int len);
+int cons_puts(const char *s);
+int cons_putchar(char c);
+int cons_rb_flush(void);
+void cons_init(void);
+
+/* We want the console on UART 0 (IRDA UART) */
+#define CONS_UART_NR 0
+
+/* Size of the static ring-buffer that we keep for console print messages */
+#define CONS_RB_SIZE 4096
+
+#endif /* _CONSOLE_H */
diff --git a/src/target/firmware/include/debug.h b/src/target/firmware/include/debug.h
new file mode 100644
index 00000000..27c4185d
--- /dev/null
+++ b/src/target/firmware/include/debug.h
@@ -0,0 +1,31 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/*
+ * Check at compile time that something is of a particular type.
+ * Always evaluates to 1 so you may use it easily in comparisons.
+ */
+#define typecheck(type,x) \
+({ type __dummy; \
+ typeof(x) __dummy2; \
+ (void)(&__dummy == &__dummy2); \
+ 1; \
+})
+
+#ifdef DEBUG
+#define dputchar(x) putchar(x)
+#define dputs(x) puts(x)
+#define dphex(x,y) phex(x,y)
+#define printd(x, args ...) printf(x, ## args)
+#else
+#define dputchar(x)
+#define dputs(x)
+#define dphex(x,y)
+#define printd(x, args ...)
+#endif
+
+#endif /* _DEBUG_H */
diff --git a/src/target/firmware/include/delay.h b/src/target/firmware/include/delay.h
new file mode 100644
index 00000000..0d6f3efd
--- /dev/null
+++ b/src/target/firmware/include/delay.h
@@ -0,0 +1,7 @@
+#ifndef delay_h
+#define delay_h
+
+void delay_ms(unsigned int ms);
+void delay_us(unsigned int us);
+
+#endif
diff --git a/src/target/firmware/include/display/st7558.h b/src/target/firmware/include/display/st7558.h
new file mode 100644
index 00000000..efed064c
--- /dev/null
+++ b/src/target/firmware/include/display/st7558.h
@@ -0,0 +1,15 @@
+#ifndef _ST7558_H
+#define _ST7558_H
+
+enum display_attr {
+ DISP_ATTR_INVERT = 0x0001,
+};
+
+void st7558_init(void);
+void st7558_set_attr(unsigned long attr);
+void st7558_unset_attr(unsigned long attr);
+void st7558_clrscr(void);
+void st7558_putchar(unsigned char c);
+void st7558_puts(const char *str);
+
+#endif
diff --git a/src/target/firmware/include/gsm.h b/src/target/firmware/include/gsm.h
new file mode 100644
index 00000000..f3250128
--- /dev/null
+++ b/src/target/firmware/include/gsm.h
@@ -0,0 +1,29 @@
+#ifndef _GSM_H
+#define _GSM_H
+
+#include <l1a_l23_interface.h>
+
+enum gsm_band {
+ GSM_850 = 1,
+ GSM_900 = 2,
+ GSM_1800 = 4,
+ GSM_1900 = 8,
+ GSM_450 = 0x10,
+ GSM_480 = 0x20,
+ GSM_750 = 0x40,
+ GSM_810 = 0x80,
+};
+
+#define ARFCN_PCS 0x8000
+
+enum gsm_band gsm_arfcn2band(uint16_t arfcn);
+
+/* Convert an ARFCN to the frequency in MHz * 10 */
+uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink);
+
+/* Convert from frame number to GSM time */
+void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn);
+
+/* Convert from GSM time to frame number */
+uint32_t gsm_gsmtime2fn(struct gsm_time *time);
+#endif
diff --git a/src/target/firmware/include/i2c.h b/src/target/firmware/include/i2c.h
new file mode 100644
index 00000000..37097a85
--- /dev/null
+++ b/src/target/firmware/include/i2c.h
@@ -0,0 +1,7 @@
+#ifndef _I2C_H
+#define _I2C_H
+
+int i2c_write(uint8_t chip, uint32_t addr, int alen, const uint8_t *buffer, int len);
+void i2c_init(int speed, int slaveadd);
+
+#endif /* I2C_H */
diff --git a/src/target/firmware/include/keypad.h b/src/target/firmware/include/keypad.h
new file mode 100644
index 00000000..dd89734c
--- /dev/null
+++ b/src/target/firmware/include/keypad.h
@@ -0,0 +1,66 @@
+#ifndef _KEYPAD_H
+#define _KEYPAD_H
+
+enum buttons {
+ BTN_0 = 0x00002000,
+ BTN_1 = 0x00008000,
+ BTN_2 = 0x00000400,
+ BTN_3 = 0x00000020,
+ BTN_4 = 0x00010000,
+ BTN_5 = 0x00000800,
+ BTN_6 = 0x00000040,
+ BTN_7 = 0x00020000,
+ BTN_8 = 0x00001000,
+ BTN_9 = 0x00000080,
+ BTN_STAR = 0x00040000,
+ BTN_HASH = 0x00000100,
+ BTN_MENU = 0x00004000,
+ BTN_LEFT_SB = 0x00080000,
+ BTN_RIGHT_SB = 0x00000200,
+ BTN_UP = 0x00000002,
+ BTN_DOWN = 0x00000004,
+ BTN_LEFT = 0x00000008,
+ BTN_RIGHT = 0x00000010,
+ BTN_OK = 0x00000001,
+ BTN_POWER = 0x01000000,
+};
+
+enum key_codes {
+ KEY_0 = 0,
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_STAR, //*
+ KEY_HASH, //#
+ KEY_MENU, //center of directional keys
+ KEY_LEFT_SB, //softbutton
+ KEY_RIGHT_SB, //softbutton
+ KEY_UP,
+ KEY_DOWN,
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_OK, //green off-hook
+ KEY_POWER, //red on-hook
+ KEY_INV = 0xFF
+};
+
+enum key_states {
+ PRESSED,
+ RELEASED,
+};
+
+void keypad_init();
+
+void keypad_scan();
+
+typedef void (*key_handler_t)(enum key_codes code, enum key_states state);
+
+void keypad_set_handler(key_handler_t handler);
+
+#endif /* KEYPAD_H */
diff --git a/src/target/firmware/include/layer1/afc.h b/src/target/firmware/include/layer1/afc.h
new file mode 100644
index 00000000..2e927a50
--- /dev/null
+++ b/src/target/firmware/include/layer1/afc.h
@@ -0,0 +1,13 @@
+#ifndef _L1_AFC_H
+#define _L1_AFC_H
+
+/* Input a frequency error sample into the AFC averaging */
+void afc_input(int32_t freq_error, uint16_t arfcn, int valid);
+
+/* Update the AFC with a frequency error, bypassing averaging */
+void afc_correct(int16_t freq_error, uint16_t arfcn);
+
+/* Update DSP with new AFC DAC value to be used for next TDMA frame */
+void afc_load_dsp(void);
+
+#endif
diff --git a/src/target/firmware/include/layer1/agc.h b/src/target/firmware/include/layer1/agc.h
new file mode 100644
index 00000000..e4b13f13
--- /dev/null
+++ b/src/target/firmware/include/layer1/agc.h
@@ -0,0 +1,6 @@
+#ifndef _L1_AGC_H
+#define _L1_AGC_H
+
+int16_t agc_inp_dbm8_by_pm(int16_t pm);
+
+#endif /* _L1_AGC_H */
diff --git a/src/target/firmware/include/layer1/avg.h b/src/target/firmware/include/layer1/avg.h
new file mode 100644
index 00000000..6c5de172
--- /dev/null
+++ b/src/target/firmware/include/layer1/avg.h
@@ -0,0 +1,23 @@
+#ifndef _L1_AVG_H
+#define _L1_AVG_H
+
+struct running_avg {
+ /* configuration */
+ uint16_t period; /* over how many samples to average */
+ uint16_t min_valid;
+
+ int32_t acc_val;
+ uint16_t num_samples; /* how often did we try to sample? */
+ uint16_t num_samples_valid; /* how often did we receive valid samples? */
+
+ void (*outfn)(struct running_avg *, int32_t avg);
+ void *priv;
+};
+
+/* input a new sample into the averaging process */
+void runavg_input(struct running_avg *ravg, int32_t val, int valid);
+
+/* check if sufficient samples have been obtained, and call outfn() */
+int runavg_check_output(struct running_avg *ravg);
+
+#endif /* _AVG_H */
diff --git a/src/target/firmware/include/layer1/l23_api.h b/src/target/firmware/include/layer1/l23_api.h
new file mode 100644
index 00000000..a03c59c8
--- /dev/null
+++ b/src/target/firmware/include/layer1/l23_api.h
@@ -0,0 +1,11 @@
+#ifndef _L1_L23_API_H
+#define _L1_L23_API_H
+
+#include <stdint.h>
+#include <comm/msgb.h>
+#include <l1a_l23_interface.h>
+
+void l1_queue_for_l2(struct msgb *msg);
+struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr);
+
+#endif /* _L1_L23_API_H */
diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h
new file mode 100644
index 00000000..28eda42c
--- /dev/null
+++ b/src/target/firmware/include/layer1/sync.h
@@ -0,0 +1,75 @@
+#ifndef _L1_SYNC_H
+#define _L1_SYNC_H
+
+#include <layer1/tdma_sched.h>
+#include <l1a_l23_interface.h>
+
+struct l1_cell_info {
+ uint16_t arfcn;
+ uint32_t bsic;
+ uint32_t fn_offset;
+ uint32_t time_alignment;
+};
+
+struct l1s_state {
+ struct gsm_time current_time; /* current time */
+ struct gsm_time next_time; /* time at next TMDMA irq */
+
+ struct l1_cell_info serving_cell;
+
+ struct tdma_scheduler tdma_sched;
+
+ uint32_t tpu_offset;
+
+ int task;
+};
+
+extern struct l1s_state l1s;
+
+enum l1_sig_num {
+ L1_SIG_PM, /* Power Measurement */
+ L1_SIG_NB, /* Normal Burst */
+};
+
+struct l1s_meas_hdr {
+ uint16_t snr; /* signal/noise ratio */
+ int16_t toa_qbit; /* time of arrival (qbits) */
+ int16_t pm_dbm8; /* power level in dbm/8 */
+ int16_t freq_err; /* Frequency error in Hz */
+};
+
+struct l1_signal {
+ uint16_t signum;
+ uint16_t arfcn;
+ union {
+ struct {
+ int16_t dbm8[2];
+ } pm;
+ struct {
+ struct l1s_meas_hdr meas[4];
+ uint16_t crc;
+ uint16_t fire;
+ uint16_t num_biterr;
+ uint8_t frame[24];
+ } nb;
+ };
+};
+
+typedef void (*l1s_cb_t)(struct l1_signal *sig);
+
+void l1s_set_handler(l1s_cb_t handler);
+
+int16_t l1s_snr_int(uint16_t snr);
+uint16_t l1s_snr_fract(uint16_t snr);
+
+void l1s_fb_test(uint8_t base_fn, uint8_t fb_mode);
+void l1s_sb_test(uint8_t base_fn);
+void l1s_pm_test(uint8_t base_fn, uint16_t arfcn);
+void l1s_nb_test(uint8_t base_fn);
+
+void l1s_init(void);
+
+/* init.c */
+void layer1_init(void);
+
+#endif /* _L1_SYNC_H */
diff --git a/src/target/firmware/include/layer1/tdma_sched.h b/src/target/firmware/include/layer1/tdma_sched.h
new file mode 100644
index 00000000..65c59b83
--- /dev/null
+++ b/src/target/firmware/include/layer1/tdma_sched.h
@@ -0,0 +1,52 @@
+#ifndef _L1_TDMA_SCHED_H
+#define _L1_TDMA_SCHED_H
+
+#include <stdint.h>
+
+/* TDMA scheduler */
+
+/* The idea of this scheduler is that we have a circular buffer of buckets,
+ * where each bucket corresponds to one future TDMA frame [interrupt]. Each
+ * bucket contains of a list of callbacks which are executed when the bucket
+ * index reaches that particular bucket. */
+
+#define TDMASCHED_NUM_FRAMES 25
+#define TDMASCHED_NUM_CB 5
+
+typedef int tdma_sched_cb(uint16_t p1, uint16_t p2);
+
+/* A single item in a TDMA scheduler bucket */
+struct tdma_sched_item {
+ tdma_sched_cb *cb;
+ uint16_t p1;
+ uint16_t p2;
+};
+
+/* A bucket inside the TDMA scheduler */
+struct tdma_sched_bucket {
+ struct tdma_sched_item item[TDMASCHED_NUM_CB];
+ uint8_t num_items;
+};
+
+/* The scheduler itself, consisting of buckets and a current index */
+struct tdma_scheduler {
+ struct tdma_sched_bucket bucket[TDMASCHED_NUM_FRAMES];
+ uint8_t cur_bucket;
+};
+
+/* Schedule an item at 'frame_offset' TDMA frames in the future */
+int tdma_schedule(uint8_t frame_offset, tdma_sched_cb *cb, uint16_t p1, uint16_t p2);
+
+/* Schedule a set of items starting from 'frame_offset' TDMA frames in the future */
+int tdma_schedule_set(uint8_t frame_offset, const struct tdma_sched_item *item_set, uint8_t num_items);
+
+/* Execute pre-scheduled events for current frame */
+int tdma_sched_execute(void);
+
+/* reset the scheduler; erase all scheduled items */
+void tdma_sched_reset(void);
+
+/* debug function: print number of entries of all TDMA buckets */
+void tdma_sched_dump(void);
+
+#endif /* _L1_TDMA_SCHED_H */
diff --git a/src/target/firmware/include/layer1/tpu_window.h b/src/target/firmware/include/layer1/tpu_window.h
new file mode 100644
index 00000000..01fab910
--- /dev/null
+++ b/src/target/firmware/include/layer1/tpu_window.h
@@ -0,0 +1,17 @@
+#ifndef _L1_TPU_CTRL_H
+#define _L1_TPU_CTRL_H
+
+enum l1_rxwin_type {
+ L1_RXWIN_PW, /* power measurement */
+ L1_RXWIN_FB, /* FCCH burst detection */
+ L1_RXWIN_SB, /* SCH burst detection */
+ L1_RXWIN_NB, /* Normal burst decoding */
+ _NUM_L1_RXWIN
+};
+
+
+void l1s_rx_win_ctrl(uint16_t arfcn, enum l1_rxwin_type wtype);
+
+void tpu_end_scenario(void);
+
+#endif /* _L1_TPU_CTRL_H */
diff --git a/src/target/firmware/include/linuxlist.h b/src/target/firmware/include/linuxlist.h
new file mode 100644
index 00000000..fb99c5ec
--- /dev/null
+++ b/src/target/firmware/include/linuxlist.h
@@ -0,0 +1,360 @@
+#ifndef _LINUX_LLIST_H
+#define _LINUX_LLIST_H
+
+#include <stddef.h>
+
+#ifndef inline
+#define inline __inline__
+#endif
+
+static inline void prefetch(const void *x) {;}
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (typeof( ((type *)0)->member ) *)(ptr); \
+ (type *)( (char *)__mptr - offsetof(type, member) );})
+
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized llist entries.
+ */
+#define LLIST_POISON1 ((void *) 0x00100100)
+#define LLIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked llist implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole llists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct llist_head {
+ struct llist_head *next, *prev;
+};
+
+#define LLIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LLIST_HEAD(name) \
+ struct llist_head name = LLIST_HEAD_INIT(name)
+
+#define INIT_LLIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_add(struct llist_head *_new,
+ struct llist_head *prev,
+ struct llist_head *next)
+{
+ next->prev = _new;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+}
+
+/**
+ * llist_add - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void llist_add(struct llist_head *_new, struct llist_head *head)
+{
+ __llist_add(_new, head, head->next);
+}
+
+/**
+ * llist_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
+{
+ __llist_add(_new, head->prev, head);
+}
+
+/*
+ * Delete a llist entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * llist_del - deletes entry from llist.
+ * @entry: the element to delete from the llist.
+ * Note: llist_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void llist_del(struct llist_head *entry)
+{
+ __llist_del(entry->prev, entry->next);
+ entry->next = (struct llist_head *)LLIST_POISON1;
+ entry->prev = (struct llist_head *)LLIST_POISON2;
+}
+
+/**
+ * llist_del_init - deletes entry from llist and reinitialize it.
+ * @entry: the element to delete from the llist.
+ */
+static inline void llist_del_init(struct llist_head *entry)
+{
+ __llist_del(entry->prev, entry->next);
+ INIT_LLIST_HEAD(entry);
+}
+
+/**
+ * llist_move - delete from one llist and add as another's head
+ * @llist: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void llist_move(struct llist_head *llist, struct llist_head *head)
+{
+ __llist_del(llist->prev, llist->next);
+ llist_add(llist, head);
+}
+
+/**
+ * llist_move_tail - delete from one llist and add as another's tail
+ * @llist: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void llist_move_tail(struct llist_head *llist,
+ struct llist_head *head)
+{
+ __llist_del(llist->prev, llist->next);
+ llist_add_tail(llist, head);
+}
+
+/**
+ * llist_empty - tests whether a llist is empty
+ * @head: the llist to test.
+ */
+static inline int llist_empty(const struct llist_head *head)
+{
+ return head->next == head;
+}
+
+static inline void __llist_splice(struct llist_head *llist,
+ struct llist_head *head)
+{
+ struct llist_head *first = llist->next;
+ struct llist_head *last = llist->prev;
+ struct llist_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * llist_splice - join two llists
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ */
+static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
+{
+ if (!llist_empty(llist))
+ __llist_splice(llist, head);
+}
+
+/**
+ * llist_splice_init - join two llists and reinitialise the emptied llist.
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ *
+ * The llist at @llist is reinitialised
+ */
+static inline void llist_splice_init(struct llist_head *llist,
+ struct llist_head *head)
+{
+ if (!llist_empty(llist)) {
+ __llist_splice(llist, head);
+ INIT_LLIST_HEAD(llist);
+ }
+}
+
+/**
+ * llist_entry - get the struct for this entry
+ * @ptr: the &struct llist_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * llist_for_each - iterate over a llist
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __llist_for_each - iterate over a llist
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ *
+ * This variant differs from llist_for_each() in that it's the
+ * simplest possible llist iteration code, no prefetching is done.
+ * Use this for code that knows the llist to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __llist_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * llist_for_each_prev - iterate over a llist backwards
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * llist_for_each_safe - iterate over a llist safe against removal of llist entry
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @n: another &struct llist_head to use as temporary storage
+ * @head: the head for your llist.
+ */
+#define llist_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * llist_for_each_entry - iterate over llist of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry(pos, head, member) \
+ for (pos = llist_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_reverse - iterate backwards over llist of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_reverse(pos, head, member) \
+ for (pos = llist_entry((head)->prev, typeof(*pos), member), \
+ prefetch(pos->member.prev); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.prev, typeof(*pos), member), \
+ prefetch(pos->member.prev))
+
+/**
+ * llist_for_each_entry_continue - iterate over llist of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_continue(pos, head, member) \
+ for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = llist_entry((head)->next, typeof(*pos), member), \
+ n = llist_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = llist_entry(n->member.next, typeof(*n), member))
+
+/**
+ * llist_for_each_rcu - iterate over an rcu-protected llist
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each_rcu(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
+
+#define __llist_for_each_rcu(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
+
+/**
+ * llist_for_each_safe_rcu - iterate over an rcu-protected llist safe
+ * against removal of llist entry
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @n: another &struct llist_head to use as temporary storage
+ * @head: the head for your llist.
+ */
+#define llist_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
+
+/**
+ * llist_for_each_entry_rcu - iterate over rcu llist of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your llist.
+ * @member: the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_rcu(pos, head, member) \
+ for (pos = llist_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = llist_entry(pos->member.next, typeof(*pos), member), \
+ ({ smp_read_barrier_depends(); 0;}), \
+ prefetch(pos->member.next))
+
+
+/**
+ * llist_for_each_continue_rcu - iterate over an rcu-protected llist
+ * continuing after existing point.
+ * @pos: the &struct llist_head to use as a loop counter.
+ * @head: the head for your llist.
+ */
+#define llist_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
+ (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
+
+
+#endif
diff --git a/src/target/firmware/include/memory.h b/src/target/firmware/include/memory.h
new file mode 100644
index 00000000..b0a0490c
--- /dev/null
+++ b/src/target/firmware/include/memory.h
@@ -0,0 +1,28 @@
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+#define __arch_getb(a) (*(volatile unsigned char *)(a))
+#define __arch_getw(a) (*(volatile unsigned short *)(a))
+#define __arch_getl(a) (*(volatile unsigned int *)(a))
+
+#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
+#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v))
+#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
+
+#define __raw_writeb(v,a) __arch_putb(v,a)
+#define __raw_writew(v,a) __arch_putw(v,a)
+#define __raw_writel(v,a) __arch_putl(v,a)
+
+#define __raw_readb(a) __arch_getb(a)
+#define __raw_readw(a) __arch_getw(a)
+#define __raw_readl(a) __arch_getl(a)
+
+#define writeb(v,a) __arch_putb(v,a)
+#define writew(v,a) __arch_putw(v,a)
+#define writel(v,a) __arch_putl(v,a)
+
+#define readb(a) __arch_getb(a)
+#define readw(a) __arch_getw(a)
+#define readl(a) __arch_getl(a)
+
+#endif /* _MEMORY_H */
diff --git a/src/target/firmware/include/rf/trf6151.h b/src/target/firmware/include/rf/trf6151.h
new file mode 100644
index 00000000..41cbe6c4
--- /dev/null
+++ b/src/target/firmware/include/rf/trf6151.h
@@ -0,0 +1,35 @@
+#ifndef _TRF6151_H
+#define _TRF6151_H
+
+#include <gsm.h>
+
+/* initialize (reset + power up) */
+void trf6151_init(void);
+
+/* switch power off or on */
+void trf6151_power(int on);
+
+/* set the VGA and RF gain */
+int trf6151_set_gain(uint8_t dbm, int high);
+
+/* obtain the current total gain of the TRF6151 */
+uint8_t trf6151_get_gain(void);
+
+/* Request the PLL to be tuned to the given frequency */
+void trf6151_set_arfcn(uint16_t arfcn, int uplink);
+
+enum trf6151_mode {
+ TRF6151_IDLE,
+ TRF6151_RX,
+ TRF6151_TX,
+};
+
+/* Set the operational mode of the TRF6151 chip */
+void trf6151_set_mode(enum trf6151_mode mode);
+
+void trf6151_test(uint16_t arfcn);
+
+/* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
+void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn, uint8_t vga_dbm, int rf_gain_high);
+
+#endif /* TRF6151_H */
diff --git a/src/target/firmware/include/rffe.h b/src/target/firmware/include/rffe.h
new file mode 100644
index 00000000..00a27080
--- /dev/null
+++ b/src/target/firmware/include/rffe.h
@@ -0,0 +1,15 @@
+#ifndef _RFFE_H
+#define _RFFE_H
+
+#include "gsm.h"
+
+/* initialize RF Frontend */
+void rffe_init(void);
+
+/* switch RF Frontend Mode */
+void rffe_mode(enum gsm_band band, int tx);
+
+/* get current gain of RF frontend (anything between antenna and baseband in dBm */
+uint8_t rffe_get_gain(void);
+
+#endif
diff --git a/src/target/firmware/include/spi.h b/src/target/firmware/include/spi.h
new file mode 100644
index 00000000..0925a9a3
--- /dev/null
+++ b/src/target/firmware/include/spi.h
@@ -0,0 +1,7 @@
+#ifndef _SPI_H
+#define _SPI_H
+
+void spi_init(void);
+int spi_xfer(uint8_t dev_idx, uint8_t bitlen, const void *dout, void *din);
+
+#endif /* _SPI_H */
diff --git a/src/target/firmware/include/stdio.h b/src/target/firmware/include/stdio.h
new file mode 100644
index 00000000..c1f86371
--- /dev/null
+++ b/src/target/firmware/include/stdio.h
@@ -0,0 +1,47 @@
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#ifndef NULL
+#define NULL 0
+#endif /* NULL */
+
+#include <sys/types.h>
+
+int printf(const char *format, ...);
+int sprintf(char *str, const char *format, ...);
+int snprintf(char *str, size_t size, const char *format, ...);
+
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap);
+int vsprintf(char *str, const char *format, va_list ap);
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+int puts(const char *s);
+
+#if 0
+/* start.S based uart console */
+#include <calypso/uart.h>
+#define putchar(c) uart_putchar_wait(1, c)
+int puts(const char *s);
+#endif
+
+#if 0
+/* regular UART console */
+#include <console.h>
+#define putchar(c) cons_putchar(c)
+#define _puts(s) cons_puts(s)
+#define ARCH_HAS_CONSOLE
+#endif
+
+#if 1
+/* sercomm based console */
+#include <comm/sercomm_cons.h>
+#define putchar(c) sercomm_putchar(c)
+#define _puts(s) sercomm_puts(s)
+#define ARCH_HAS_CONSOLE
+#endif
+
+/* non-standard */
+extern void phex(unsigned int c, unsigned int len);
+
+#endif /* _STDIO_H */
diff --git a/src/target/firmware/include/string.h b/src/target/firmware/include/string.h
new file mode 100644
index 00000000..f060659a
--- /dev/null
+++ b/src/target/firmware/include/string.h
@@ -0,0 +1,12 @@
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <sys/types.h>
+
+size_t strnlen(const char *s, size_t count);
+size_t strlen(const char *s);
+
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+
+#endif
diff --git a/src/target/firmware/layer1/Makefile b/src/target/firmware/layer1/Makefile
new file mode 100644
index 00000000..113e7e60
--- /dev/null
+++ b/src/target/firmware/layer1/Makefile
@@ -0,0 +1,18 @@
+INCLUDES=-I../include/ -I../../../../include
+-include ../Makefile.inc
+
+LIBNAME=layer1
+OBJS=avg.o agc.o afc.o sync.o gsm.o tdma_sched.o tpu_window.o init.o l23_api.o
+
+LST=$(OBJS:.o=.lst)
+
+all: lib$(LIBNAME).a
+
+%.o: %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
+
+lib$(LIBNAME).a: $(OBJS)
+ $(CROSS_COMPILE)$(AR) cru $@ $^
+
+clean:
+ rm -f *.a $(OBJS) $(LST)
diff --git a/src/target/firmware/layer1/afc.c b/src/target/firmware/layer1/afc.c
new file mode 100644
index 00000000..846d208f
--- /dev/null
+++ b/src/target/firmware/layer1/afc.c
@@ -0,0 +1,122 @@
+/* AFC (Automatic Frequency Correction) Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <gsm.h>
+
+#include <layer1/afc.h>
+#include <layer1/avg.h>
+#include <calypso/dsp.h>
+
+/* Over how many TDMA frames do we want to average? (this may change in dedicated mode) */
+#define AFC_PERIOD 40
+/* How many of our measurements have to be valid? */
+#define AFC_MIN_MUN_VALID 8
+
+/* The actual AFC code */
+
+struct afc_state {
+ struct running_avg ravg; /* running average */
+ int16_t dac_value; /* current DAC output value */
+ uint16_t arfcn;
+};
+
+static void afc_ravg_output(struct running_avg *ravg, int32_t avg);
+
+static struct afc_state afc_state = {
+ .ravg = {
+ .outfn = &afc_ravg_output,
+ .period = AFC_PERIOD,
+ .min_valid = AFC_MIN_MUN_VALID,
+ },
+};
+
+/* The AFC DAC in the ABB has to be configured as follows:
+ * DAC = 1MHz / 947MHz * FreqErr(Hz) / AFCslop(ppm/LSB)
+ * where:
+ * 947 MHz is the center of EGSM
+ * AFCslope is coded F1.15, thus a normalization factor of 2^15 aplpies
+ */
+
+#define AFC_NORM_FACTOR_GSM ((1<<15) / 947)
+#define AFC_NORM_FACTOR_DCS ((1<<15) / 1894)
+
+/* we assume 4.9ppb per LSB, equals 0.0049 * 32768 == 160 */
+#define AFC_SLOPE 160
+//#define AFC_SLOPE 141
+
+/* The DSP can measure the frequency error in the following ranges:
+ * FB_MODE0: +/- 20 kHz
+ * FB_MODE1: +/- 4 kHz
+ * Sync Burst: +/- 1 kHz
+ * Normal Burst: +/- 400 Hz
+ */
+
+/* Update the AFC with a frequency error, bypassing averaging */
+void afc_correct(int16_t freq_error, uint16_t arfcn)
+{
+ int32_t afc_norm_factor;
+ int16_t delta;
+
+ switch (gsm_arfcn2band(arfcn)) {
+ case GSM_900:
+ case GSM_850:
+ afc_norm_factor = AFC_NORM_FACTOR_GSM;
+ break;
+ default:
+ afc_norm_factor = AFC_NORM_FACTOR_DCS;
+ }
+
+ delta = (int16_t) ((afc_norm_factor * (int32_t)freq_error) / AFC_SLOPE);
+ printd("afc_correct(error=%dHz, arfcn=%u): delta=%d, afc_dac(old=%d,new=%d)\n",
+ freq_error, arfcn, delta, afc_state.dac_value, afc_state.dac_value+delta);
+ afc_state.dac_value += delta;
+
+ /* The AFC DAC has only 13 bits */
+ if (afc_state.dac_value > 4095)
+ afc_state.dac_value = 4095;
+ else if (afc_state.dac_value < -4096)
+ afc_state.dac_value = -4096;
+}
+
+void afc_input(int32_t freq_error, uint16_t arfcn, int valid)
+{
+ afc_state.arfcn = arfcn;
+ runavg_input(&afc_state.ravg, freq_error, valid);
+ runavg_check_output(&afc_state.ravg);
+}
+
+/* callback function for runavg */
+static void afc_ravg_output(struct running_avg *ravg, int32_t avg)
+{
+ afc_correct(avg, afc_state.arfcn);
+}
+
+/* Update DSP with new AFC DAC value to be used for next TDMA frame */
+void afc_load_dsp(void)
+{
+ dsp_api.db_w->d_afc = afc_state.dac_value;
+ dsp_api.db_w->d_ctrl_abb |= (1 << B_AFC);
+}
diff --git a/src/target/firmware/layer1/agc.c b/src/target/firmware/layer1/agc.c
new file mode 100644
index 00000000..aa4af5e1
--- /dev/null
+++ b/src/target/firmware/layer1/agc.c
@@ -0,0 +1,67 @@
+/* AFC (Automatic Gain Control) Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <gsm.h>
+#include <rffe.h>
+
+#include <layer1/agc.h>
+#include <calypso/dsp.h>
+
+/* This is a value that has been measured on the C123 by Harald: 71dBm,
+ it is the difference between the input level at the antenna and what
+ the DSP reports, subtracted by the total gain of the TRF6151 */
+#define SYSTEM_INHERENT_GAIN 71
+
+/* compute the input level present at the antenna based on a baseband
+ * power measurement of the DSP at baseband */
+int16_t agc_inp_dbm8_by_pm(int16_t pm)
+{
+ /* pm is in 1/8 dBm at baseband */
+ int16_t total_gain_dbm8;
+
+ /* compute total current gain */
+ total_gain_dbm8 = (SYSTEM_INHERENT_GAIN + rffe_get_gain()) * 8;
+
+ /* subtract gain from power measurement at baseband level */
+ return pm - total_gain_dbm8;
+}
+
+uint8_t agc_il_by_dbm8(int16_t dbm8)
+{
+ uint16_t il;
+
+ /* convert from 1/8 dBm to l1c format: [220..0] in -1/2dBm unit */
+ if (dbm8 >= 0)
+ il = 0;
+ else
+ il = -dbm8;
+
+ /* saturate */
+ if (il > 4 * 255)
+ il = 4 * 255;
+
+ return (uint8_t)(il >> 2);
+}
diff --git a/src/target/firmware/layer1/avg.c b/src/target/firmware/layer1/avg.c
new file mode 100644
index 00000000..a4bf565b
--- /dev/null
+++ b/src/target/firmware/layer1/avg.c
@@ -0,0 +1,57 @@
+/* Averaging Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+
+#include <layer1/avg.h>
+
+/* input a new sample into the averaging process */
+void runavg_input(struct running_avg *ravg, int32_t val, int valid)
+{
+ ravg->num_samples++;
+ if (valid) {
+ ravg->acc_val += val;
+ ravg->num_samples_valid++;
+ }
+}
+
+/* check if sufficient samples have been obtained, and call outfn() */
+int runavg_check_output(struct running_avg *ravg)
+{
+ if (ravg->num_samples < ravg->period)
+ return 0;
+
+ if (ravg->num_samples_valid >= ravg->min_valid) {
+ int32_t avg = ravg->acc_val / ravg->num_samples_valid;
+
+ ravg->outfn(ravg, avg);
+
+ ravg->num_samples = ravg->num_samples_valid = 0;
+ ravg->acc_val = 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
diff --git a/src/target/firmware/layer1/gsm.c b/src/target/firmware/layer1/gsm.c
new file mode 100644
index 00000000..99f67f30
--- /dev/null
+++ b/src/target/firmware/layer1/gsm.c
@@ -0,0 +1,117 @@
+/* Generic GSM utility routines */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <stdint.h>
+
+#include <gsm.h>
+
+enum gsm_band gsm_arfcn2band(uint16_t arfcn)
+{
+ if (arfcn & ARFCN_PCS)
+ return GSM_1900;
+ else if (arfcn <= 124)
+ return GSM_900;
+ else if (arfcn >= 955 && arfcn <= 1023)
+ return GSM_900;
+ else if (arfcn >= 128 && arfcn <= 251)
+ return GSM_850;
+ else if (arfcn >= 512 && arfcn <= 885)
+ return GSM_1800;
+ else if (arfcn >= 259 && arfcn <= 293)
+ return GSM_450;
+ else if (arfcn >= 306 && arfcn <= 340)
+ return GSM_480;
+ else if (arfcn >= 350 && arfcn <= 425)
+ return GSM_810;
+ else if (arfcn >= 438 && arfcn <= 511)
+ return GSM_750;
+ else
+ return GSM_1800;
+}
+
+/* Convert an ARFCN to the frequency in MHz * 10 */
+uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
+{
+ uint16_t freq10_ul;
+ uint16_t freq10_dl;
+
+ if (arfcn & ARFCN_PCS) {
+ /* DCS 1900 */
+ arfcn &= ~ARFCN_PCS;
+ freq10_ul = 18502 + 2 * (arfcn-512);
+ freq10_dl = freq10_ul + 800;
+ } else if (arfcn <= 124) {
+ /* Primary GSM + ARFCN 0 of E-GSM */
+ freq10_ul = 8900 + 2 * arfcn;
+ freq10_dl = freq10_ul + 450;
+ } else if (arfcn >= 955 && arfcn <= 1023) {
+ /* E-GSM and R-GSM */
+ freq10_ul = 8900 + 2 * (arfcn - 1024);
+ freq10_dl = freq10_ul + 450;
+ } else if (arfcn >= 128 && arfcn <= 251) {
+ /* GSM 850 */
+ freq10_ul = 8242 + 2 * (arfcn - 128);
+ freq10_dl = freq10_ul + 450;
+ } else if (arfcn >= 512 && arfcn <= 885) {
+ /* DCS 1800 */
+ freq10_ul = 17102 + 2 * (arfcn - 512);
+ freq10_dl = freq10_ul + 950;
+ } else if (arfcn >= 259 && arfcn <= 293) {
+ /* GSM 450 */
+ freq10_ul = 4506 + 2 * (arfcn - 259);
+ freq10_dl = freq10_ul + 100;
+ } else if (arfcn >= 306 && arfcn <= 340) {
+ /* GSM 480 */
+ freq10_ul = 4790 + 2 * (arfcn - 306);
+ freq10_dl = freq10_ul + 100;
+ } else if (arfcn >= 350 && arfcn <= 425) {
+ /* GSM 810 */
+ freq10_ul = 8060 + 2 * (arfcn - 350);
+ freq10_dl = freq10_ul + 450;
+ } else if (arfcn >= 438 && arfcn <= 511) {
+ /* GSM 750 */
+ freq10_ul = 7472 + 2 * (arfcn - 438);
+ freq10_dl = freq10_ul + 300;
+ } else
+ return 0xffff;
+
+ if (uplink)
+ return freq10_ul;
+ else
+ return freq10_dl;
+}
+
+void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
+{
+ time->fn = fn;
+ time->t1 = time->fn / (26*51);
+ time->t2 = time->fn % 26;
+ time->t3 = time->fn % 51;
+ time->tc = (time->fn / 51) % 8;
+}
+
+uint32_t gsm_gsmtime2fn(struct gsm_time *time)
+{
+ /* TS 05.02 Chapter 4.3.3 TDMA frame number */
+ return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
+}
diff --git a/src/target/firmware/layer1/init.c b/src/target/firmware/layer1/init.c
new file mode 100644
index 00000000..1c387772
--- /dev/null
+++ b/src/target/firmware/layer1/init.c
@@ -0,0 +1,70 @@
+/* OsmocomBB Layer1 initialization */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rffe.h>
+#include <rf/trf6151.h>
+#include <abb/twl3025.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/irq.h>
+
+#include <layer1/sync.h>
+#include <layer1/l23_api.h>
+
+void layer1_init(void)
+{
+ struct msgb *msg;
+
+ /* initialize TDMA Frame IRQ driven synchronous L1 */
+ l1s_init();
+ /* power up the DSP */
+ dsp_power_on();
+
+ /* Initialize TPU, TSP and TRF drivers */
+ tpu_init();
+ tsp_init();
+ trf6151_init();
+
+ rffe_init();
+
+#if 0 /* only if RX TPU window is disabled! */
+ /* Put TWL3025 in downlink mode (includes calibration) */
+ twl3025_downlink(1, 1000);
+#endif
+
+ /* issue the TRF and TWL initialization sequence */
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+
+ /* Disable RTC interrupt as it causes lost TDMA frames */
+ irq_disable(IRQ_RTC_TIMER);
+
+ /* inform l2 and upwards that we are ready for orders */
+ msg = l1_create_l2_msg(LAYER1_RESET, 0, 0);
+ l1_queue_for_l2(msg);
+}
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
new file mode 100644
index 00000000..85f73cde
--- /dev/null
+++ b/src/target/firmware/layer1/l23_api.c
@@ -0,0 +1,63 @@
+/* Synchronous part of GSM Layer 1: API to Layer2+ */
+
+/* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <comm/msgb.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <l1a_l23_interface.h>
+
+/* the size we will allocate struct msgb* for HDLC */
+#define L3_MSG_SIZE (sizeof(struct l1_ccch_info_ind) + 4)
+#define L3_MSG_HEAD 4
+
+void l1_queue_for_l2(struct msgb *msg)
+{
+ /* forward via serial for now */
+ sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
+}
+
+struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr)
+{
+ struct l1_info_dl *dl;
+ struct msgb *msg;
+
+ msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1_burst");
+ if (!msg) {
+ while (1) {
+ puts("OOPS. Out of buffers...\n");
+ }
+
+ return NULL;
+ }
+
+ dl = (struct l1_info_dl *) msgb_put(msg, sizeof(*dl));
+ dl->msg_type = msg_type;
+ /* FIXME: we may want to compute T1/T2/T3 in L23 */
+ gsm_fn2gsmtime(&dl->time, fn);
+ dl->snr[0] = snr;
+
+ return msg;
+}
diff --git a/src/target/firmware/layer1/sync.c b/src/target/firmware/layer1/sync.c
new file mode 100644
index 00000000..088b2ea7
--- /dev/null
+++ b/src/target/firmware/layer1/sync.c
@@ -0,0 +1,911 @@
+/* Synchronous part of GSM Layer 1 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <calypso/dsp_api.h>
+#include <calypso/irq.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <calypso/dsp.h>
+#include <calypso/timer.h>
+#include <comm/sercomm.h>
+
+#include <layer1/sync.h>
+#include <layer1/afc.h>
+#include <layer1/agc.h>
+#include <layer1/tdma_sched.h>
+#include <layer1/tpu_window.h>
+#include <layer1/l23_api.h>
+
+//#define DEBUG_EVERY_TDMA
+
+/* A debug macro to print every TDMA frame */
+#ifdef DEBUG_EVERY_TDMA
+#define putchart(x) putchar(x)
+#else
+#define putchart(x)
+#endif
+
+struct l1s_state l1s;
+
+static l1s_cb_t l1s_cb = NULL;
+
+void l1s_set_handler(l1s_cb_t cb)
+{
+ l1s_cb = cb;
+}
+
+#define ADD_MODULO(sum, delta, modulo) do { \
+ if ((sum += delta) >= modulo) \
+ sum -= modulo; \
+ } while (0)
+
+#define GSM_MAX_FN (26*51*2048)
+
+static void l1s_time_inc(struct gsm_time *time, uint32_t delta_fn)
+{
+ ADD_MODULO(time->fn, delta_fn, GSM_MAX_FN);
+
+ if (delta_fn == 1) {
+ ADD_MODULO(time->t2, 1, 26);
+ ADD_MODULO(time->t3, 1, 51);
+
+ /* if the new frame number is a multiple of 51 */
+ if (time->t3 == 0) {
+ ADD_MODULO(time->tc, 1, 8);
+
+ /* if new FN is multiple of 51 and 26 */
+ if (time->t2 == 0)
+ ADD_MODULO(time->t1, 1, 2048);
+ }
+ } else
+ gsm_fn2gsmtime(time, time->fn);
+}
+
+static void l1s_time_dump(const struct gsm_time *time)
+{
+ printf("fn=%u(%u/%2u/%2u)", time->fn, time->t1, time->t2, time->t3);
+}
+
+/* determine the GSM time and BSIC from a Sync Burst */
+static uint8_t l1s_decode_sb(struct gsm_time *time, uint32_t sb)
+{
+ uint8_t bsic = (sb >> 2) & 0x3f;
+ uint8_t t3p;
+
+ memset(time, 0, sizeof(*time));
+
+ /* TS 05.02 Chapter 3.3.2.2.1 SCH Frame Numbers */
+ time->t1 = ((sb >> 23) & 1) | ((sb >> 7) & 0x1fe) | ((sb << 9) & 0x600);
+ time->t2 = (sb >> 18) & 0x1f;
+ t3p = ((sb >> 24) & 1) | ((sb >> 15) & 6);
+ time->t3 = t3p*10 + 1;
+
+ /* TS 05.02 Chapter 4.3.3 TDMA frame number */
+ time->fn = gsm_gsmtime2fn(time);
+
+ time->tc = (time->fn / 51) % 8;
+
+ return bsic;
+}
+
+static int last_task_fnr;
+
+extern uint16_t rf_arfcn; // TODO
+
+/* clip a signed 16bit value at a certain limit */
+int16_t clip_int16(int16_t angle, int16_t clip_at)
+{
+ if (angle > clip_at)
+ angle = clip_at;
+ else if (angle < -clip_at)
+ angle = -clip_at;
+
+ return angle;
+}
+
+int16_t l1s_snr_int(uint16_t snr)
+{
+ return snr >> 10;
+}
+
+uint16_t l1s_snr_fract(uint16_t snr)
+{
+ uint32_t fract = snr & 0x3ff;
+ fract = fract * 1000 / (2 << 10);
+
+ return fract & 0xffff;
+}
+
+static void l1ddsp_meas_read(uint8_t nbmeas, uint16_t *pm)
+{
+ uint8_t i;
+
+ for (i = 0; i < nbmeas; i++)
+ pm[i] = (uint16_t) ((dsp_api.db_r->a_pm[i] & 0xffff) >> 3);
+ dsp_api.r_page_used = 1;
+}
+
+/* Convert an angle in fx1.15 notatinon into Hz */
+#define BITFREQ_DIV_2PI 43104 /* 270kHz / 2 * pi */
+#define ANG2FREQ_SCALING (2<<15) /* 2^15 scaling factor for fx1.15 */
+#define ANGLE_TO_FREQ(angle) ((int16_t)angle * BITFREQ_DIV_2PI / ANG2FREQ_SCALING)
+
+#define AFC_MAX_ANGLE 328 /* 0.01 radian in fx1.15 */
+#define AFC_SNR_THRESHOLD 2560 /* 2.5 dB in fx6.10 */
+
+#define BITS_PER_TDMA 1250
+#define QBITS_PER_TDMA (BITS_PER_TDMA * 4) /* 5000 */
+#define TPU_RANGE QBITS_PER_TDMA
+#define SWITCH_TIME (TPU_RANGE-10)
+
+
+static int fb_once = 0;
+
+/* synchronize the L1S to a new timebase (typically a new cell */
+static void synchronize_tdma(struct l1_cell_info *cinfo)
+{
+ int32_t fn_offset;
+ uint32_t tpu_shift = cinfo->time_alignment;
+
+ /* NB detection only works if the TOA of the SB
+ * is within 0...8. We have to add 75 to get an SB TOA of 4. */
+ tpu_shift += 75;
+
+ tpu_shift = (l1s.tpu_offset + tpu_shift) % QBITS_PER_TDMA;
+
+ fn_offset = cinfo->fn_offset - 1;
+
+ /* if we're already very close to the end of the TPU frame,
+ * the next interrupt will basically occur now and we need to compensate */
+ if (tpu_shift < SWITCH_TIME)
+ fn_offset++;
+
+#if 0 /* probably wrong as we already added "offset" and "shift" above */
+ /* increment the TPU quarter-bit offset */
+ l1s.tpu_offset = (l1s.tpu_offset + tpu_shift) % TPU_RANGE;
+#else
+ l1s.tpu_offset = tpu_shift;
+#endif
+
+ puts("Synchronize_TDMA\n");
+ /* request the TPU to adjust the SYNCHRO and OFFSET registers */
+ tpu_enq_at(SWITCH_TIME);
+ tpu_enq_sync(l1s.tpu_offset);
+#if 0
+ /* FIXME: properly end the TPU window at the emd of l1_sync() */
+ tpu_end_scenario();
+#endif
+
+ /* Change the current time to reflect the new value */
+ l1s_time_inc(&l1s.current_time, fn_offset);
+ l1s.next_time = l1s.current_time;
+ l1s_time_inc(&l1s.next_time, 1);
+
+ /* The serving cell now no longer has a frame or bit offset */
+ cinfo->fn_offset = 0;
+ cinfo->time_alignment = 0;
+}
+
+static void l1s_reset_hw(void)
+{
+ dsp_api.w_page = 0;
+ dsp_api.r_page = 0;
+ dsp_api.r_page_used = 0;
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
+ dsp_api.ndb->d_dsp_page = 0;
+
+ /* we have to really reset the TPU, otherwise FB detection
+ * somtimes returns wrong TOA values. */
+ tpu_reset(1);
+ tpu_reset(0);
+ tpu_rewind();
+ tpu_enq_wait(5); /* really needed ? */
+ tpu_enq_offset(l1s.tpu_offset);
+ tpu_end_scenario();
+}
+
+struct mon_state {
+ uint32_t fnr_report; /* frame number when DSP reported it */
+ int attempt; /* which attempt was this ? */
+
+ int16_t toa;
+ uint16_t pm;
+ uint16_t angle;
+ uint16_t snr;
+
+ /* computed values */
+ int16_t freq_diff;
+};
+
+static void dump_mon_state(struct mon_state *fb)
+{
+#if 0
+ printf("(%u:%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz, "
+ "SNR=%04x(%d.%u) OFFSET=%u SYNCHRO=%u\n", fb->fnr_report, fb->attempt,
+ fb->toa, agc_inp_dbm8_by_pm(fb->pm)/8,
+ ANGLE_TO_FREQ(fb->angle), fb->snr, l1s_snr_int(fb->snr),
+ l1s_snr_fract(fb->snr), tpu_get_offset(), tpu_get_synchro());
+#else
+ printf("(%u:%u): TOA=%5u, Power=%4ddBm, Angle=%5dHz ", fb->fnr_report, fb->attempt,
+ fb->toa, agc_inp_dbm8_by_pm(fb->pm)/8,
+ ANGLE_TO_FREQ(fb->angle));
+#endif
+}
+
+static struct mon_state _last_fb, *last_fb = &_last_fb;
+
+static int read_fb_result(int attempt)
+{
+ last_fb->toa = dsp_api.ndb->a_sync_demod[D_TOA];
+ last_fb->pm = dsp_api.ndb->a_sync_demod[D_PM]>>3;
+ last_fb->angle = dsp_api.ndb->a_sync_demod[D_ANGLE];
+ last_fb->snr = dsp_api.ndb->a_sync_demod[D_SNR];
+
+ //last_fb->angle = clip_int16(last_fb->angle, AFC_MAX_ANGLE);
+ last_fb->freq_diff = ANGLE_TO_FREQ(last_fb->angle);
+ last_fb->fnr_report = l1s.current_time.fn;
+ last_fb->attempt = attempt;
+
+ dump_mon_state(last_fb);
+
+ dsp_api.ndb->d_fb_det = 0;
+ dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */
+
+ /* Update AFC with current frequency offset */
+ afc_correct(last_fb->freq_diff, rf_arfcn);
+
+ //tpu_dsp_frameirq_enable();
+ return 1;
+}
+
+static void read_sb_result(int attempt)
+{
+ last_fb->toa = dsp_api.db_r->a_serv_demod[D_TOA];
+ last_fb->pm = dsp_api.db_r->a_serv_demod[D_PM]>>3;
+ last_fb->angle = dsp_api.db_r->a_serv_demod[D_ANGLE];
+ last_fb->snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ last_fb->freq_diff = ANGLE_TO_FREQ(last_fb->angle);
+ last_fb->fnr_report = l1s.current_time.fn;
+ last_fb->attempt = attempt;
+
+ dump_mon_state(last_fb);
+
+ if (last_fb->snr > AFC_SNR_THRESHOLD)
+ afc_input(last_fb->freq_diff, rf_arfcn, 1);
+ else
+ afc_input(last_fb->freq_diff, rf_arfcn, 0);
+
+ dsp_api.r_page_used = 1;
+}
+
+#define TIMER_TICKS_PER_TDMA 1875
+
+static int last_timestamp;
+
+static inline void check_lost_frame(void)
+{
+ int diff, timestamp = hwtimer_read(1);
+
+ if (last_timestamp < timestamp)
+ last_timestamp += (4*TIMER_TICKS_PER_TDMA);
+
+ diff = last_timestamp - timestamp;
+ if (diff != 1875)
+ printf("LOST!\n");
+
+ last_timestamp = timestamp;
+}
+
+/* main routine for synchronous part of layer 1, called by frame interrupt
+ * generated by TPU once every TDMA frame */
+static void l1_sync(void)
+{
+ putchart('+');
+
+ check_lost_frame();
+
+ /* Increment Time */
+ l1s.current_time = l1s.next_time;
+ l1s_time_inc(&l1s.next_time, 1);
+ //l1s_time_dump(&l1s.current_time); putchar(' ');
+
+ dsp_api.frame_ctr++;
+ dsp_api.r_page_used = 0;
+
+ /* Update pointers */
+ if (dsp_api.w_page == 0)
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
+ else
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_1;
+
+ if (dsp_api.r_page == 0)
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
+ else
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_1;
+
+ /* Reset MCU->DSP page */
+ dsp_api_memset((uint16_t *) dsp_api.db_w, sizeof(*dsp_api.db_w));
+
+ /* Update AFC */
+ afc_load_dsp();
+
+ if (dsp_api.ndb->d_error_status) {
+ printf("DSP Error Status: %u\n", dsp_api.ndb->d_error_status);
+ dsp_api.ndb->d_error_status = 0;
+ }
+
+#if 0
+ if (l1s.task != dsp_api.db_r->d_task_md)
+ printf("DSP task (%u) and L1S task (%u) disagree\n", dsp_api.db_r->d_task_md, l1s.task);
+#endif
+ /* execute the sched_items that have been scheduled for this TDMA frame */
+ tdma_sched_execute();
+
+ if (dsp_api.r_page_used) {
+ /* clear and switch the read page */
+ dsp_api_memset((uint16_t *) dsp_api.db_r, sizeof(*dsp_api.db_r));
+
+ /* TSM30 does it (really needed ?):
+ * Set crc result as "SB not found". */
+ dsp_api.db_r->a_sch[0] = (1<<B_SCH_CRC); /* B_SCH_CRC =1, BLUD =0 */
+
+ dsp_api.r_page ^= 1;
+ }
+
+ //dsp_end_scenario();
+}
+
+/* ABORT command ********************************************************/
+
+static int l1s_abort_cmd(uint16_t p1, uint16_t p2)
+{
+ putchart('A');
+
+ /* similar to l1s_reset_hw() without touching the TPU */
+
+ dsp_api.w_page = 0;
+ dsp_api.r_page = 0;
+ dsp_api.r_page_used = 0;
+ dsp_api.db_w = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0;
+ dsp_api.db_r = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0;
+
+ /* Reset task commands. */
+ dsp_api.db_w->d_task_d = NO_DSP_TASK; /* Init. RX task to NO TASK */
+ dsp_api.db_w->d_task_u = NO_DSP_TASK; /* Init. TX task to NO TASK */
+ dsp_api.db_w->d_task_ra = NO_DSP_TASK; /* Init. RA task to NO TASK */
+ dsp_api.db_w->d_task_md = NO_DSP_TASK; /* Init. MONITORING task to NO TASK */
+ dsp_api.ndb->d_dsp_page = 0;
+
+ /* Set "b_abort" to TRUE, dsp will reset current and pending tasks */
+ dsp_api.db_w->d_ctrl_system |= (1 << B_TASK_ABORT);
+ return 0;
+}
+
+void l1s_dsp_abort(void)
+{
+ /* abort right now */
+ tdma_schedule(0, &l1s_abort_cmd, 0, 0);
+}
+
+/* FCCH Burst *****************************************************************/
+
+/* scheduler callback to issue a FB detection task to the DSP */
+static int l1s_fbdet_cmd(uint16_t p1, uint16_t fb_mode)
+{
+ if (fb_mode == 0) {
+ putchart('F');
+ } else {
+ putchart('V');
+ }
+
+ /* Program DSP */
+ l1s.task = dsp_api.db_w->d_task_md = FB_DSP_TASK; /* maybe with I/Q swap? */
+ dsp_api.ndb->d_fb_mode = fb_mode;
+ dsp_end_scenario();
+ last_task_fnr = dsp_api.frame_ctr;
+
+ /* Program TPU */
+ l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_FB);
+ tpu_end_scenario();
+
+ return 0;
+}
+
+
+/* scheduler callback to check for a FB detection response */
+static int l1s_fbdet_resp(uint16_t p1, uint16_t attempt)
+{
+ int ntdma, qbits, fn_offset;
+
+ putchart('f');
+
+ if (!dsp_api.ndb->d_fb_det) {
+ /* we did not detect a FB, fall back to mode 0! */
+ if (attempt == 12) {
+ /* If we don't reset here, we get DSP DMA errors */
+ tdma_sched_reset();
+
+ /* if we are already synchronized initially */
+ if (fb_once == 1)
+ l1s_fb_test(1, 1);
+ else
+ l1s_fb_test(1, 0);
+ }
+ return 0;
+ }
+
+ printf("FB%u ", dsp_api.ndb->d_fb_mode);
+ read_fb_result(attempt);
+
+ last_fb->toa -= 23;
+
+ if (last_fb->toa < 0) {
+ qbits = (last_fb->toa + BITS_PER_TDMA) * 4;
+ ntdma = -1;
+ } else {
+ ntdma = (last_fb->toa) / BITS_PER_TDMA;
+ qbits = (last_fb->toa - ntdma * BITS_PER_TDMA) * 4;
+ }
+
+ {
+ fn_offset = l1s.current_time.fn - attempt + ntdma;
+ int fnr_delta = last_fb->fnr_report - attempt;
+ int bits_delta = fnr_delta * BITS_PER_TDMA;
+
+ struct l1_cell_info *cinfo = &l1s.serving_cell;
+
+ cinfo->fn_offset = fnr_delta;
+ cinfo->time_alignment = qbits;
+ cinfo->arfcn = rf_arfcn;
+
+ if (last_fb->toa > bits_delta)
+ printf("=> DSP reports FB in bit that is %d bits in the future?!?\n",
+ last_fb->toa - bits_delta);
+ else {
+ int fb_fnr = last_task_fnr + last_fb->toa/BITS_PER_TDMA;
+ printf("=>FB @ FNR %u fn_offset=%d qbits=%u\n", fb_fnr, fn_offset, qbits);
+ }
+ }
+
+ if (dsp_api.frame_ctr > 500 && fb_once == 0) {
+ /* Don't synchronize_tdma() yet, it does probably not work
+ * reliable due to the TPU reset) */
+ l1s_reset_hw();
+ tdma_sched_reset();
+ fb_once = 1;
+ } else {
+ /* We found a frequency burst, reset everything and start next task */
+ l1s_reset_hw();
+ tdma_sched_reset();
+ }
+
+#if 1
+ /* restart a SB or new FB detection task */
+ if (dsp_api.frame_ctr > 1000 && fb_once == 1 &&
+ abs(last_fb->freq_diff) < 1000) {
+ int delay;
+
+ /* synchronize before reading SB */
+ synchronize_tdma(&l1s.serving_cell);
+
+ delay = fn_offset + 11 - l1s.current_time.fn - 1;
+ dsp_api.ndb->d_fb_det = 0;
+ dsp_api.ndb->a_sync_demod[D_TOA] = 0; /* TSM30 does it (really needed ?) */
+ fb_once = 0;
+ l1s_sb_test(delay);
+ } else
+#endif
+ {
+ /* If we don't reset here, we get DSP DMA errors */
+ tdma_sched_reset();
+ /* use FB_MODE_1 if we are within certain limits */
+ if (abs(last_fb->freq_diff < 2000))
+ l1s_fb_test(fn_offset + 10 - l1s.current_time.fn - 1, 1);
+ else
+ l1s_fb_test(fn_offset + 10 - l1s.current_time.fn - 1, 0);
+ }
+
+ return 0;
+}
+
+#define SCHED_ITEM(x, y, z) { .cb = x, .p1 = y, .p2 = z }
+#define SCHED_END_FRAME() { .cb = NULL, .p1 = 0, .p2 = 0 }
+
+/* we don't really use this because we need to configure the fb_mode! */
+static const struct tdma_sched_item fb_sched_set[] = {
+ SCHED_ITEM(l1s_fbdet_cmd, 0, 0), SCHED_END_FRAME(),
+ SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 4), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 5), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 6), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 7), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 8), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 9), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 10), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 11), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_fbdet_resp, 0, 12), SCHED_END_FRAME(),
+};
+
+void l1s_fb_test(uint8_t base_fn, uint8_t fb_mode)
+{
+#if 1
+ int i;
+ /* schedule the FB detection command */
+ tdma_schedule(base_fn, &l1s_fbdet_cmd, 0, fb_mode);
+
+ /* schedule 12 attempts to read the result */
+ for (i = 1; i <= 12; i++) {
+ uint8_t fn = base_fn + 1 + i;
+ tdma_schedule(fn, &l1s_fbdet_resp, 0, i);
+ }
+#else
+ /* use the new scheduler 'set' and simply schedule the whole set */
+ /* WARNING: we cannot set FB_MODE_1 this way !!! */
+ tdma_schedule_set(base_fn, fb_sched_set, ARRAY_SIZE(fb_sched_set));
+#endif
+}
+
+/* SCH Burst Detection ********************************************************/
+
+static int sb_once = 0;
+
+static uint8_t sb_cnt;
+
+/* Note: When we get the SB response, it is 2 TDMA frames after the SB
+ * actually happened, as it is a "C W W R" task */
+#define SB2_LATENCY 2
+
+static int l1s_sbdet_resp(uint16_t p1, uint16_t attempt)
+{
+ uint32_t sb;
+ uint8_t bsic;
+ static struct gsm_time sb_time;
+ int qbits, fn_offset;
+ struct l1_cell_info *cinfo = &l1s.serving_cell;
+ int fnr_delta, bits_delta;
+ struct l1_sync_new_ccch_resp *l1;
+ struct msgb *msg;
+
+ putchart('s');
+
+ if (dsp_api.db_r->a_sch[0] & (1<<B_SCH_CRC)) {
+ /* after 2nd attempt, restart */
+ if (attempt == 2)
+ l1s_sb_test(2);
+
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+ }
+
+ sb_cnt++;
+
+ printf("SB%d ", attempt);
+ read_sb_result(dsp_api.frame_ctr);
+
+ sb = dsp_api.db_r->a_sch[3] | dsp_api.db_r->a_sch[4] << 16;
+ bsic = l1s_decode_sb(&sb_time, sb);
+ printf("=> SB 0x%08x: BSIC=%u ", sb, bsic);
+ l1s_time_dump(&sb_time);
+
+ l1s.serving_cell.bsic = bsic;
+
+ /* calculate synchronisation value (TODO: only complete for qbits) */
+ last_fb->toa -= 23;
+ qbits = last_fb->toa * 4;
+ fn_offset = l1s.current_time.fn; // TODO
+
+ if (qbits > QBITS_PER_TDMA) {
+ qbits -= QBITS_PER_TDMA;
+ fn_offset -= 1;
+ } else if (qbits < 0) {
+ qbits += QBITS_PER_TDMA;
+ fn_offset += 1;
+ }
+
+ fnr_delta = last_fb->fnr_report - attempt;
+ bits_delta = fnr_delta * BITS_PER_TDMA;
+
+ cinfo->fn_offset = fnr_delta;
+ cinfo->time_alignment = qbits;
+ cinfo->arfcn = rf_arfcn;
+
+ if (last_fb->toa > bits_delta)
+ printf("=> DSP reports SB in bit that is %d bits in the future?!?\n",
+ last_fb->toa - bits_delta);
+ else
+ printf(" qbits=%u\n", qbits);
+
+ if (sb_cnt > 5 && sb_once == 0) {
+ synchronize_tdma(&l1s.serving_cell);
+ sb_once = 1;
+ }
+
+ /* if we have recived a SYNC burst, update our local GSM time */
+ gsm_fn2gsmtime(&l1s.current_time, sb_time.fn + SB2_LATENCY);
+ /* compute next time from new current time */
+ l1s.next_time = l1s.current_time;
+ l1s_time_inc(&l1s.next_time, 1);
+
+ /* place it in the queue for the layer2 */
+ msg = l1_create_l2_msg(SYNC_NEW_CCCH_RESP, sb_time.fn, last_fb->snr);
+ l1 = (struct l1_sync_new_ccch_resp *) msgb_put(msg, sizeof(*l1));
+ l1->bsic = bsic;
+ l1_queue_for_l2(msg);
+
+#if 0
+ tdma_sched_reset();
+#else
+ /*
+ If we call tdma_sched_reset(), which is only needed if there are
+ further l1s_sbdet_resp() scheduled, we will bring dsp_api.db_r and
+ dsp_api.db_w out of sync because we changed dsp_api.db_w for l1s_sbdet_cmd()
+ and canceled l1s_sbdet_resp() which would change dsp_api.db_r. The DSP
+ however expects dsp_api.db_w and dsp_api.db_r to be in sync (either
+ "0 - 0" or "1 - 1"). So we have to bring dsp_api.db_w and dsp_api.db_r
+ into sync again, otherwise NB reading will complain. We probably don't
+ need the Abort command and could just bring dsp_api.db_w and dsp_api.db_r
+ into sync.
+ */
+ if (attempt != 2) {
+ tdma_sched_reset();
+ l1s_dsp_abort();
+ }
+#endif
+ if (sb_cnt > 10 && sb_time.t3 == 41) {
+ l1s_reset_hw();
+ /* current t3 == 43, need to start NB detection in t3 = 1, difference is 9 */
+ l1s_nb_test(9);
+ } else {
+ /* We have just seen a SCH burst, we know the next one is not in
+ * less than 7 TDMA frames from now */
+ l1s_sb_test(7);
+ }
+
+ return 0;
+}
+
+static int l1s_sbdet_cmd(uint16_t p1, uint16_t p2)
+{
+ putchart('S');
+
+ l1s.task = dsp_api.db_w->d_task_md = SB_DSP_TASK;
+ dsp_api.ndb->d_fb_mode = 0; /* wideband search */
+ dsp_end_scenario();
+
+ last_task_fnr = dsp_api.frame_ctr;
+
+ /* Program TPU */
+ l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_SB);
+ tpu_end_scenario();
+
+ return 0;
+}
+
+void l1s_sb_test(uint8_t base_fn)
+{
+#if 1
+ /* This is how it is done by the TSM30 */
+ tdma_schedule(base_fn, &l1s_sbdet_cmd, 0, 1);
+ tdma_schedule(base_fn + 1, &l1s_sbdet_cmd, 0, 2);
+ tdma_schedule(base_fn + 3, &l1s_sbdet_resp, 0, 1);
+ tdma_schedule(base_fn + 4, &l1s_sbdet_resp, 0, 2);
+#else
+ tdma_schedule(base_fn, &l1s_sbdet_cmd, 0, 1);
+ tdma_schedule(base_fn + 1, &l1s_sbdet_resp, 0, 1);
+ tdma_schedule(base_fn + 2, &l1s_sbdet_resp, 0, 2);
+#endif
+}
+
+/* Power Measurement **********************************************************/
+
+/* scheduler callback to issue a power measurement task to the DSP */
+static int l1s_pm_cmd(uint16_t p1, uint16_t arfcn)
+{
+ putchart('P');
+
+ l1s.task = dsp_api.db_w->d_task_md = 2;
+ dsp_api.ndb->d_fb_mode = 0; /* wideband search */
+ dsp_end_scenario();
+ last_task_fnr = dsp_api.frame_ctr;
+
+ /* Program TPU */
+ //l1s_rx_win_ctrl(arfcn, L1_RXWIN_PW);
+ l1s_rx_win_ctrl(arfcn, L1_RXWIN_NB);
+ tpu_end_scenario();
+
+ return 0;
+}
+
+/* scheduler callback to read power measurement resposnse from the DSP */
+static int l1s_pm_resp(uint16_t p1, uint16_t p2)
+{
+ uint16_t pm_level[2];
+ struct l1_signal sig;
+
+ putchart('p');
+
+ l1ddsp_meas_read(2, pm_level);
+
+ printd("PM MEAS: %-4d dBm, %-4d dBm ARFCN=%u\n",
+ agc_inp_dbm8_by_pm(pm_level[0])/8,
+ agc_inp_dbm8_by_pm(pm_level[1])/8, rf_arfcn);
+
+ /* build and deliver signal */
+ sig.signum = L1_SIG_PM;
+ sig.arfcn = rf_arfcn;
+ sig.pm.dbm8[0] = agc_inp_dbm8_by_pm(pm_level[0]);
+ sig.pm.dbm8[1] = agc_inp_dbm8_by_pm(pm_level[1]);
+
+ if (l1s_cb)
+ l1s_cb(&sig);
+
+ return 0;
+}
+
+void l1s_pm_test(uint8_t base_fn, uint16_t arfcn)
+{
+ tdma_schedule(base_fn, &l1s_pm_cmd, 0, arfcn);
+ tdma_schedule(base_fn + 2, &l1s_pm_resp, 0, 0);
+}
+
+/* Normal Burst ***************************************************************/
+
+static int l1s_nb_resp(uint16_t p1, uint16_t burst_id)
+{
+ static struct l1_signal _nb_sig, *sig = &_nb_sig;
+ struct msgb *msg;
+
+ putchart('n');
+
+ /* just for debugging, d_task_d should not be 0 */
+ if (dsp_api.db_r->d_task_d == 0) {
+ puts("EMPTY\n");
+ return 0;
+ }
+
+ /* DSP burst ID needs to corespond with what we expect */
+ if (dsp_api.db_r->d_burst_d != burst_id) {
+ puts("BURST ID\n");
+ return 0;
+ }
+
+ sig->nb.meas[burst_id].toa_qbit = dsp_api.db_r->a_serv_demod[D_TOA];
+ sig->nb.meas[burst_id].pm_dbm8 = dsp_api.db_r->a_serv_demod[D_PM] >> 3;
+ sig->nb.meas[burst_id].freq_err = ANGLE_TO_FREQ(dsp_api.db_r->a_serv_demod[D_ANGLE]);
+ sig->nb.meas[burst_id].snr = dsp_api.db_r->a_serv_demod[D_SNR];
+
+ /* feed computed frequency error into AFC loop */
+ if (sig->nb.meas[burst_id].snr > AFC_SNR_THRESHOLD)
+ afc_input(sig->nb.meas[burst_id].freq_err, rf_arfcn, 1);
+ else
+ afc_input(sig->nb.meas[burst_id].freq_err, rf_arfcn, 0);
+
+ /* 4th burst, get frame data */
+ if (dsp_api.db_r->d_burst_d == 3) {
+ struct l1_info_dl *dl;
+ struct l1_ccch_info_ind *l1;
+ uint8_t i, j;
+
+ sig->signum = L1_SIG_NB;
+ sig->nb.num_biterr = dsp_api.ndb->a_cd[2] & 0xffff;
+ sig->nb.crc = ((dsp_api.ndb->a_cd[0] & 0xffff) & ((1 << B_FIRE1) | (1 << B_FIRE0))) >> B_FIRE0;
+ sig->nb.fire = ((dsp_api.ndb->a_cd[0] & 0xffff) & (1 << B_FIRE1)) >> B_FIRE1;
+
+ /* copy actual data, skipping the information block [0,1,2] */
+ for (j = 0,i = 3; i < 15; i++) {
+ sig->nb.frame[j++] = dsp_api.ndb->a_cd[i] & 0xFF;
+ sig->nb.frame[j++] = (dsp_api.ndb->a_cd[i] >> 8) & 0xFF;
+ }
+
+ /* actually issue the signal */
+ if (l1s_cb)
+ l1s_cb(sig);
+
+ /* place it in the queue for the layer2 */
+ msg = l1_create_l2_msg(CCCH_INFO_IND, l1s.current_time.fn-4, last_fb->snr);
+ dl = (struct l1_info_dl *) msg->data;
+ l1 = (struct l1_ccch_info_ind *) msgb_put(msg, sizeof(*l1));
+
+ /* copy the snr and data */
+ for (i = 0; i < 3; ++i)
+ dl->snr[i] = sig->nb.meas[i].snr;
+ for (i = 0; i < 23; ++i)
+ l1->data[i] = sig->nb.frame[i];
+ l1_queue_for_l2(msg);
+
+ /* clear downlink task */
+ l1s.task = dsp_api.db_w->d_task_d = 0;
+
+ l1s_sb_test(4);
+ }
+
+ /* mark READ page as being used */
+ dsp_api.r_page_used = 1;
+
+ return 0;
+}
+
+static int l1s_nb_cmd(uint16_t p1, uint16_t burst_id)
+{
+ uint8_t tsc = l1s.serving_cell.bsic & 0x7;
+
+ putchart('N');
+ dsp_load_rx_task(ALLC_DSP_TASK, burst_id, tsc);
+ dsp_end_scenario();
+
+ l1s_rx_win_ctrl(rf_arfcn, L1_RXWIN_NB);
+ tpu_end_scenario();
+
+ return 0;
+}
+
+static const struct tdma_sched_item nb_sched_set[] = {
+ SCHED_ITEM(l1s_nb_cmd, 0, 0), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_cmd, 0, 1), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, 0, 0), SCHED_ITEM(l1s_nb_cmd, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, 0, 1), SCHED_ITEM(l1s_nb_cmd, 0, 3), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, 0, 2), SCHED_END_FRAME(),
+ SCHED_ITEM(l1s_nb_resp, 0, 3), SCHED_END_FRAME(),
+};
+
+void l1s_nb_test(uint8_t base_fn)
+{
+ puts("Starting NB\n");
+ tdma_schedule_set(base_fn, nb_sched_set, ARRAY_SIZE(nb_sched_set));
+}
+
+/* Interrupt handler */
+static void frame_irq(enum irq_nr nr)
+{
+ l1_sync();
+}
+
+void l1s_init(void)
+{
+ /* register FRAME interrupt as FIQ so it can interrupt normal IRQs */
+ irq_register_handler(IRQ_TPU_FRAME, &frame_irq);
+ irq_config(IRQ_TPU_FRAME, 1, 1, 0);
+ irq_enable(IRQ_TPU_FRAME);
+
+ /* configure timer 1 to be auto-reload and have a prescale of 12 (13MHz/12 == qbit clock) */
+ hwtimer_enable(1, 1);
+ hwtimer_load(1, (1875*4)-1);
+ hwtimer_config(1, 0, 1);
+ hwtimer_enable(1, 1);
+}
+
diff --git a/src/target/firmware/layer1/tdma_sched.c b/src/target/firmware/layer1/tdma_sched.c
new file mode 100644
index 00000000..097e9a42
--- /dev/null
+++ b/src/target/firmware/layer1/tdma_sched.c
@@ -0,0 +1,163 @@
+/* TDMA Scheduler Implementation */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <debug.h>
+#include <gsm.h>
+
+#include <layer1/tdma_sched.h>
+#include <layer1/sync.h>
+
+#include <calypso/dsp.h>
+
+static uint8_t wrap_bucket(uint8_t offset)
+{
+ uint16_t bucket;
+
+ bucket = (l1s.tdma_sched.cur_bucket + offset)
+ % ARRAY_SIZE(l1s.tdma_sched.bucket);
+
+ return bucket;
+}
+
+/* Schedule an item at 'frame_offset' TDMA frames in the future */
+int tdma_schedule(uint8_t frame_offset, tdma_sched_cb *cb, uint16_t p1, uint16_t p2)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ uint8_t bucket_nr = wrap_bucket(frame_offset);
+ struct tdma_sched_bucket *bucket = &sched->bucket[bucket_nr];
+ struct tdma_sched_item *sched_item;
+
+ if (bucket->num_items >= ARRAY_SIZE(bucket->item)) {
+ puts("tdma_schedule bucket overflow\n");
+ return -1;
+ }
+
+ sched_item = &bucket->item[bucket->num_items++];
+
+ sched_item->cb = cb;
+ sched_item->p1 = p1;
+ sched_item->p2 = p2;
+
+ return 0;
+}
+
+/* Schedule a set of items starting from 'frame_offset' TDMA frames in the future */
+int tdma_schedule_set(uint8_t frame_offset, const struct tdma_sched_item *item_set,
+ uint8_t num_items)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ uint8_t bucket_nr = wrap_bucket(frame_offset);
+ int i;
+
+ for (i = 0; i < num_items; i++) {
+ const struct tdma_sched_item *sched_item = &item_set[i];
+ struct tdma_sched_bucket *bucket = &sched->bucket[bucket_nr];
+
+ if (sched_item->cb == NULL) {
+ /* advance to next bucket (== TDMA frame) */
+ bucket_nr = wrap_bucket(++frame_offset);
+ continue;
+ }
+ /* check for bucket overflow */
+ if (bucket->num_items >= ARRAY_SIZE(bucket->item)) {
+ puts("tdma_schedule bucket overflow\n");
+ return -1;
+ }
+ /* copy the item from the set into the current bucket item position */
+ memcpy(&bucket->item[bucket->num_items++], sched_item, sizeof(*sched_item));
+ }
+
+ return num_items;
+}
+
+/* Execute pre-scheduled events for current frame */
+int tdma_sched_execute(void)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ struct tdma_sched_bucket *bucket;
+ uint8_t next_bucket;
+ int i, num_events = 0;
+
+ /* determine current bucket */
+ bucket = &sched->bucket[sched->cur_bucket];
+
+ /* iterate over items in this bucket and call callback function */
+ for (i = 0; i < bucket->num_items; i++) {
+ struct tdma_sched_item *item = &bucket->item[i];
+ int rc;
+
+ num_events++;
+
+ rc = item->cb(item->p1, item->p2);
+ if (rc < 0) {
+ printf("Error %d during processing of item %u of bucket %u\n",
+ rc, i, sched->cur_bucket);
+ return rc;
+ }
+ /* if the cb() we just called has scheduled more items for the
+ * current TDMA, bucket->num_items will have increased and we
+ * will simply continue to execute them as intended */
+ }
+
+ /* clear/reset the bucket */
+ bucket->num_items = 0;
+
+ /* advance to the next bucket */
+ next_bucket = wrap_bucket(1);
+ sched->cur_bucket = next_bucket;
+
+ /* return number of items that we called */
+ return num_events;
+}
+
+void tdma_sched_reset(void)
+{
+ struct tdma_scheduler *sched = &l1s.tdma_sched;
+ unsigned int bucket_nr;
+
+ for (bucket_nr = 0; bucket_nr < ARRAY_SIZE(sched->bucket); bucket_nr++) {
+ struct tdma_sched_bucket *bucket = &sched->bucket[bucket_nr];
+ /* current bucket will be reset by iteration code above! */
+ if (bucket_nr != sched->cur_bucket)
+ bucket->num_items = 0;
+ }
+
+ /* Don't reset cur_bucket, as it would upset the bucket iteration code
+ * in tdma_sched_execute() */
+}
+
+void tdma_sched_dump(void)
+{
+ unsigned int i;
+
+ printf("\n(%2u)", l1s.tdma_sched.cur_bucket);
+ for (i = 0; i < ARRAY_SIZE(l1s.tdma_sched.bucket); i++) {
+ int bucket_nr = wrap_bucket(i);
+ struct tdma_sched_bucket *bucket = &l1s.tdma_sched.bucket[bucket_nr];
+ printf("%u:", bucket->num_items);
+ }
+ putchar('\n');
+}
diff --git a/src/target/firmware/layer1/tpu_window.c b/src/target/firmware/layer1/tpu_window.c
new file mode 100644
index 00000000..dc9fc34a
--- /dev/null
+++ b/src/target/firmware/layer1/tpu_window.c
@@ -0,0 +1,94 @@
+/* TPU window control routines for Layer 1 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <debug.h>
+#include <stdio.h>
+
+#include <rffe.h>
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+#include <abb/twl3025.h>
+#include <rf/trf6151.h>
+
+#include <layer1/tpu_window.h>
+
+/* all units in GSM quarter-bits (923.1ns) */
+#define L1_TDMA_LENGTH_Q 5000
+#define L1_BURST_LENGTH_Q 625 /* L1_TDMA_LENGTH_Q/8 */
+
+#define L1_NB_MARGIN_Q (3 * 4)
+#define L1_SB_MARGIN_Q (23 * 4)
+#define L1_TAIL_DURATION_Q (3 * 4)
+
+/* Sample length as required by the Calypso DSP */
+#define L1_NB_DURATION_Q (L1_BURST_LENGTH_Q + 2 * L1_NB_MARGIN_Q - L1_TAIL_DURATION_Q)
+#define L1_SB_DURATION_Q (L1_BURST_LENGTH_Q + 2 * L1_SB_MARGIN_Q - L1_TAIL_DURATION_Q)
+#define L1_FB_DURATION_Q (11 * L1_TDMA_LENGTH_Q + 2057) /* more than 11 full slots */
+#define L1_FB26_DURATION_Q (L1_TDMA_LENGTH_Q + 798)
+#define L1_PW_DURATION_Q 289
+
+#define DSP_SETUP_TIME 66
+
+static const uint16_t rx_burst_duration[_NUM_L1_RXWIN] = {
+ [L1_RXWIN_PW] = L1_PW_DURATION_Q,
+ [L1_RXWIN_FB] = L1_FB_DURATION_Q,
+ [L1_RXWIN_SB] = L1_SB_DURATION_Q,
+ [L1_RXWIN_NB] = L1_NB_DURATION_Q,
+};
+
+void l1s_rx_win_ctrl(uint16_t arfcn, enum l1_rxwin_type wtype)
+{
+ int16_t start = DSP_SETUP_TIME;
+ int16_t stop = start + rx_burst_duration[wtype] - 1;
+
+ /* FIXME: AGC */
+ /* FIXME: RF PLL */
+
+ /* window open for TRF6151 */
+ /* FIXME: why do we need the magic value 100 ? */
+ rffe_mode(gsm_arfcn2band(arfcn), 0);
+ trf6151_rx_window(start - 100, arfcn, 40, 0);
+
+ /* Window open for ABB */
+ twl3025_downlink(1, start);
+
+ /* Delay 11 full TDMA frames */
+ if (wtype == L1_RXWIN_FB) {
+ uint8_t i;
+ for (i = 0; i < 11; i++)
+ tpu_enq_at(0);
+
+ stop -= 11 * L1_TDMA_LENGTH_Q;
+ }
+
+ /* Window close for ABB */
+ twl3025_downlink(0, stop);
+
+ /* FIXME: window close for TRF6151 */
+}
+
+void tpu_end_scenario(void)
+{
+ tpu_enq_sleep();
+ tpu_enable(1);
+}
diff --git a/src/target/firmware/lib/Makefile b/src/target/firmware/lib/Makefile
new file mode 100644
index 00000000..4056e91b
--- /dev/null
+++ b/src/target/firmware/lib/Makefile
@@ -0,0 +1,26 @@
+INCLUDES=-I../include/
+-include ../Makefile.inc
+
+LIBNAME=mini
+CSRCS=vsprintf.c string.c ctype.c printf.c console.c
+SSRCS=changebit.S clearbit.S div64.S lib1funcs.S memcpy.S memset.S setbit.S testchangebit.S testclearbit.S testsetbit.S
+
+COBJS=$(CSRCS:.c=.o)
+SOBJS=$(SSRCS:.S=.o)
+OBJS=$(COBJS) $(SOBJS)
+
+LST=$(OBJS:.o=.lst)
+
+all: lib$(LIBNAME).a
+
+$(COBJS): %.o : %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^
+
+$(SOBJS): %.o : %.S
+ $(CROSS_COMPILE)$(CC) $(ASFLAGS) -c -o $@ $^
+
+lib$(LIBNAME).a: $(OBJS)
+ $(CROSS_COMPILE)$(AR) cru $@ $^
+
+clean:
+ rm -f *.a $(OBJS) $(LST)
diff --git a/src/target/firmware/lib/bitops.h b/src/target/firmware/lib/bitops.h
new file mode 100644
index 00000000..428c9a63
--- /dev/null
+++ b/src/target/firmware/lib/bitops.h
@@ -0,0 +1,33 @@
+ .macro bitop, instr
+ and r2, r0, #7
+ mov r3, #1
+ mov r3, r3, lsl r2
+ save_and_disable_irqs ip
+ ldrb r2, [r1, r0, lsr #3]
+ \instr r2, r2, r3
+ strb r2, [r1, r0, lsr #3]
+ restore_irqs ip
+ mov pc, lr
+ .endm
+
+/**
+ * testop - implement a test_and_xxx_bit operation.
+ * @instr: operational instruction
+ * @store: store instruction
+ *
+ * Note: we can trivially conditionalise the store instruction
+ * to avoid dirting the data cache.
+ */
+ .macro testop, instr, store
+ add r1, r1, r0, lsr #3
+ and r3, r0, #7
+ mov r0, #1
+ save_and_disable_irqs ip
+ ldrb r2, [r1]
+ tst r2, r0, lsl r3
+ \instr r2, r2, r0, lsl r3
+ \store r2, [r1]
+ restore_irqs ip
+ moveq r0, #0
+ mov pc, lr
+ .endm
diff --git a/src/target/firmware/lib/changebit.S b/src/target/firmware/lib/changebit.S
new file mode 100644
index 00000000..7c709fb3
--- /dev/null
+++ b/src/target/firmware/lib/changebit.S
@@ -0,0 +1,21 @@
+/*
+ * linux/arch/arm/lib/changebit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+/* Purpose : Function to change a bit
+ * Prototype: int change_bit(int bit, void *addr)
+ */
+ENTRY(_change_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_change_bit_le)
+ bitop eor
diff --git a/src/target/firmware/lib/clearbit.S b/src/target/firmware/lib/clearbit.S
new file mode 100644
index 00000000..cb48f7ac
--- /dev/null
+++ b/src/target/firmware/lib/clearbit.S
@@ -0,0 +1,22 @@
+/*
+ * linux/arch/arm/lib/clearbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+/*
+ * Purpose : Function to clear a bit
+ * Prototype: int clear_bit(int bit, void *addr)
+ */
+ENTRY(_clear_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_clear_bit_le)
+ bitop bic
diff --git a/src/target/firmware/lib/console.c b/src/target/firmware/lib/console.c
new file mode 100644
index 00000000..f7d0226e
--- /dev/null
+++ b/src/target/firmware/lib/console.c
@@ -0,0 +1,202 @@
+/* Ringbuffer based serial console layer, imported from OpenPCD */
+
+/* (C) 2006-2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <console.h>
+#include <calypso/uart.h>
+
+#include <asm/system.h>
+
+struct cons {
+ char buf[CONS_RB_SIZE];
+ char *next_inbyte;
+ char *next_outbyte;
+ int initialized;
+};
+static struct cons cons;
+
+void cons_init(void)
+{
+ memset(cons.buf, 0, sizeof(cons.buf));
+ cons.next_inbyte = &cons.buf[0];
+ cons.next_outbyte = &cons.buf[0];
+ cons.initialized = 1;
+}
+
+/* determine how many bytes are left in the ringbuffer without overwriting
+ bytes that haven't been written to the console yet */
+static int __cons_rb_space(void)
+{
+ if (cons.next_inbyte == cons.next_outbyte)
+ return sizeof(cons.buf)-1;
+ else if (cons.next_outbyte > cons.next_inbyte)
+ return (cons.next_outbyte - cons.next_inbyte) -1;
+ else
+ return sizeof(cons.buf) - 1 - (cons.next_inbyte - cons.next_outbyte);
+}
+
+/* pull one char out of debug ring buffer */
+static int cons_rb_pull(char *ret)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (cons.next_outbyte == cons.next_inbyte) {
+ local_irq_restore(flags);
+ return -1;
+ }
+
+ *ret = *cons.next_outbyte;
+
+ cons.next_outbyte++;
+ if (cons.next_outbyte >= &cons.buf[0]+sizeof(cons.buf)) {
+ cons.next_outbyte = &cons.buf[0];
+ }
+#if 0
+ else if (cons.next_outbyte > &cons.buf[0]+sizeof(cons.buf)) {
+ cons.next_outbyte -= sizeof(cons.buf);
+ }
+#endif
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/* returns if everything was flushed (1) or if there's more to flush (0) */
+static void __rb_flush_wait(void)
+{
+ char ch;
+ while (cons_rb_pull(&ch) >= 0)
+ uart_putchar_wait(CONS_UART_NR, ch);
+}
+
+/* returns if everything was flushed (1) or if there's more to flush (0) */
+static int __rb_flush(void)
+{
+ while (!uart_tx_busy(CONS_UART_NR)) {
+ char ch;
+ if (cons_rb_pull(&ch) < 0) {
+ /* no more data to write, disable interest in Tx FIFO interrupts */
+ return 1;
+ }
+ uart_putchar_nb(CONS_UART_NR, ch);
+ }
+
+ /* if we reach here, UART Tx FIFO is busy again */
+ return 0;
+}
+
+/* flush pending data from debug ring buffer to serial port */
+int cons_rb_flush(void)
+{
+ return __rb_flush();
+}
+
+static void cons_memcpy(char *pos, const char *data, int len)
+{
+#if 0
+ /* Somehow our memcpy is broken !?! */
+ memcpy(pos, data, len);
+#else
+ int i;
+ for (i = 0; i < len; i++)
+ *pos++ = *data++;
+#endif
+}
+
+/* Append bytes to ring buffer, not more than we have left! */
+static void __cons_rb_append(const char *data, int len)
+{
+ if (cons.next_inbyte + len >= &cons.buf[0]+sizeof(cons.buf)) {
+ int before_tail = (&cons.buf[0]+sizeof(cons.buf)) - cons.next_inbyte;
+ /* copy the first part before we wrap */
+ cons_memcpy(cons.next_inbyte, data, before_tail);
+ data += before_tail;
+ len -= before_tail;
+ /* reset the buffer */
+ cons.next_inbyte = &cons.buf[0];
+ }
+ cons_memcpy(cons.next_inbyte, data, len);
+ cons.next_inbyte += len;
+}
+
+/* append bytes to the ringbuffer, do one wrap */
+int cons_rb_append(const char *data, int len)
+{
+ unsigned long flags;
+ int bytes_left;
+ const char *data_cur;
+
+ /* we will never be able to write more than the console buffer */
+ if (len > (int) sizeof(cons.buf))
+ len = sizeof(cons.buf);
+
+ local_irq_save(flags);
+
+ bytes_left = __cons_rb_space();
+ data_cur = data;
+
+ if (len > bytes_left) {
+ /* append what we can */
+ __cons_rb_append(data_cur, bytes_left);
+ /* busy-wait for all characters to be transmitted */
+ __rb_flush_wait();
+ /* fill it with the remaining bytes */
+ len -= bytes_left;
+ data_cur += bytes_left;
+ }
+ __cons_rb_append(data_cur, len);
+
+ /* we want to get Tx FIFO interrupts */
+ uart_irq_enable(CONS_UART_NR, UART_IRQ_TX_EMPTY, 1);
+
+ local_irq_restore(flags);
+
+ return len;
+}
+
+int cons_puts(const char *s)
+{
+ if (cons.initialized) {
+ return cons_rb_append(s, strlen(s));
+ } else {
+ /* if the console is not active yet, we need to fall back */
+ int i = strlen(s);
+ while (i--)
+ uart_putchar_wait(CONS_UART_NR, *s++);
+ return i;
+ }
+}
+
+int cons_putchar(char c)
+{
+ if (cons.initialized)
+ return cons_rb_append(&c, 1);
+ else {
+ /* if the console is not active yet, we need to fall back */
+ uart_putchar_wait(CONS_UART_NR, c);
+ return 0;
+ }
+}
diff --git a/src/target/firmware/lib/copy_template.S b/src/target/firmware/lib/copy_template.S
new file mode 100644
index 00000000..cab355c0
--- /dev/null
+++ b/src/target/firmware/lib/copy_template.S
@@ -0,0 +1,255 @@
+/*
+ * linux/arch/arm/lib/copy_template.s
+ *
+ * Code template for optimized memory copy functions
+ *
+ * Author: Nicolas Pitre
+ * Created: Sep 28, 2005
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This can be used to enable code to cacheline align the source pointer.
+ * Experiments on tested architectures (StrongARM and XScale) didn't show
+ * this a worthwhile thing to do. That might be different in the future.
+ */
+//#define CALGN(code...) code
+#define CALGN(code...)
+
+/*
+ * Theory of operation
+ * -------------------
+ *
+ * This file provides the core code for a forward memory copy used in
+ * the implementation of memcopy(), copy_to_user() and copy_from_user().
+ *
+ * The including file must define the following accessor macros
+ * according to the need of the given function:
+ *
+ * ldr1w ptr reg abort
+ *
+ * This loads one word from 'ptr', stores it in 'reg' and increments
+ * 'ptr' to the next word. The 'abort' argument is used for fixup tables.
+ *
+ * ldr4w ptr reg1 reg2 reg3 reg4 abort
+ * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ *
+ * This loads four or eight words starting from 'ptr', stores them
+ * in provided registers and increments 'ptr' past those words.
+ * The'abort' argument is used for fixup tables.
+ *
+ * ldr1b ptr reg cond abort
+ *
+ * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
+ * It also must apply the condition code if provided, otherwise the
+ * "al" condition is assumed by default.
+ *
+ * str1w ptr reg abort
+ * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ * str1b ptr reg cond abort
+ *
+ * Same as their ldr* counterparts, but data is stored to 'ptr' location
+ * rather than being loaded.
+ *
+ * enter reg1 reg2
+ *
+ * Preserve the provided registers on the stack plus any additional
+ * data as needed by the implementation including this code. Called
+ * upon code entry.
+ *
+ * exit reg1 reg2
+ *
+ * Restore registers with the values previously saved with the
+ * 'preserv' macro. Called upon code termination.
+ */
+
+
+ enter r4, lr
+
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ PLD( pld [r1, #0] )
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+ CALGN( ands ip, r1, #31 )
+ CALGN( rsb r3, ip, #32 )
+ CALGN( sbcnes r4, r3, r2 ) @ C is always set here
+ CALGN( bcs 2f )
+ CALGN( adr r4, 6f )
+ CALGN( subs r2, r2, r3 ) @ C gets set
+ CALGN( add pc, r4, ip )
+
+ PLD( pld [r1, #0] )
+2: PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 4f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+3: PLD( pld [r1, #124] )
+4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+ subs r2, r2, #32
+ str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
+ bge 3b
+ PLD( cmn r2, #96 )
+ PLD( bge 4b )
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6: nop
+ ldr1w r1, r3, abort=20f
+ ldr1w r1, r4, abort=20f
+ ldr1w r1, r5, abort=20f
+ ldr1w r1, r6, abort=20f
+ ldr1w r1, r7, abort=20f
+ ldr1w r1, r8, abort=20f
+ ldr1w r1, lr, abort=20f
+
+ add pc, pc, ip
+ nop
+ nop
+ str1w r0, r3, abort=20f
+ str1w r0, r4, abort=20f
+ str1w r0, r5, abort=20f
+ str1w r0, r6, abort=20f
+ str1w r0, r7, abort=20f
+ str1w r0, r8, abort=20f
+ str1w r0, lr, abort=20f
+
+ CALGN( bcs 2b )
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldr1b r1, r3, ne, abort=21f
+ ldr1b r1, r4, cs, abort=21f
+ ldr1b r1, ip, cs, abort=21f
+ str1b r0, r3, ne, abort=21f
+ str1b r0, r4, cs, abort=21f
+ str1b r0, ip, cs, abort=21f
+
+ exit r4, pc
+
+9: rsb ip, ip, #4
+ cmp ip, #2
+ ldr1b r1, r3, gt, abort=21f
+ ldr1b r1, r4, ge, abort=21f
+ ldr1b r1, lr, abort=21f
+ str1b r0, r3, gt, abort=21f
+ str1b r0, r4, ge, abort=21f
+ subs r2, r2, ip
+ str1b r0, lr, abort=21f
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr1w r1, lr, abort=21f
+ beq 17f
+ bgt 18f
+
+
+ .macro forward_copy_shift pull push
+
+ subs r2, r2, #28
+ blt 14f
+
+ CALGN( ands ip, r1, #31 )
+ CALGN( rsb ip, ip, #32 )
+ CALGN( sbcnes r4, ip, r2 ) @ C is always set here
+ CALGN( subcc r2, r2, ip )
+ CALGN( bcc 15f )
+
+11: stmfd sp!, {r5 - r9}
+
+ PLD( pld [r1, #0] )
+ PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 13f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+12: PLD( pld [r1, #124] )
+13: ldr4w r1, r4, r5, r6, r7, abort=19f
+ mov r3, lr, pull #\pull
+ subs r2, r2, #32
+ ldr4w r1, r8, r9, ip, lr, abort=19f
+ orr r3, r3, r4, push #\push
+ mov r4, r4, pull #\pull
+ orr r4, r4, r5, push #\push
+ mov r5, r5, pull #\pull
+ orr r5, r5, r6, push #\push
+ mov r6, r6, pull #\pull
+ orr r6, r6, r7, push #\push
+ mov r7, r7, pull #\pull
+ orr r7, r7, r8, push #\push
+ mov r8, r8, pull #\pull
+ orr r8, r8, r9, push #\push
+ mov r9, r9, pull #\pull
+ orr r9, r9, ip, push #\push
+ mov ip, ip, pull #\pull
+ orr ip, ip, lr, push #\push
+ str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
+ bge 12b
+ PLD( cmn r2, #96 )
+ PLD( bge 13b )
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov r3, lr, pull #\pull
+ ldr1w r1, lr, abort=21f
+ subs ip, ip, #4
+ orr r3, r3, lr, push #\push
+ str1w r0, r3, abort=21f
+ bgt 15b
+ CALGN( cmp r2, #0 )
+ CALGN( bge 11b )
+
+16: sub r1, r1, #(\push / 8)
+ b 8b
+
+ .endm
+
+
+ forward_copy_shift pull=8 push=24
+
+17: forward_copy_shift pull=16 push=16
+
+18: forward_copy_shift pull=24 push=8
+
+
+/*
+ * Abort preamble and completion macros.
+ * If a fixup handler is required then those macros must surround it.
+ * It is assumed that the fixup code will handle the private part of
+ * the exit macro.
+ */
+
+ .macro copy_abort_preamble
+19: ldmfd sp!, {r5 - r9}
+ b 21f
+20: ldmfd sp!, {r5 - r8}
+21:
+ .endm
+
+ .macro copy_abort_end
+ ldmfd sp!, {r4, pc}
+ .endm
+
diff --git a/src/target/firmware/lib/ctype.c b/src/target/firmware/lib/ctype.c
new file mode 100644
index 00000000..6ec51cc2
--- /dev/null
+++ b/src/target/firmware/lib/ctype.c
@@ -0,0 +1,34 @@
+/*
+ * linux/lib/ctype.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <asm/ctype.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
+
diff --git a/src/target/firmware/lib/div64.S b/src/target/firmware/lib/div64.S
new file mode 100644
index 00000000..7eeef50c
--- /dev/null
+++ b/src/target/firmware/lib/div64.S
@@ -0,0 +1,200 @@
+/*
+ * linux/arch/arm/lib/div64.S
+ *
+ * Optimized computation of 64-bit dividend / 32-bit divisor
+ *
+ * Author: Nicolas Pitre
+ * Created: Oct 5, 2003
+ * Copyright: Monta Vista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/linkage.h>
+
+#ifdef __ARMEB__
+#define xh r0
+#define xl r1
+#define yh r2
+#define yl r3
+#else
+#define xl r0
+#define xh r1
+#define yl r2
+#define yh r3
+#endif
+
+/*
+ * __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
+ *
+ * Note: Calling convention is totally non standard for optimal code.
+ * This is meant to be used by do_div() from include/asm/div64.h only.
+ *
+ * Input parameters:
+ * xh-xl = dividend (clobbered)
+ * r4 = divisor (preserved)
+ *
+ * Output values:
+ * yh-yl = result
+ * xh = remainder
+ *
+ * Clobbered regs: xl, ip
+ */
+
+ENTRY(__do_div64)
+
+ @ Test for easy paths first.
+ subs ip, r4, #1
+ bls 9f @ divisor is 0 or 1
+ tst ip, r4
+ beq 8f @ divisor is power of 2
+
+ @ See if we need to handle upper 32-bit result.
+ cmp xh, r4
+ mov yh, #0
+ blo 3f
+
+ @ Align divisor with upper part of dividend.
+ @ The aligned divisor is stored in yl preserving the original.
+ @ The bit position is stored in ip.
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz yl, r4
+ clz ip, xh
+ sub yl, yl, ip
+ mov ip, #1
+ mov ip, ip, lsl yl
+ mov yl, r4, lsl yl
+
+#else
+
+ mov yl, r4
+ mov ip, #1
+1: cmp yl, #0x80000000
+ cmpcc yl, xh
+ movcc yl, yl, lsl #1
+ movcc ip, ip, lsl #1
+ bcc 1b
+
+#endif
+
+ @ The division loop for needed upper bit positions.
+ @ Break out early if dividend reaches 0.
+2: cmp xh, yl
+ orrcs yh, yh, ip
+ subcss xh, xh, yl
+ movnes ip, ip, lsr #1
+ mov yl, yl, lsr #1
+ bne 2b
+
+ @ See if we need to handle lower 32-bit result.
+3: cmp xh, #0
+ mov yl, #0
+ cmpeq xl, r4
+ movlo xh, xl
+ movlo pc, lr
+
+ @ The division loop for lower bit positions.
+ @ Here we shift remainer bits leftwards rather than moving the
+ @ divisor for comparisons, considering the carry-out bit as well.
+ mov ip, #0x80000000
+4: movs xl, xl, lsl #1
+ adcs xh, xh, xh
+ beq 6f
+ cmpcc xh, r4
+5: orrcs yl, yl, ip
+ subcs xh, xh, r4
+ movs ip, ip, lsr #1
+ bne 4b
+ mov pc, lr
+
+ @ The top part of remainder became zero. If carry is set
+ @ (the 33th bit) this is a false positive so resume the loop.
+ @ Otherwise, if lower part is also null then we are done.
+6: bcs 5b
+ cmp xl, #0
+ moveq pc, lr
+
+ @ We still have remainer bits in the low part. Bring them up.
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz xh, xl @ we know xh is zero here so...
+ add xh, xh, #1
+ mov xl, xl, lsl xh
+ mov ip, ip, lsr xh
+
+#else
+
+7: movs xl, xl, lsl #1
+ mov ip, ip, lsr #1
+ bcc 7b
+
+#endif
+
+ @ Current remainder is now 1. It is worthless to compare with
+ @ divisor at this point since divisor can not be smaller than 3 here.
+ @ If possible, branch for another shift in the division loop.
+ @ If no bit position left then we are done.
+ movs ip, ip, lsr #1
+ mov xh, #1
+ bne 4b
+ mov pc, lr
+
+8: @ Division by a power of 2: determine what that divisor order is
+ @ then simply shift values around
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz ip, r4
+ rsb ip, ip, #31
+
+#else
+
+ mov yl, r4
+ cmp r4, #(1 << 16)
+ mov ip, #0
+ movhs yl, yl, lsr #16
+ movhs ip, #16
+
+ cmp yl, #(1 << 8)
+ movhs yl, yl, lsr #8
+ addhs ip, ip, #8
+
+ cmp yl, #(1 << 4)
+ movhs yl, yl, lsr #4
+ addhs ip, ip, #4
+
+ cmp yl, #(1 << 2)
+ addhi ip, ip, #3
+ addls ip, ip, yl, lsr #1
+
+#endif
+
+ mov yh, xh, lsr ip
+ mov yl, xl, lsr ip
+ rsb ip, ip, #32
+ orr yl, yl, xh, lsl ip
+ mov xh, xl, lsl ip
+ mov xh, xh, lsr ip
+ mov pc, lr
+
+ @ eq -> division by 1: obvious enough...
+9: moveq yl, xl
+ moveq yh, xh
+ moveq xh, #0
+ moveq pc, lr
+
+ @ Division by 0:
+ str lr, [sp, #-8]!
+ bl __div0
+
+ @ as wrong as it could be...
+ mov yl, #0
+ mov yh, #0
+ mov xh, #0
+ ldr pc, [sp], #8
+
diff --git a/src/target/firmware/lib/lib1funcs.S b/src/target/firmware/lib/lib1funcs.S
new file mode 100644
index 00000000..b02a85eb
--- /dev/null
+++ b/src/target/firmware/lib/lib1funcs.S
@@ -0,0 +1,334 @@
+/*
+ * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
+ *
+ * Author: Nicolas Pitre <nico@cam.org>
+ * - contributed to gcc-3.4 on Sep 30, 2003
+ * - adapted for the Linux kernel on Oct 2, 2003
+ */
+
+/* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+
+
+.macro ARM_DIV_BODY dividend, divisor, result, curbit
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz \curbit, \divisor
+ clz \result, \dividend
+ sub \result, \curbit, \result
+ mov \curbit, #1
+ mov \divisor, \divisor, lsl \result
+ mov \curbit, \curbit, lsl \result
+ mov \result, #0
+
+#else
+
+ @ Initially shift the divisor left 3 bits if possible,
+ @ set curbit accordingly. This allows for curbit to be located
+ @ at the left end of each 4 bit nibbles in the division loop
+ @ to save one loop in most cases.
+ tst \divisor, #0xe0000000
+ moveq \divisor, \divisor, lsl #3
+ moveq \curbit, #8
+ movne \curbit, #1
+
+ @ Unless the divisor is very big, shift it up in multiples of
+ @ four bits, since this is the amount of unwinding in the main
+ @ division loop. Continue shifting until the divisor is
+ @ larger than the dividend.
+1: cmp \divisor, #0x10000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #4
+ movlo \curbit, \curbit, lsl #4
+ blo 1b
+
+ @ For very big divisors, we must shift it a bit at a time, or
+ @ we will be in danger of overflowing.
+1: cmp \divisor, #0x80000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #1
+ movlo \curbit, \curbit, lsl #1
+ blo 1b
+
+ mov \result, #0
+
+#endif
+
+ @ Division loop
+1: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ orrhs \result, \result, \curbit
+ cmp \dividend, \divisor, lsr #1
+ subhs \dividend, \dividend, \divisor, lsr #1
+ orrhs \result, \result, \curbit, lsr #1
+ cmp \dividend, \divisor, lsr #2
+ subhs \dividend, \dividend, \divisor, lsr #2
+ orrhs \result, \result, \curbit, lsr #2
+ cmp \dividend, \divisor, lsr #3
+ subhs \dividend, \dividend, \divisor, lsr #3
+ orrhs \result, \result, \curbit, lsr #3
+ cmp \dividend, #0 @ Early termination?
+ movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
+ movne \divisor, \divisor, lsr #4
+ bne 1b
+
+.endm
+
+
+.macro ARM_DIV2_ORDER divisor, order
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz \order, \divisor
+ rsb \order, \order, #31
+
+#else
+
+ cmp \divisor, #(1 << 16)
+ movhs \divisor, \divisor, lsr #16
+ movhs \order, #16
+ movlo \order, #0
+
+ cmp \divisor, #(1 << 8)
+ movhs \divisor, \divisor, lsr #8
+ addhs \order, \order, #8
+
+ cmp \divisor, #(1 << 4)
+ movhs \divisor, \divisor, lsr #4
+ addhs \order, \order, #4
+
+ cmp \divisor, #(1 << 2)
+ addhi \order, \order, #3
+ addls \order, \order, \divisor, lsr #1
+
+#endif
+
+.endm
+
+
+.macro ARM_MOD_BODY dividend, divisor, order, spare
+
+#if __LINUX_ARM_ARCH__ >= 5
+
+ clz \order, \divisor
+ clz \spare, \dividend
+ sub \order, \order, \spare
+ mov \divisor, \divisor, lsl \order
+
+#else
+
+ mov \order, #0
+
+ @ Unless the divisor is very big, shift it up in multiples of
+ @ four bits, since this is the amount of unwinding in the main
+ @ division loop. Continue shifting until the divisor is
+ @ larger than the dividend.
+1: cmp \divisor, #0x10000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #4
+ addlo \order, \order, #4
+ blo 1b
+
+ @ For very big divisors, we must shift it a bit at a time, or
+ @ we will be in danger of overflowing.
+1: cmp \divisor, #0x80000000
+ cmplo \divisor, \dividend
+ movlo \divisor, \divisor, lsl #1
+ addlo \order, \order, #1
+ blo 1b
+
+#endif
+
+ @ Perform all needed substractions to keep only the reminder.
+ @ Do comparisons in batch of 4 first.
+ subs \order, \order, #3 @ yes, 3 is intended here
+ blt 2f
+
+1: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ cmp \dividend, \divisor, lsr #1
+ subhs \dividend, \dividend, \divisor, lsr #1
+ cmp \dividend, \divisor, lsr #2
+ subhs \dividend, \dividend, \divisor, lsr #2
+ cmp \dividend, \divisor, lsr #3
+ subhs \dividend, \dividend, \divisor, lsr #3
+ cmp \dividend, #1
+ mov \divisor, \divisor, lsr #4
+ subges \order, \order, #4
+ bge 1b
+
+ tst \order, #3
+ teqne \dividend, #0
+ beq 5f
+
+ @ Either 1, 2 or 3 comparison/substractions are left.
+2: cmn \order, #2
+ blt 4f
+ beq 3f
+ cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ mov \divisor, \divisor, lsr #1
+3: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+ mov \divisor, \divisor, lsr #1
+4: cmp \dividend, \divisor
+ subhs \dividend, \dividend, \divisor
+5:
+.endm
+
+
+ENTRY(__udivsi3)
+ENTRY(__aeabi_uidiv)
+
+ subs r2, r1, #1
+ moveq pc, lr
+ bcc Ldiv0
+ cmp r0, r1
+ bls 11f
+ tst r1, r2
+ beq 12f
+
+ ARM_DIV_BODY r0, r1, r2, r3
+
+ mov r0, r2
+ mov pc, lr
+
+11: moveq r0, #1
+ movne r0, #0
+ mov pc, lr
+
+12: ARM_DIV2_ORDER r1, r2
+
+ mov r0, r0, lsr r2
+ mov pc, lr
+
+
+ENTRY(__umodsi3)
+
+ subs r2, r1, #1 @ compare divisor with 1
+ bcc Ldiv0
+ cmpne r0, r1 @ compare dividend with divisor
+ moveq r0, #0
+ tsthi r1, r2 @ see if divisor is power of 2
+ andeq r0, r0, r2
+ movls pc, lr
+
+ ARM_MOD_BODY r0, r1, r2, r3
+
+ mov pc, lr
+
+
+ENTRY(__divsi3)
+ENTRY(__aeabi_idiv)
+
+ cmp r1, #0
+ eor ip, r0, r1 @ save the sign of the result.
+ beq Ldiv0
+ rsbmi r1, r1, #0 @ loops below use unsigned.
+ subs r2, r1, #1 @ division by 1 or -1 ?
+ beq 10f
+ movs r3, r0
+ rsbmi r3, r0, #0 @ positive dividend value
+ cmp r3, r1
+ bls 11f
+ tst r1, r2 @ divisor is power of 2 ?
+ beq 12f
+
+ ARM_DIV_BODY r3, r1, r0, r2
+
+ cmp ip, #0
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+10: teq ip, r0 @ same sign ?
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+11: movlo r0, #0
+ moveq r0, ip, asr #31
+ orreq r0, r0, #1
+ mov pc, lr
+
+12: ARM_DIV2_ORDER r1, r2
+
+ cmp ip, #0
+ mov r0, r3, lsr r2
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+
+ENTRY(__modsi3)
+
+ cmp r1, #0
+ beq Ldiv0
+ rsbmi r1, r1, #0 @ loops below use unsigned.
+ movs ip, r0 @ preserve sign of dividend
+ rsbmi r0, r0, #0 @ if negative make positive
+ subs r2, r1, #1 @ compare divisor with 1
+ cmpne r0, r1 @ compare dividend with divisor
+ moveq r0, #0
+ tsthi r1, r2 @ see if divisor is power of 2
+ andeq r0, r0, r2
+ bls 10f
+
+ ARM_MOD_BODY r0, r1, r2, r3
+
+10: cmp ip, #0
+ rsbmi r0, r0, #0
+ mov pc, lr
+
+ENTRY(__aeabi_uidivmod)
+
+ stmfd sp!, {r0, r1, ip, lr}
+ bl __aeabi_uidiv
+ ldmfd sp!, {r1, r2, ip, lr}
+ mul r3, r0, r2
+ sub r1, r1, r3
+ mov pc, lr
+
+ENTRY(__aeabi_idivmod)
+
+ stmfd sp!, {r0, r1, ip, lr}
+ bl __aeabi_idiv
+ ldmfd sp!, {r1, r2, ip, lr}
+ mul r3, r0, r2
+ sub r1, r1, r3
+ mov pc, lr
+
+Ldiv0:
+
+ str lr, [sp, #-8]!
+ bl __div0
+ mov r0, #0 @ About as wrong as it could be.
+ ldr pc, [sp], #8
+
+ENTRY(__div0)
+ mov pc, lr
diff --git a/src/target/firmware/lib/memcpy.S b/src/target/firmware/lib/memcpy.S
new file mode 100644
index 00000000..2bbd5692
--- /dev/null
+++ b/src/target/firmware/lib/memcpy.S
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/arm/lib/memcpy.S
+ *
+ * Author: Nicolas Pitre
+ * Created: Sep 28, 2005
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+
+ .macro ldr1w ptr reg abort
+ ldr \reg, [\ptr], #4
+ .endm
+
+ .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
+ ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
+ .endm
+
+ .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+ .endm
+
+ .macro ldr1b ptr reg cond=al abort
+ ldr\cond\()b \reg, [\ptr], #1
+ .endm
+
+ .macro str1w ptr reg abort
+ str \reg, [\ptr], #4
+ .endm
+
+ .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
+ stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
+ .endm
+
+ .macro str1b ptr reg cond=al abort
+ str\cond\()b \reg, [\ptr], #1
+ .endm
+
+ .macro enter reg1 reg2
+ stmdb sp!, {r0, \reg1, \reg2}
+ .endm
+
+ .macro exit reg1 reg2
+ ldmfd sp!, {r0, \reg1, \reg2}
+ .endm
+
+ .text
+
+/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
+
+ENTRY(memcpy)
+
+#include "copy_template.S"
+
diff --git a/src/target/firmware/lib/memset.S b/src/target/firmware/lib/memset.S
new file mode 100644
index 00000000..04e254a8
--- /dev/null
+++ b/src/target/firmware/lib/memset.S
@@ -0,0 +1,80 @@
+/*
+ * linux/arch/arm/lib/memset.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ASM optimised string functions
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+ .align 5
+ .word 0
+
+1: subs r2, r2, #4 @ 1 do we have enough
+ blt 5f @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [r0], #1 @ 1
+ strleb r1, [r0], #1 @ 1
+ strb r1, [r0], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+/*
+ * The pointer is now aligned and the length is adjusted. Try doing the
+ * memzero again.
+ */
+
+ENTRY(memset)
+ ands r3, r0, #3 @ 1 unaligned?
+ bne 1b @ 1
+/*
+ * we know that the pointer in r0 is aligned to a word boundary.
+ */
+ orr r1, r1, r1, lsl #8
+ orr r1, r1, r1, lsl #16
+ mov r3, r1
+ cmp r2, #16
+ blt 4f
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+ str lr, [sp, #-4]!
+ mov ip, r1
+ mov lr, r1
+
+2: subs r2, r2, #64
+ stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia r0!, {r1, r3, ip, lr}
+ bgt 2b
+ LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go.
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+ tst r2, #32
+ stmneia r0!, {r1, r3, ip, lr}
+ stmneia r0!, {r1, r3, ip, lr}
+ tst r2, #16
+ stmneia r0!, {r1, r3, ip, lr}
+ ldr lr, [sp], #4
+
+4: tst r2, #8
+ stmneia r0!, {r1, r3}
+ tst r2, #4
+ strne r1, [r0], #4
+/*
+ * When we get here, we've got less than 4 bytes to zero. We
+ * may have an unaligned pointer as well.
+ */
+5: tst r2, #2
+ strneb r1, [r0], #1
+ strneb r1, [r0], #1
+ tst r2, #1
+ strneb r1, [r0], #1
+ RETINSTR(mov,pc,lr)
diff --git a/src/target/firmware/lib/printf.c b/src/target/firmware/lib/printf.c
new file mode 100644
index 00000000..a4fc6876
--- /dev/null
+++ b/src/target/firmware/lib/printf.c
@@ -0,0 +1,19 @@
+
+#include <stdio.h>
+#include <stdarg.h>
+
+static char printf_buffer[1024];
+
+int printf(const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+ r = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, args);
+ va_end(args);
+
+ puts(printf_buffer);
+
+ return r;
+}
diff --git a/src/target/firmware/lib/setbit.S b/src/target/firmware/lib/setbit.S
new file mode 100644
index 00000000..9009bc1e
--- /dev/null
+++ b/src/target/firmware/lib/setbit.S
@@ -0,0 +1,22 @@
+/*
+ * linux/arch/arm/lib/setbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+/*
+ * Purpose : Function to set a bit
+ * Prototype: int set_bit(int bit, void *addr)
+ */
+ENTRY(_set_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_set_bit_le)
+ bitop orr
diff --git a/src/target/firmware/lib/string.c b/src/target/firmware/lib/string.c
new file mode 100644
index 00000000..437373bd
--- /dev/null
+++ b/src/target/firmware/lib/string.c
@@ -0,0 +1,50 @@
+/*
+ * linux/lib/string.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * - Added strsep() which will replace strtok() soon (because strsep() is
+ * reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ * Matthew Hawkins <matt@mh.dropbear.id.au>
+ * - Kissed strtok() goodbye
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <asm/ctype.h>
+
+
+#ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char *s, size_t count)
+{
+ const char *sc;
+
+ for (sc = s; count-- && *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
+#endif
+
+size_t strlen(const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
diff --git a/src/target/firmware/lib/testchangebit.S b/src/target/firmware/lib/testchangebit.S
new file mode 100644
index 00000000..37c303e3
--- /dev/null
+++ b/src/target/firmware/lib/testchangebit.S
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/lib/testchangebit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+ENTRY(_test_and_change_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_test_and_change_bit_le)
+ testop eor, strb
diff --git a/src/target/firmware/lib/testclearbit.S b/src/target/firmware/lib/testclearbit.S
new file mode 100644
index 00000000..985c3996
--- /dev/null
+++ b/src/target/firmware/lib/testclearbit.S
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/lib/testclearbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+ENTRY(_test_and_clear_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_test_and_clear_bit_le)
+ testop bicne, strneb
diff --git a/src/target/firmware/lib/testsetbit.S b/src/target/firmware/lib/testsetbit.S
new file mode 100644
index 00000000..4a8a164b
--- /dev/null
+++ b/src/target/firmware/lib/testsetbit.S
@@ -0,0 +1,18 @@
+/*
+ * linux/arch/arm/lib/testsetbit.S
+ *
+ * Copyright (C) 1995-1996 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/linkage.h>
+#include <asm/assembler.h>
+#include "bitops.h"
+ .text
+
+ENTRY(_test_and_set_bit_be)
+ eor r0, r0, #0x18 @ big endian byte ordering
+ENTRY(_test_and_set_bit_le)
+ testop orreq, streqb
diff --git a/src/target/firmware/lib/vsprintf.c b/src/target/firmware/lib/vsprintf.c
new file mode 100644
index 00000000..81057e4d
--- /dev/null
+++ b/src/target/firmware/lib/vsprintf.c
@@ -0,0 +1,847 @@
+/*
+ * linux/lib/vsprintf.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
+/*
+ * Wirzenius wrote this portably, Torvalds fucked it up :-)
+ */
+
+/*
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
+ * - scnprintf and vscnprintf
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <string.h>
+#include <asm/ctype.h>
+
+#include <asm/div64.h>
+
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
+ }
+ while (isxdigit(*cp) &&
+ (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -simple_strtoul(cp+1,endp,base);
+ return simple_strtoul(cp,endp,base);
+}
+
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ } else if (base == 16) {
+ if (cp[0] == '0' && toupper(cp[1]) == 'X')
+ cp += 2;
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long long simple_strtoll(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -simple_strtoull(cp+1,endp,base);
+ return simple_strtoull(cp,endp,base);
+}
+
+static int skip_atoi(const char **s)
+{
+ int i=0;
+
+ while (isdigit(**s))
+ i = i*10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+{
+ char c,sign,tmp[66];
+ const char *digits;
+ static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i;
+
+ digits = (type & LARGE) ? large_digits : small_digits;
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return NULL;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if ((signed long long) num < 0) {
+ sign = '-';
+ num = - (signed long long) num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++]='0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num,base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type&(ZEROPAD+LEFT))) {
+ while(size-->0) {
+ if (buf <= end)
+ *buf = ' ';
+ ++buf;
+ }
+ }
+ if (sign) {
+ if (buf <= end)
+ *buf = sign;
+ ++buf;
+ }
+ if (type & SPECIAL) {
+ if (base==8) {
+ if (buf <= end)
+ *buf = '0';
+ ++buf;
+ } else if (base==16) {
+ if (buf <= end)
+ *buf = '0';
+ ++buf;
+ if (buf <= end)
+ *buf = digits[33];
+ ++buf;
+ }
+ }
+ if (!(type & LEFT)) {
+ while (size-- > 0) {
+ if (buf <= end)
+ *buf = c;
+ ++buf;
+ }
+ }
+ while (i < precision--) {
+ if (buf <= end)
+ *buf = '0';
+ ++buf;
+ }
+ while (i-- > 0) {
+ if (buf <= end)
+ *buf = tmp[i];
+ ++buf;
+ }
+ while (size-- > 0) {
+ if (buf <= end)
+ *buf = ' ';
+ ++buf;
+ }
+ return buf;
+}
+
+/**
+ * vsnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which would
+ * be generated for the given input, excluding the trailing
+ * '\0', as per ISO C99. If you want to have the exact
+ * number of characters written into @buf as return value
+ * (not including the trailing '\0'), use vscnprintf. If the
+ * return is greater than or equal to @size, the resulting
+ * string is truncated.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ int len;
+ unsigned long long num;
+ int i, base;
+ char *str, *end, c;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+ /* 'z' support added 23/7/1999 S.H. */
+ /* 'z' changed to 'Z' --davidm 1/25/99 */
+ /* 't' added for ptrdiff_t */
+
+ /* Reject out-of-range values early */
+ if ((int) size < 0) {
+ return 0;
+ }
+
+ str = buf;
+ end = buf + size - 1;
+
+ if (end < buf - 1) {
+ end = ((void *) -1);
+ size = end - buf + 1;
+ }
+
+ for (; *fmt ; ++fmt) {
+ if (*fmt != '%') {
+ if (str <= end)
+ *str = *fmt;
+ ++str;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-': flags |= LEFT; goto repeat;
+ case '+': flags |= PLUS; goto repeat;
+ case ' ': flags |= SPACE; goto repeat;
+ case '#': flags |= SPECIAL; goto repeat;
+ case '0': flags |= ZEROPAD; goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (isdigit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+ *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
+ qualifier = *fmt;
+ ++fmt;
+ if (qualifier == 'l' && *fmt == 'l') {
+ qualifier = 'L';
+ ++fmt;
+ }
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT)) {
+ while (--field_width > 0) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ }
+ c = (unsigned char) va_arg(args, int);
+ if (str <= end)
+ *str = c;
+ ++str;
+ while (--field_width > 0) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT)) {
+ while (len < field_width--) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ }
+ for (i = 0; i < len; ++i) {
+ if (str <= end)
+ *str = *s;
+ ++str; ++s;
+ }
+ while (len < field_width--) {
+ if (str <= end)
+ *str = ' ';
+ ++str;
+ }
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2*sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str, end,
+ (unsigned long) va_arg(args, void *),
+ 16, field_width, precision, flags);
+ continue;
+
+
+ case 'n':
+ /* FIXME:
+ * What does C99 say about the overflow case here? */
+ if (qualifier == 'l') {
+ long * ip = va_arg(args, long *);
+ *ip = (str - buf);
+ } else if (qualifier == 'Z' || qualifier == 'z') {
+ size_t * ip = va_arg(args, size_t *);
+ *ip = (str - buf);
+ } else {
+ int * ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ case '%':
+ if (str <= end)
+ *str = '%';
+ ++str;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ if (str <= end)
+ *str = '%';
+ ++str;
+ if (*fmt) {
+ if (str <= end)
+ *str = *fmt;
+ ++str;
+ } else {
+ --fmt;
+ }
+ continue;
+ }
+ if (qualifier == 'L')
+ num = va_arg(args, long long);
+ else if (qualifier == 'l') {
+ num = va_arg(args, unsigned long);
+ if (flags & SIGN)
+ num = (signed long) num;
+ } else if (qualifier == 'Z' || qualifier == 'z') {
+ num = va_arg(args, size_t);
+ } else if (qualifier == 't') {
+ num = va_arg(args, long);
+ } else if (qualifier == 'h') {
+ num = (unsigned short) va_arg(args, int);
+ if (flags & SIGN)
+ num = (signed short) num;
+ } else {
+ num = va_arg(args, unsigned int);
+ if (flags & SIGN)
+ num = (signed int) num;
+ }
+ str = number(str, end, num, base,
+ field_width, precision, flags);
+ }
+ if (str <= end)
+ *str = '\0';
+ else if (size > 0)
+ /* don't write out a null byte if the buf size is zero */
+ *end = '\0';
+ /* the trailing null byte doesn't count towards the total
+ * ++str;
+ */
+ return str-buf;
+}
+
+
+/**
+ * vscnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The return value is the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is <= 0 the function
+ * returns 0.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want scnprintf instead.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ unsigned int i;
+
+ i=vsnprintf(buf,size,fmt,args);
+ return (i >= size) ? (size - 1) : i;
+}
+
+
+/**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99. If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsnprintf(buf,size,fmt,args);
+ va_end(args);
+ return i;
+}
+
+
+/**
+ * scnprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
+ * greater than or equal to @size, the resulting string is truncated.
+ */
+
+int scnprintf(char * buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ unsigned int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+ return (i >= size) ? (size - 1) : i;
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use vsnprintf or vscnprintf in order to avoid
+ * buffer overflows.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ return vsnprintf(buf, INT_MAX, fmt, args);
+}
+
+
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf. Use snprintf or scnprintf in order to avoid
+ * buffer overflows.
+ */
+int sprintf(char * buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i=vsnprintf(buf, INT_MAX, fmt, args);
+ va_end(args);
+ return i;
+}
+
+
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: format of buffer
+ * @args: arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+ const char *str = buf;
+ char *next;
+ char digit;
+ int num = 0;
+ int qualifier;
+ int base;
+ int field_width;
+ int is_sign = 0;
+
+ while(*fmt && *str) {
+ /* skip any white space in format */
+ /* white space in format matchs any amount of
+ * white space, including none, in the input.
+ */
+ if (isspace(*fmt)) {
+ while (isspace(*fmt))
+ ++fmt;
+ while (isspace(*str))
+ ++str;
+ }
+
+ /* anything that is not a conversion must match exactly */
+ if (*fmt != '%' && *fmt) {
+ if (*fmt++ != *str++)
+ break;
+ continue;
+ }
+
+ if (!*fmt)
+ break;
+ ++fmt;
+
+ /* skip this conversion.
+ * advance both strings to next white space
+ */
+ if (*fmt == '*') {
+ while (!isspace(*fmt) && *fmt)
+ fmt++;
+ while (!isspace(*str) && *str)
+ str++;
+ continue;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+
+ /* get conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
+ *fmt == 'Z' || *fmt == 'z') {
+ qualifier = *fmt++;
+ if (qualifier == *fmt) {
+ if (qualifier == 'h') {
+ qualifier = 'H';
+ fmt++;
+ } else if (qualifier == 'l') {
+ qualifier = 'L';
+ fmt++;
+ }
+ }
+ }
+ base = 10;
+ is_sign = 0;
+
+ if (!*fmt || !*str)
+ break;
+
+ switch(*fmt++) {
+ case 'c':
+ {
+ char *s = (char *) va_arg(args,char*);
+ if (field_width == -1)
+ field_width = 1;
+ do {
+ *s++ = *str++;
+ } while (--field_width > 0 && *str);
+ num++;
+ }
+ continue;
+ case 's':
+ {
+ char *s = (char *) va_arg(args, char *);
+ if(field_width == -1)
+ field_width = INT_MAX;
+ /* first, skip leading white space in buffer */
+ while (isspace(*str))
+ str++;
+
+ /* now copy until next white space */
+ while (*str && !isspace(*str) && field_width--) {
+ *s++ = *str++;
+ }
+ *s = '\0';
+ num++;
+ }
+ continue;
+ case 'n':
+ /* return number of characters read so far */
+ {
+ int *i = (int *)va_arg(args,int*);
+ *i = str - buf;
+ }
+ continue;
+ case 'o':
+ base = 8;
+ break;
+ case 'x':
+ case 'X':
+ base = 16;
+ break;
+ case 'i':
+ base = 0;
+ case 'd':
+ is_sign = 1;
+ case 'u':
+ break;
+ case '%':
+ /* looking for '%' in str */
+ if (*str++ != '%')
+ return num;
+ continue;
+ default:
+ /* invalid format; stop here */
+ return num;
+ }
+
+ /* have some sort of integer conversion.
+ * first, skip white space in buffer.
+ */
+ while (isspace(*str))
+ str++;
+
+ digit = *str;
+ if (is_sign && digit == '-')
+ digit = *(str + 1);
+
+ if (!digit
+ || (base == 16 && !isxdigit(digit))
+ || (base == 10 && !isdigit(digit))
+ || (base == 8 && (!isdigit(digit) || digit > '7'))
+ || (base == 0 && !isdigit(digit)))
+ break;
+
+ switch(qualifier) {
+ case 'H': /* that's 'hh' in format */
+ if (is_sign) {
+ signed char *s = (signed char *) va_arg(args,signed char *);
+ *s = (signed char) simple_strtol(str,&next,base);
+ } else {
+ unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
+ *s = (unsigned char) simple_strtoul(str, &next, base);
+ }
+ break;
+ case 'h':
+ if (is_sign) {
+ short *s = (short *) va_arg(args,short *);
+ *s = (short) simple_strtol(str,&next,base);
+ } else {
+ unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
+ *s = (unsigned short) simple_strtoul(str, &next, base);
+ }
+ break;
+ case 'l':
+ if (is_sign) {
+ long *l = (long *) va_arg(args,long *);
+ *l = simple_strtol(str,&next,base);
+ } else {
+ unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
+ *l = simple_strtoul(str,&next,base);
+ }
+ break;
+ case 'L':
+ if (is_sign) {
+ long long *l = (long long*) va_arg(args,long long *);
+ *l = simple_strtoll(str,&next,base);
+ } else {
+ unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
+ *l = simple_strtoull(str,&next,base);
+ }
+ break;
+ case 'Z':
+ case 'z':
+ {
+ size_t *s = (size_t*) va_arg(args,size_t*);
+ *s = (size_t) simple_strtoul(str,&next,base);
+ }
+ break;
+ default:
+ if (is_sign) {
+ int *i = (int *) va_arg(args, int*);
+ *i = (int) simple_strtol(str,&next,base);
+ } else {
+ unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
+ *i = (unsigned int) simple_strtoul(str,&next,base);
+ }
+ break;
+ }
+ num++;
+
+ if (!next)
+ break;
+ str = next;
+ }
+ return num;
+}
+
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf: input buffer
+ * @fmt: formatting of buffer
+ * @...: resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args,fmt);
+ i = vsscanf(buf,fmt,args);
+ va_end(args);
+ return i;
+}
+
+/* generic puts() implementation independent of who provides putchar() */
+int puts(const char *s)
+{
+#ifdef ARCH_HAS_CONSOLE
+ return _puts(s);
+#else
+ while (1) {
+ char c = *s++;
+ if (c == 0)
+ return;
+ putchar(c);
+ }
+ return 0;
+#endif
+}
diff --git a/src/target/firmware/rf/trf6151.c b/src/target/firmware/rf/trf6151.c
new file mode 100644
index 00000000..ea009858
--- /dev/null
+++ b/src/target/firmware/rf/trf6151.c
@@ -0,0 +1,380 @@
+/* Driver for RF Transceiver Circuit (TRF6151) */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <keypad.h>
+#include <gsm.h>
+
+#include <calypso/tpu.h>
+#include <calypso/tsp.h>
+
+#include <rf/trf6151.h>
+
+enum trf6151_reg {
+ REG_RX = 0, /* RF general settings */
+ REG_PLL = 1, /* PLL settings */
+ REG_PWR = 2, /* Power on/off funcitonal blocks */
+ REG_CFG = 3, /* Transceiver and PA controller settings */
+ REG_TEST1 = 4,
+ REG_TEST2 = 5,
+ REG_TEST3 = 6,
+ REG_TEST4 = 7,
+ _MAX_REG
+};
+
+/* REG_RX */
+#define RX_READ_EN (1 << 7)
+#define RX_CAL_MODE (1 << 8)
+#define RX_RF_GAIN_HIGH (3 << 9)
+#define RX_VGA_GAIN_SHIFT 11
+
+/* REG_PWR */
+#define PWR_BANDGAP_SHIFT 3
+#define PWR_BANDGAP_OFF (0 << PWR_BANDGAP_SHIFT)
+#define PWR_BANDGAP_ON_SPEEDUP (2 << PWR_BANDGAP_SHIFT)
+#define PWR_BANDGAP_ON (3 << PWR_BANDGAP_SHIFT)
+#define PWR_REGUL_ON (1 << 5)
+#define PWR_SYNTHE_OFF (0)
+#define PWR_SYNTHE_RX_ON (1 << 9)
+#define PWR_SYNTHE_TX_ON (1 << 10)
+#define PWR_RX_MODE (1 << 11)
+#define PWR_TX_MODE (1 << 13)
+#define PWR_PACTRL_APC (1 << 14)
+#define PWR_PACTRL_APCEN (1 << 15)
+
+/* REG_CFG */
+#define CFG_TX_LOOP_MANU (1 << 3)
+#define CFG_PACTLR_IDIOD_30uA (0 << 4)
+#define CFG_PACTLR_IDIOD_300uA (1 << 4)
+#define CFG_PACTLR_RES_OPEN (0 << 10)
+#define CFG_PACTLR_RES_150k (1 << 10)
+#define CFG_PACTLR_RES_300k (2 << 10)
+#define CFG_PACTLR_CAP_0pF (0 << 12)
+#define CFG_PACTLR_CAP_12p5F (1 << 12)
+#define CFG_PACTLR_CAP_25pF (3 << 12)
+#define CFG_PACTLR_CAP_50pF (2 << 12)
+#define CFG_TEMP_SENSOR (1 << 14)
+#define CFG_ILOGIC_INIT_DIS (1 << 15)
+
+/* FIXME: This must be defined in the RFFE configuration */
+#define TRF6151_TSP_UID 2
+#define TRF6151_PACTRL_CFG (CFG_PACTLR_RES_OPEN|CFG_PACTLR_CAP_0pF|CFG_PACTLR_IDIOD_30uA)
+
+#define PLL_VAL(a, b) ((a << 3) | (((b)-64) << 9))
+
+/* All values in qbits unless otherwise speciifed */
+#define TRF6151_LDO_DELAY_TS 6 /* six TDMA frames (at least 25ms) */
+#define TRF6151_RX_PLL_DELAY 184 /* 170 us */
+#define TRF6151_TX_PLL_DELAY 260 /* 170 us */
+
+uint16_t rf_arfcn = 871; /* TODO: this needs to be private */
+static uint16_t rf_band;
+
+static uint16_t trf6151_reg_cache[_MAX_REG] = {
+ [REG_RX] = 0x9E00,
+ [REG_PLL] = 0x0000,
+ [REG_PWR] = 0x0000,
+ [REG_CFG] = 0x2980,
+};
+
+/* Write to a TRF6151 register (4 TPU instructions) */
+static void trf6151_reg_write(uint16_t reg, uint16_t val)
+{
+ printd("trf6151_reg_write(reg=%u, val=0x%04x)\n", reg, val);
+ /* each TSP write takes 4 TPU instructions */
+ tsp_write(TRF6151_TSP_UID, 16, (reg | val));
+ trf6151_reg_cache[reg] = val;
+}
+
+int trf6151_set_gain(uint8_t dbm, int high)
+{
+ uint16_t reg = trf6151_reg_cache[REG_RX] & 0x07ff;
+
+ if (dbm < 14 || dbm > 40)
+ return -1;
+
+ /* clear the gain bits first */
+ reg &= ~((0x1F) << RX_VGA_GAIN_SHIFT);
+ /* OR-in the new gain value */
+ reg |= (6 + (dbm-14)/2) << RX_VGA_GAIN_SHIFT;
+
+ if (high)
+ reg |= RX_RF_GAIN_HIGH;
+ else
+ reg &= ~RX_RF_GAIN_HIGH;
+
+ trf6151_reg_write(REG_RX, reg);
+
+ return 0;
+}
+
+#define SCALE_100KHZ 100
+
+/* Compute TRF6151 PLL valuese for all 4 RX bands */
+static uint16_t trf6151_pll_rx(uint32_t freq_khz)
+{
+ uint32_t freq_100khz = freq_khz / SCALE_100KHZ; /* Scale from *1000 (k) to *100000 (0.1M) */
+ uint32_t fb_100khz; /* frequency of B alone, without A (units of 100kHz) */
+ uint32_t l;
+ uint32_t b10; /* B value expanded by a factor of 10 */
+ uint32_t a, b; /* The PLL multipliers we want to compute */
+
+ /* L = 4 for low band, 2 for high band */
+ if (freq_khz < 1000000)
+ l = 4;
+ else
+ l = 2;
+
+ /* To compute B, we assume A is zero */
+ b = (freq_100khz * 65 * l) / (64 * 26 * 10);
+
+ if ((l == 4 && (b < 135 || b > 150)) ||
+ (l == 2 && (b < 141 || b > 155)))
+ printf("Frequency %u kHz is out of spec\n", freq_khz);
+
+ /* Compute PLL frequency assuming A == 0 */
+ fb_100khz = (b * 64 * 26 * 10) / (65 * l);
+
+ /* Compute how many 100kHz units A needs to add */
+ a = freq_100khz - fb_100khz;
+
+ if (l == 2)
+ a = a / 2;
+
+ /* since all frequencies are expanded a factor of 10, we don't need to multiply A */
+ printd("Freq %u kHz => A = %u, B = %u\n", freq_khz, a, b);
+
+ /* return value in trf6151 register layout form */
+ return PLL_VAL(a, b);
+}
+
+enum trf6151_pwr_unit {
+ TRF1651_PACTLR_APC,
+ TRF6151_PACTRL_APCEN,
+ TRF6151_TRANSMITTER,
+ TRF6151_REGULATORS,
+};
+
+enum trf6151_gsm_band {
+ GSM900 = 1,
+ GSM1800 = 2,
+ GSM850_LOW = 4,
+ GSM850_HIGH = 5,
+ GSM1900 = 6,
+};
+
+static inline void trf6151_reset(void)
+{
+ /* pull the nRESET line low */
+ tsp_act_disable((1 << 0));
+ tpu_enq_wait(50);
+ /* release nRESET */
+ tsp_act_enable((1 << 0));
+}
+
+void trf6151_init(void)
+{
+ /* Configure TSPEN0, which is connected to TWL3025,
+ * FIXME: why is this here and not in the TWL3025 driver? */
+ tsp_setup(0, 1, 0, 0);
+ /* Configure TSPEN2, which is connected ot TRF6151 STROBE */
+ tsp_setup(TRF6151_TSP_UID, 0, 1, 1);
+
+ trf6151_reset();
+
+ /* configure TRF6151 for operation */
+ trf6151_power(1);
+ trf6151_reg_write(REG_CFG, TRF6151_PACTRL_CFG | CFG_ILOGIC_INIT_DIS);
+
+ /* FIXME: Uplink / Downlink Calibration */
+}
+
+void trf6151_power(int on)
+{
+ if (on) {
+ trf6151_reg_write(REG_PWR, PWR_REGUL_ON | PWR_BANDGAP_ON);
+ /* wait until regulators are stable (25ms == 27100 qbits) */
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(5000);
+ tpu_enq_wait(2100);
+ } else
+ trf6151_reg_write(REG_PWR, PWR_BANDGAP_ON);
+}
+
+/* Set the operational mode of the TRF6151 chip */
+void trf6151_set_mode(enum trf6151_mode mode)
+{
+ uint16_t pwr = (PWR_REGUL_ON | PWR_BANDGAP_ON | (rf_band<<6));
+
+ switch (mode) {
+ case TRF6151_IDLE:
+ /* should we switch of the RF gain for power saving? */
+ break;
+ case TRF6151_RX:
+ pwr |= (PWR_SYNTHE_RX_ON | PWR_RX_MODE);
+ break;
+ case TRF6151_TX:
+ pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE);
+ break;
+ }
+ trf6151_reg_write(REG_PWR, pwr);
+}
+
+static void trf6151_band_select(enum trf6151_gsm_band band)
+{
+ uint16_t pwr = trf6151_reg_cache[REG_PWR];
+
+ pwr &= ~(3 << 6);
+ pwr |= (band << 6);
+
+ trf6151_reg_write(REG_PWR, pwr);
+}
+
+/* Set ARFCN. Takes 2 reg_write, i.e. 8 TPU instructions */
+void trf6151_set_arfcn(uint16_t arfcn, int uplink)
+{
+ uint32_t freq_khz;
+
+ switch (gsm_arfcn2band(arfcn)) {
+ case GSM_850:
+ rf_band = GSM850_LOW; /* FIXME: what about HIGH */
+ break;
+ case GSM_900:
+ rf_band = GSM900;
+ break;
+ case GSM_1800:
+ rf_band = GSM1800;
+ break;
+ case GSM_1900:
+ rf_band = GSM1900;
+ break;
+ case GSM_450:
+ case GSM_480:
+ case GSM_750:
+ case GSM_810:
+ printf("Unsupported rf_band.\n");
+ break;
+ }
+
+ trf6151_band_select(rf_band);
+
+ freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100;
+ printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz);
+
+ if (uplink == 0)
+ trf6151_reg_write(REG_PLL, trf6151_pll_rx(freq_khz));
+ else
+ printf("We don't support uplink tuning yet!\n");
+
+ rf_arfcn = arfcn; // TODO: arfcn is referenced at other places
+}
+
+void trf6151_calib_dc_offs(void)
+{
+ uint16_t rx = trf6151_reg_cache[REG_RX];
+
+ /* Set RX CAL Mode bit, it will re-set automatically */
+ trf6151_reg_write(REG_RX, rx | RX_CAL_MODE);
+ /* DC offset calibration can take up to 50us, i.e. 54.16 * 923ns*/
+ tpu_enq_wait(55);
+}
+
+/* Frontend gain can be switched high or low (dB) */
+#define TRF6151_FE_GAIN_LOW 7
+#define TRF6151_FE_GAIN_HIGH 27
+
+/* VGA at baseband can be adjusted in this range (dB) */
+#define TRF6151_VGA_GAIN_MIN 14
+#define TRF6151_VGA_GAIN_MAX 40
+
+uint8_t trf6151_get_gain(void)
+{
+ uint16_t vga, reg_rx = trf6151_reg_cache[REG_RX];
+ uint8_t gain = 0;
+
+ switch ((reg_rx >> 9) & 3) {
+ case 0:
+ gain += TRF6151_FE_GAIN_LOW;
+ break;
+ case 3:
+ gain += TRF6151_FE_GAIN_HIGH;
+ break;
+ }
+
+ vga = (reg_rx >> RX_VGA_GAIN_SHIFT) & 0x1f;
+ if (vga < 6)
+ vga = 6;
+
+ gain += TRF6151_VGA_GAIN_MIN + (vga - 6) * 2;
+
+ return gain;
+}
+
+void trf6151_test(uint16_t arfcn)
+{
+ /* Select ARFCN 871 downlink */
+ trf6151_set_arfcn(arfcn, 0);
+ trf6151_set_gain(40, 0);
+
+ trf6151_set_mode(TRF6151_RX);
+ //trf6151_reg_write(REG_PWR, (PWR_SYNTHE_RX_ON | PWR_RX_MODE | PWR_REGUL_ON | (rf_band<<6) | PWR_BANDGAP_ON));
+ /* Wait for PLL stabilization (170us max) */
+ tpu_enq_wait(TRF6151_RX_PLL_DELAY);
+
+ /* Use DC offset calibration after RX mode has been switched on
+ * (might not be needed) */
+ trf6151_calib_dc_offs();
+
+ tpu_enq_sleep();
+ tpu_enable(1);
+ tpu_wait_idle();
+}
+
+#define TRF6151_REGWR_QBITS 8 /* 4 GSM qbits + 4 TPU instructions */
+#define TRF6151_RX_TPU_INSTR 4 /* set_gain(1), set_arfcn(2), set_mode(1) */
+
+/* delay caused by this driver programming the TPU for RX mode */
+#define TRF6151_RX_TPU_DELAY (TRF6151_RX_TPU_INSTR * TRF6151_REGWR_QBITS)
+
+/* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
+void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn, uint8_t vga_dbm, int rf_gain_high)
+{
+ int16_t start_pll_qbits;
+
+ /* Set the AGC and PLL registers right now, not time critical */
+ trf6151_set_gain(vga_dbm, rf_gain_high);
+ trf6151_set_arfcn(arfcn, 0);
+
+ /* power up at the right time _before_ the 'start_qbits' point in time */
+ start_pll_qbits = add_mod5000(start_qbits, -(TRF6151_RX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
+ tpu_enq_at(start_pll_qbits);
+ trf6151_set_mode(TRF6151_RX);
+
+ /* FIXME: power down at the right time again */
+}
diff --git a/src/target_dsp/.gitignore b/src/target_dsp/.gitignore
new file mode 100644
index 00000000..5cf144ea
--- /dev/null
+++ b/src/target_dsp/.gitignore
@@ -0,0 +1,4 @@
+*.o
+*.a
+*.coff
+*.bin
diff --git a/src/target_dsp/calypso/Makefile b/src/target_dsp/calypso/Makefile
new file mode 100644
index 00000000..ff21e694
--- /dev/null
+++ b/src/target_dsp/calypso/Makefile
@@ -0,0 +1,7 @@
+dsp_dump.bin: bl_stage3.S dsp_dump.lds
+ c54x-coff-as bl_stage3.S -o bl_stage3.o
+ c54x-coff-ld --script dsp_dump.lds bl_stage3.o -o dsp_dump.coff
+ c54x-coff-objcopy -j .text -O binary dsp_dump.coff dsp_dump.bin
+
+clean:
+ rm -f *.o *.bin *.coff
diff --git a/src/target_dsp/calypso/bin2cfile.py b/src/target_dsp/calypso/bin2cfile.py
new file mode 100755
index 00000000..51401b8f
--- /dev/null
+++ b/src/target_dsp/calypso/bin2cfile.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import struct
+import sys
+
+def group_by_n(s, n, do_join=True):
+ return ( ''.join(x) for x in zip(*[s[i::n] for i in range(n)]) )
+
+
+def main(pn, filename):
+ # Get all bytes
+ f = open(filename, 'r')
+ d = f.read()
+ f.close()
+
+ # Get the data
+ ops = ''.join([
+ '0x%04x,%c' % (
+ struct.unpack('=H', x)[0],
+ '\n' if (i&3==3) else ' '
+ )
+ for i, x
+ in enumerate(group_by_n(d, 2))
+ ])[:-1]
+
+ # Header / footer
+ print """
+#define _SA_DECL (const uint16_t *)&(const uint16_t [])
+
+static const struct dsp_section dsp_xxx[] = {
+ {
+ .addr = 0x,
+ .size = 0x%04x,
+ .data = _SA_DECL {
+%s
+ },
+ },
+ { /* Guard */
+ .addr = 0,
+ .size = 0,
+ .data = NULL,
+ },
+};
+
+#undef _SA_DECL
+""" % (len(d)/2, ops)
+
+
+if __name__ == "__main__":
+ main(*sys.argv)
diff --git a/src/target_dsp/calypso/bl_stage3.S b/src/target_dsp/calypso/bl_stage3.S
new file mode 100644
index 00000000..402c3c59
--- /dev/null
+++ b/src/target_dsp/calypso/bl_stage3.S
@@ -0,0 +1,142 @@
+
+BCSR .equ 0x29
+
+CMD_IDLE .equ 1 ; Do nothing / DSP ready for commands
+CMD_COPY_BLOCK .equ 2 ; (if size == 0, then exec)
+CMD_COPY_MODE .equ 4 ; Select copy mode
+ ; (0=code write, 1=data write,
+ ; 2=code read, 3=data read,
+ ; 4=prom read, 5=drom read)
+CMD_VERSION .equ 0xffff ; API_RAM[0] = bootloader version
+
+VERSION .equ 0x0100 ; 1.00
+
+
+ .section .apiram
+
+ .org 0x07fc
+bl_addr_hi .ds 1
+bl_size .ds 1
+bl_addr_lo .ds 1
+bl_status .ds 1
+
+
+ .text
+ .mmregs
+_start:
+ orm #2, *(BCSR) ; ?
+
+ ld #0x1f, DP
+ stm #0x1100, SP
+ stm #0, AR4
+_done:
+ stm #_api_ram, AR2
+ st #CMD_IDLE, @bl_status
+_loop:
+ ; Version
+ cmpm @bl_status, #CMD_VERSION
+ bc 1f, ntc
+
+ bd _done
+ st #VERSION, *AR2
+1:
+
+ ; Select copy mode
+ cmpm @bl_status, #CMD_COPY_MODE
+ bc 1f, ntc
+
+ bd _done
+ mvdm @_api_ram, AR4
+1:
+
+ ; Copy
+ cmpm @bl_status, #CMD_COPY_BLOCK
+ bc _loop, ntc
+
+ ; Capture values for copy operations
+ ; A = full address
+ ; AR1 size-1
+ ; AR2 api_ram (set previously)
+ ; AR3 data/code address
+ ; AR4 mode
+
+ ldu @bl_addr_lo, A
+ stlm A, AR3
+ add @bl_addr_hi, 16, A
+
+ ldu @bl_size, B
+ stlm B, AR1
+ ; mar *AR1- ; We do this in a delay slot later on ...
+
+ ; Start
+ bc 1f, bneq ; B still contains size
+ bacc A
+
+1:
+ ; Select
+ stm #AR4, AR5 ; AR5 = &AR4
+ bit *AR5, 13 ; Test mode(2)
+ bcd _read_rom, tc
+ mar *AR1-
+ bit *AR5, 15 ; Test mode(0) lsb
+ bcd _copy_data, tc
+ bit *AR5, 14 ; Test mode(1)
+ nop
+
+ ; Copy to/from Program space
+_copy_prog:
+ bc _read_prog, tc
+
+ ; Copy from API -> prog space (mode 0)
+_write_prog:
+ rpt *(AR1)
+ writa *AR2+
+ b _done
+
+ ; Copy from prog space -> API (mode 2)
+_read_prog:
+ rpt *(AR1)
+ reada *AR2+
+ b _done
+
+ ; Copy to/from Data space
+_copy_data:
+ bc _read_data, tc
+
+ ; Copy from API -> data space (mode 1)
+_write_data:
+ rpt *(AR1)
+ mvdd *AR2+, *AR3+
+ b _done
+
+ ; Copy from data space -> API (mode 3)
+_read_data:
+ rpt *(AR1)
+ mvdd *AR3+, *AR2+
+ b _done
+
+ ; Read from {D,P}ROM bypassing protection
+_read_rom:
+ ldm AR1, B ; Can't put those two ops in the delay slot of
+ stlm B, BRC ; 'bc' because of unprotected pipeline conflicts
+ bc _read_rom_data, tc
+
+_read_rom_prog:
+ rptb 1f - 1
+ call prom_read_xplt
+1:
+ b _done
+
+_read_rom_data:
+ rptb 1f - 1
+ call drom_read_xplt
+1:
+ b _done
+
+
+drom_read_xplt .equ 0xe4b8
+prom_read_xplt .equ 0x7213
+
+
+ .end
+
diff --git a/src/target_dsp/calypso/dsp_dump.lds b/src/target_dsp/calypso/dsp_dump.lds
new file mode 100644
index 00000000..56633026
--- /dev/null
+++ b/src/target_dsp/calypso/dsp_dump.lds
@@ -0,0 +1,22 @@
+OUTPUT_FORMAT("coff1-c54x")
+OUTPUT_ARCH("")
+MEMORY
+{
+ apiram (RWXI) : ORIGIN = 0x0800, LENGTH = 0x2000
+}
+SECTIONS
+{
+ . = 0x0800;
+
+ .apiram :
+ {
+ PROVIDE(_api_ram = .);
+ *(.apiram)
+ } > apiram
+
+ .text :
+ {
+ *(.text)
+ } > apiram
+}
+