Initial import of OsmocomBB into git repository
This commit is contained in:
commit
fbe7b94c9c
|
@ -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>
|
After Width: | Height: | Size: 35 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
GSM burst duration: 577uS
|
||||||
|
RITA synthesizer retuning max: 170uS
|
|
@ -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
|
|
@ -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>
|
After Width: | Height: | Size: 37 KiB |
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
|
aclocal.m4
|
||||||
|
configure
|
||||||
|
missing
|
||||||
|
*.o
|
||||||
|
depcomp
|
||||||
|
config.*
|
||||||
|
*.sw?
|
||||||
|
*.deps
|
||||||
|
layer2
|
||||||
|
install-sh
|
||||||
|
autom4te.cache
|
||||||
|
*.a
|
|
@ -0,0 +1,3 @@
|
||||||
|
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
|
||||||
|
|
||||||
|
SUBDIRS = include src
|
|
@ -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)
|
|
@ -0,0 +1,2 @@
|
||||||
|
noinst_HEADERS = l1a_l23_interface.h
|
||||||
|
SUBDIRS = osmocom
|
|
@ -0,0 +1 @@
|
||||||
|
../../../../include/l1a_l23_interface.h
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/debug.h
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/gsm_04_08.h
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/linuxlist.h
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/meas_rep.h
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/msgb.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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/select.h
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/talloc.h
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/include/osmocom/timer.h
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/src/debug.c
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/src/msgb.c
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/src/select.c
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/src/signal.c
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/src/talloc.c
|
|
@ -0,0 +1 @@
|
||||||
|
../../../libosmocom/src/timer.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;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
This is a copy of OpenBSC header and sources. Do not edit them.
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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");
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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(¤t_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(¤t_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(¤t_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;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
*.o
|
||||||
|
osmocon
|
||||||
|
*.id*
|
||||||
|
*.nam
|
||||||
|
*.til
|
||||||
|
*.dump
|
||||||
|
*.bin
|
||||||
|
*.log
|
||||||
|
version.h
|
|
@ -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
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -0,0 +1,7 @@
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.lst
|
||||||
|
*.bin
|
||||||
|
*.elf
|
||||||
|
*.size
|
||||||
|
*~
|
|
@ -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)
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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) {}
|
||||||
|
}
|
||||||
|
|
|
@ -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) {}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 = .);
|
||||||
|
}
|
|
@ -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
|
|
@ -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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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)
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 !?! */
|
||||||
|
};
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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)
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
Binary file not shown.
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef _ARM_H
|
||||||
|
#define _ARM_H
|
||||||
|
|
||||||
|
void arm_enable_interrupts(void);
|
||||||
|
int arm_disable_interrupts(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue