Initial import of OsmocomBB into git repository

This commit is contained in:
Harald Welte 2010-02-18 16:46:36 +01:00
commit fbe7b94c9c
178 changed files with 25804 additions and 0 deletions

707
doc/calypso-block.svg Normal file
View File

@ -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

View File

@ -0,0 +1,2 @@
GSM burst duration: 577uS
RITA synthesizer retuning max: 170uS

184
doc/calypso-signals.txt Normal file
View File

@ -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

746
doc/gsmdevboard-block.svg Normal file
View File

@ -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

134
include/l1a_l23_interface.h Normal file
View File

@ -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

10
src/host/calypso_pll/pll.pl Executable file
View File

@ -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);
}
}

14
src/host/layer2/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
Makefile
Makefile.in
aclocal.m4
configure
missing
*.o
depcomp
config.*
*.sw?
*.deps
layer2
install-sh
autom4te.cache
*.a

View File

@ -0,0 +1,3 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
SUBDIRS = include src

View File

@ -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)

View File

@ -0,0 +1,2 @@
noinst_HEADERS = l1a_l23_interface.h
SUBDIRS = osmocom

View File

@ -0,0 +1 @@
../../../../include/l1a_l23_interface.h

View File

@ -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

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/debug.h

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/gsm_04_08.h

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/linuxlist.h

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/meas_rep.h

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/msgb.h

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/select.h

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/talloc.h

View File

@ -0,0 +1 @@
../../../libosmocom/include/osmocom/timer.h

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1 @@
../../../libosmocom/src/debug.c

View File

@ -0,0 +1 @@
../../../libosmocom/src/msgb.c

View File

@ -0,0 +1 @@
../../../libosmocom/src/select.c

View File

@ -0,0 +1 @@
../../../libosmocom/src/signal.c

View File

@ -0,0 +1 @@
../../../libosmocom/src/talloc.c

View File

@ -0,0 +1 @@
../../../libosmocom/src/timer.c

View File

@ -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;
}

View File

@ -0,0 +1 @@
This is a copy of OpenBSC header and sources. Do not edit them.

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,185 @@
/*
* (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <assert.h>
#include <string.h>
#include <osmocom/timer.h>
static LLIST_HEAD(timer_list);
static struct timeval s_nearest_time;
static struct timeval s_select_time;
#define MICRO_SECONDS 1000000LL
#define TIME_SMALLER(left, right) \
(left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
void bsc_add_timer(struct timer_list *timer)
{
struct timer_list *list_timer;
/* TODO: Optimize and remember the closest item... */
timer->active = 1;
/* this might be called from within update_timers */
llist_for_each_entry(list_timer, &timer_list, entry)
if (timer == list_timer)
return;
timer->in_list = 1;
llist_add(&timer->entry, &timer_list);
}
void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
{
struct timeval current_time;
gettimeofday(&current_time, NULL);
unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
currentTime += seconds * MICRO_SECONDS + microseconds;
timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
bsc_add_timer(timer);
}
void bsc_del_timer(struct timer_list *timer)
{
if (timer->in_list) {
timer->active = 0;
timer->in_list = 0;
llist_del(&timer->entry);
}
}
int bsc_timer_pending(struct timer_list *timer)
{
return timer->active;
}
/*
* if we have a nearest time return the delta between the current
* time and the time of the nearest timer.
* If the nearest timer timed out return NULL and then we will
* dispatch everything after the select
*/
struct timeval *bsc_nearest_timer()
{
struct timeval current_time;
if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
return NULL;
if (gettimeofday(&current_time, NULL) == -1)
return NULL;
unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
if (nearestTime < currentTime) {
s_select_time.tv_sec = 0;
s_select_time.tv_usec = 0;
} else {
s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
}
return &s_select_time;
}
/*
* Find the nearest time and update s_nearest_time
*/
void bsc_prepare_timers()
{
struct timer_list *timer, *nearest_timer = NULL;
llist_for_each_entry(timer, &timer_list, entry) {
if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
nearest_timer = timer;
}
}
if (nearest_timer) {
s_nearest_time = nearest_timer->timeout;
} else {
memset(&s_nearest_time, 0, sizeof(struct timeval));
}
}
/*
* fire all timers... and remove them
*/
int bsc_update_timers()
{
struct timeval current_time;
struct timer_list *timer, *tmp;
int work = 0;
gettimeofday(&current_time, NULL);
/*
* The callbacks might mess with our list and in this case
* even llist_for_each_entry_safe is not safe to use. To allow
* del_timer, add_timer, schedule_timer to be called from within
* the callback we jump through some loops.
*
* First we set the handled flag of each active timer to zero,
* then we iterate over the list and execute the callbacks. As the
* list might have been changed (specially the next) from within
* the callback we have to start over again. Once every callback
* is dispatched we will remove the non-active from the list.
*
* TODO: If this is a performance issue we can poison a global
* variable in add_timer and del_timer and only then restart.
*/
llist_for_each_entry(timer, &timer_list, entry) {
timer->handled = 0;
}
restart:
llist_for_each_entry(timer, &timer_list, entry) {
if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
timer->handled = 1;
timer->active = 0;
(*timer->cb)(timer->data);
work = 1;
goto restart;
}
}
llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
timer->handled = 0;
if (!timer->active) {
bsc_del_timer(timer);
}
}
return work;
}
int bsc_timer_check(void)
{
struct timer_list *timer;
int i = 0;
llist_for_each_entry(timer, &timer_list, entry) {
i++;
}
return i;
}

9
src/host/osmocon/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.o
osmocon
*.id*
*.nam
*.til
*.dump
*.bin
*.log
version.h

19
src/host/osmocon/Makefile Normal file
View File

@ -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

View File

@ -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);

660
src/host/osmocon/osmocon.c Normal file
View File

@ -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);
}

111
src/host/rita_pll/rita_pll.pl Executable file
View File

@ -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

View File

@ -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

7
src/target/firmware/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.o
*.a
*.lst
*.bin
*.elf
*.size
*~

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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) {}
}

View File

@ -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) {}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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 = .);
}

View File

@ -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

View File

@ -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)
{
}

View File

@ -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();
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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 !?! */
};

View File

@ -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);
}
}

View File

@ -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));
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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');
}

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
}

View File

@ -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
}

View File

@ -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

View File

@ -0,0 +1,7 @@
#ifndef _ARM_H
#define _ARM_H
void arm_enable_interrupts(void);
int arm_disable_interrupts(void);
#endif

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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