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