Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7ab8990be
|
||
|
|
9c608021f8 | ||
|
|
b67949fb5d | ||
|
|
255333f503 | ||
|
|
d4cd953018 | ||
|
|
45447099c9 | ||
|
|
4dd5d6b856 | ||
|
|
86f9b54863 | ||
|
|
add1ae03aa | ||
|
|
fa8a03ec5e | ||
|
|
6a1d35cb3a | ||
|
|
f6b0a7be3a | ||
|
|
8a9e2759d4 | ||
|
|
bacbb0165b | ||
|
|
df2340e48d | ||
|
|
a5279bffaf | ||
|
|
b46e4a6ad5 | ||
|
|
e65d7d1636 | ||
|
|
1f466936cb | ||
|
|
df8e50a824 | ||
|
|
4f45b045c3 | ||
|
|
3c4943340b | ||
|
|
ce67a58983 | ||
|
|
a6b6b71ded | ||
|
|
580f1de0fe | ||
|
|
f9e88d6f91 | ||
|
|
ca035e2ec1 | ||
|
|
5c0720da32 | ||
|
|
374fd1be01 | ||
|
|
f144067634 | ||
|
|
bbf438e1a8 | ||
|
|
670db0d169 | ||
|
|
6eb58dcccb | ||
|
|
b090564a85 | ||
|
|
38f83f8db4 | ||
|
|
342dc610b3 | ||
|
|
67427daf17 | ||
|
|
bf24ca2345 | ||
|
|
5c845a947e | ||
|
|
673ccaf71d | ||
|
|
9bc4b8c26f | ||
|
|
e6422cf5a2 | ||
|
|
a6effa8f62 | ||
|
|
e16a79f75e | ||
|
|
93bd73d451 | ||
|
|
0e5ceffa42 | ||
|
|
ca080dd33f | ||
|
|
4ae1f13624 | ||
|
|
69a7c2705e | ||
|
|
8d053c9074 | ||
|
|
f37c2cd7e8 | ||
|
|
e94279eecb | ||
|
|
52793b733d | ||
|
|
4bd0a47b22 | ||
|
|
adeca0dd45 | ||
|
|
b87411c02f | ||
|
|
7f38b4bd10 | ||
|
|
9e5646d30e | ||
|
|
33442482c6 | ||
|
|
e987dcd948 | ||
|
|
2fd11378c8 | ||
|
|
808ce724ee | ||
|
|
ca1db96690 | ||
|
|
a6c20b5ee4 | ||
|
|
e685787e67 | ||
|
|
10b495120e | ||
|
|
559fe2a3bd | ||
|
|
ccec7a182f | ||
|
|
31569c169a | ||
|
|
27a55c3367 | ||
|
|
cda5dc6116 | ||
|
|
5cbd5e92b8 | ||
|
|
1ec3777cb8 | ||
|
|
897919a70f | ||
|
|
76b18b9d39 | ||
|
|
ffcc10f689 | ||
|
|
16cdf3e776 | ||
|
|
dc81ebb855 | ||
|
|
66ecce9a3d | ||
|
|
87867a5904 | ||
|
|
f0b8ee117b | ||
|
|
4c8206b44f | ||
|
|
9bf886c041 | ||
|
|
955ee1bd1e | ||
|
|
08485a0c09 | ||
|
|
b4314bce15 | ||
|
|
117d0bb2d0 | ||
|
|
f7bad18a56 | ||
|
|
82de19bee1 | ||
|
|
b7c28b2c1b | ||
|
|
0a1ac25219 | ||
|
|
bd59c47ec3 | ||
|
|
645e280d69 | ||
|
|
d4ff1d9328 | ||
|
|
bc0f663e92 | ||
|
|
b8fb95b2aa | ||
|
|
e36423e8c2 | ||
|
|
430930537c | ||
|
|
7522a9fbc7 | ||
|
|
6ec64f4992 | ||
|
|
8f57f7ef61 | ||
|
|
3d71caab8f | ||
|
|
4ccf8fb369 | ||
|
|
188fa70c80 | ||
|
|
f2a51b5041 | ||
|
|
19e2b22193 | ||
|
|
15dbd14d7a | ||
|
|
0650cdf51f | ||
|
|
9ea8f2bb38 | ||
|
|
9a5f940046 | ||
|
|
5e79d651ca | ||
|
|
676da47751 | ||
|
|
ea7f2a441a | ||
|
|
61d77eed68 | ||
|
|
8a433f2d7a | ||
|
|
cf95375177 | ||
|
|
d2e7b3d242 | ||
|
|
54805eb040 | ||
|
|
7b3e9bcf00 | ||
|
|
96e4fa5995 | ||
|
|
c560f3642c | ||
|
|
98451c5851 | ||
|
|
a1623bcb7e | ||
|
|
c90c6319fe | ||
|
|
aeb9e897db | ||
|
|
6952d73082 | ||
|
|
bc7894b99d | ||
|
|
abcf256268 | ||
|
|
09920cf8ab | ||
|
|
96de6a6215 | ||
|
|
2504f9e553 | ||
|
|
2e9748e6a5 | ||
|
|
fc987674dd | ||
|
|
62fa041f86 | ||
|
|
ed4bdab6e7 | ||
|
|
d5028a12ca | ||
|
|
6482e4d2b7 | ||
|
|
57b0c6d0c4 | ||
|
|
4a4005b46d | ||
|
|
5f0897d372 | ||
|
|
d4342a8cdf | ||
|
|
055621d3a2 | ||
|
|
f36a762168 | ||
|
|
c258289b74 | ||
|
|
3c1ab9934d | ||
|
|
b48b9b558c | ||
|
|
b7f80de25d | ||
|
|
1ee86c05f4 | ||
|
|
79af7395bf | ||
|
|
ccef3c6daa | ||
|
|
05f7048580 | ||
|
|
75ea4bfbd8 | ||
|
|
3f406cc9ad | ||
|
|
94a2fe0c17 | ||
|
|
289d2f22b2 | ||
|
|
f965980e2b | ||
|
|
ef678ecf6c | ||
|
|
33f1dc8b55 | ||
|
|
bb90caec1b | ||
|
|
c86e130ab1 | ||
|
|
448365b588 | ||
|
|
ef1960cc32 | ||
|
|
5633a06710 | ||
|
|
d61815f40e | ||
|
|
15219cb99c | ||
|
|
db4c7c1951 | ||
|
|
52efd5a404 | ||
|
|
bc9f42f559 | ||
|
|
a9b1332f8f | ||
|
|
e8f9a79174 | ||
|
|
349a9d40ef | ||
|
|
c87687128f | ||
|
|
8b5c945078 | ||
|
|
2c15535099 | ||
|
|
8369f94195 | ||
|
|
f1095777c6 | ||
|
|
6372323ee8 | ||
|
|
7023b4b290 | ||
|
|
8c305104a0 | ||
|
|
d3eb042a1c | ||
|
|
93680de944 | ||
|
|
5fd0755448 | ||
|
|
bebb608bc8 | ||
|
|
75c87a1583 | ||
|
|
5d20747c30 | ||
|
|
e66015b880 | ||
|
|
e30e08136a | ||
|
|
e00331fb42 | ||
|
|
eb23177014 | ||
|
|
5611e8a68c | ||
|
|
bc4aeefab5 | ||
|
|
ea980459f1 | ||
|
|
c23e8df260 | ||
|
|
1a59034571 | ||
|
|
feb2d3ac6a | ||
|
|
78fc280577 | ||
|
|
ea9f9d5a69 | ||
|
|
3dc90e643c | ||
|
|
351bfbd055 | ||
|
|
3538c40ad1 | ||
|
|
b286e79ddb | ||
|
|
e443393aa5 | ||
|
|
8c788bad62 | ||
|
|
142ef93ddc | ||
|
|
89566f559b | ||
|
|
cfd3b662a5 | ||
|
|
65888448bf | ||
|
|
26b6f86f84 | ||
|
|
f3d203c205 | ||
|
|
79a171e823 | ||
|
|
99608d2b3f | ||
|
|
f0712d5b23 | ||
|
|
8d52950ede | ||
|
|
a8986bf631 | ||
|
|
9a1f63c5ae | ||
|
|
b1564909d7 | ||
|
|
d6eba11357 | ||
|
|
c88e5264c9 | ||
|
|
84fc04f647 | ||
|
|
03c6c3899f | ||
|
|
1610debbd5 | ||
|
|
4356b2124e | ||
|
|
dfc021d7c4 | ||
|
|
23b916bcc9 | ||
|
|
d88176dbef | ||
|
|
46750e99d0 | ||
|
|
193e01aa66 | ||
|
|
f898ac4411 | ||
|
|
c6ee6a8e68 | ||
|
|
1096c8b426 | ||
|
|
97eb4484d9 | ||
|
|
d247e9bdc8 | ||
|
|
c5d3897e77 | ||
|
|
3b68eaf303 | ||
|
|
62e26a81aa | ||
|
|
75abff061a | ||
|
|
17dd99f368 | ||
|
|
89bc4a10a3 | ||
|
|
61a23aff66 | ||
|
|
9b68e43ac1 | ||
|
|
de32a6140a | ||
|
|
55bfee79a2 | ||
|
|
287cb10250 | ||
|
|
08e53f404d | ||
|
|
f3870fd788 | ||
|
|
1b393d1e41 | ||
|
|
1c1bfb9c78 | ||
|
|
0cd7a0c2cc | ||
|
|
79832d9289 | ||
|
|
796dc3a677 | ||
|
|
1c20e5ff5f | ||
|
|
fbd23222b1 | ||
|
|
47bdc71eea | ||
|
|
d9e43ef41c | ||
|
|
3d914ce22b | ||
|
|
2b80f8e620 | ||
|
|
0df9ca3e59 | ||
|
|
3637723661 | ||
|
|
a02caaac15 | ||
|
|
a1febdd2ea | ||
|
|
848e3fe06c | ||
|
|
eb97fad2a7 | ||
|
|
7de5d7fd92 | ||
|
|
032538ec5a | ||
|
|
2c34ec70d2 | ||
|
|
5a6965afef | ||
|
|
acf7e1cad7 | ||
|
|
37844a6b9a | ||
|
|
5c90f39f6e | ||
|
|
5ca1e0c899 | ||
|
|
b997951f97 | ||
|
|
6dae516af2 | ||
|
|
f5a9d273ce | ||
|
|
22f71b0f25 | ||
|
|
f96a530392 | ||
|
|
3e17c94722 | ||
|
|
1eef797e29 | ||
|
|
62bb8e4e28 | ||
|
|
2f7bab98bf | ||
|
|
3480526cde | ||
|
|
7dd8fdb560 | ||
|
|
1bcaf8f79c | ||
|
|
e362f3cab9 | ||
|
|
9ea9bea096 | ||
|
|
1e84b07b39 | ||
|
|
e205b47789 | ||
|
|
1edbc5e52e | ||
|
|
0629204d39 | ||
|
|
a01de09ca5 | ||
|
|
355fe9dc62 | ||
|
|
857123e9e4 | ||
|
|
edb4793863 | ||
|
|
880a3e0846 | ||
|
|
9833f94dad | ||
|
|
cffeb329c4 | ||
|
|
4f6eb6e936 | ||
|
|
1776315097 | ||
|
|
def1d49ab4 | ||
|
|
3e863759d3 | ||
|
|
87202c38a0 | ||
|
|
246394d25b | ||
|
|
6ecc3e2a80 | ||
|
|
9164f331a3 | ||
|
|
d5ff815e72 | ||
|
|
8c624670cc | ||
|
|
51072eb40a | ||
|
|
bd54b19bbf | ||
|
|
69b5278710 | ||
|
|
2e78262c10 | ||
|
|
c03e01879e | ||
|
|
9087b564ba | ||
|
|
8084f68b50 | ||
|
|
1ebc2b8308 | ||
|
|
ae03494a73 | ||
|
|
6665ba9917 | ||
|
|
75df75b4e9 | ||
|
|
82dd535429 | ||
|
|
288726981a | ||
|
|
8635ea66a7 | ||
|
|
cbffb8f924 | ||
|
|
7b5d36bd4c | ||
|
|
067c84ea2c | ||
|
|
29c2b60670 | ||
|
|
09b6b377fe | ||
|
|
a6ec2b36c4 | ||
|
|
2cbeb4d0fe | ||
|
|
116e77bef7 | ||
|
|
2746da7a03 | ||
|
|
3d7b15e30b | ||
|
|
912ec5210e | ||
|
|
6a6a6348f5 | ||
|
|
01ec9928f9 | ||
|
|
bd141d2739 | ||
|
|
463dc3c6dd | ||
|
|
3f96851407 | ||
|
|
10217cd331 | ||
|
|
886b40e4b5 | ||
|
|
99294e1b74 | ||
|
|
5f0b6bb328 | ||
|
|
aa366ea133 | ||
|
|
4ef49e123a | ||
|
|
64505e1b73 | ||
|
|
a9c0daab68 | ||
|
|
420482c6b7 | ||
|
|
09a6405501 | ||
|
|
cc8cca84ef | ||
|
|
e98891e52d | ||
|
|
e66d87fde0 | ||
|
|
e4f7cf7bc5 | ||
|
|
cd9b51ad80 | ||
|
|
2189eebaf0 | ||
|
|
08adc52c78 | ||
|
|
95571860d0 | ||
|
|
f35c4048fe | ||
|
|
d76b5a2b44 | ||
|
|
d8c6a03147 | ||
|
|
fc51f45195 | ||
|
|
26c1c2914e | ||
|
|
230d45c9e3 | ||
|
|
f059663164 | ||
|
|
d9e6d47f1b | ||
|
|
b2bd1d90c7 | ||
|
|
863cf8134a | ||
|
|
6c220a45fd | ||
|
|
ada683ed9b | ||
|
|
5efa0d96b8 | ||
|
|
a321f275ef | ||
|
|
7868ad0c71 | ||
|
|
c0e490cc30 | ||
|
|
15b05dce75 | ||
|
|
e4b4d211c1 | ||
|
|
b0130e52d6 | ||
|
|
6d69da6cd1 | ||
|
|
3666e285dc | ||
|
|
ddb3406855 | ||
|
|
11410296a7 | ||
|
|
d636ef78dd | ||
|
|
0d6b32c371 | ||
|
|
66966a242d | ||
|
|
d1bb1b6094 | ||
|
|
28ca666c6e | ||
|
|
f8ad95ee4d | ||
|
|
f6c9450319 | ||
|
|
2127e08052 | ||
|
|
a072a2cf83 | ||
|
|
3a83d99f9a | ||
|
|
1a89112c25 | ||
|
|
10a2bc6319 | ||
|
|
55c158fc34 | ||
|
|
e41cf5236a | ||
|
|
54ddeb6407 | ||
|
|
8167e841ce | ||
|
|
ad7bab8df8 | ||
|
|
805bafacef | ||
|
|
40cd74c506 | ||
|
|
c92df79829 | ||
|
|
62aa414dc0 | ||
|
|
36aff5fca4 | ||
|
|
d9aeffa1d0 | ||
|
|
d0d249c738 | ||
|
|
db546a17b8 | ||
|
|
d35d6142ca | ||
|
|
2d52d8c3c6 | ||
|
|
1ba42ce46f | ||
|
|
1736afae69 | ||
|
|
0f5f96149f | ||
|
|
e084cdaabe | ||
|
|
89e70ea88c | ||
|
|
2544d42ee2 | ||
|
|
0d1d64bbfe | ||
|
|
26099e9536 | ||
|
|
17c6aefdcb | ||
|
|
ab07fec919 | ||
|
|
0e687beed3 | ||
|
|
131e8bbe1f | ||
|
|
0809303feb | ||
|
|
33d00aa714 | ||
|
|
24a12b2e72 | ||
|
|
6062a736d2 | ||
|
|
6cd01df098 | ||
|
|
8a21acc9cc | ||
|
|
8c1cfe3a6e | ||
|
|
8e2c830433 | ||
|
|
868bee0413 | ||
|
|
d6ad749515 | ||
|
|
83bcb7358c | ||
|
|
67d3e4de70 | ||
|
|
8c5590d150 | ||
|
|
cb25a8bd3e | ||
|
|
3c4c0088f0 | ||
|
|
e75b963d3a | ||
|
|
378dfe3162 | ||
|
|
dddf92646d | ||
|
|
791f805fa0 | ||
|
|
5325bfdfd1 | ||
|
|
3d42ebaf73 | ||
|
|
4ab76a5112 | ||
|
|
f4b0e9b6f3 | ||
|
|
6cf03a9e28 | ||
|
|
ded123141c | ||
|
|
8ea3ba3771 | ||
|
|
0e0844b78b | ||
|
|
a1d95afbf7 | ||
|
|
dc8844f112 | ||
|
|
a67a16479c | ||
|
|
24f34d2f55 | ||
|
|
19a8d76e0c | ||
|
|
aa89ef8dad | ||
|
|
ff7a89b781 | ||
|
|
8eb58ad08c | ||
|
|
32f2e53304 | ||
|
|
f79b653523 | ||
|
|
cc6e2dcfcd | ||
|
|
adbe2dabad | ||
|
|
4b7769a67d | ||
|
|
27acbb09a5 | ||
|
|
b142205f1c | ||
|
|
e4858deccd | ||
|
|
3ce8ca13f1 | ||
|
|
ad68e324c6 | ||
|
|
34b55a222e | ||
|
|
bc9441ddd6 | ||
|
|
6e0941a3c4 | ||
|
|
603a64757d | ||
|
|
2002ba27a2 | ||
|
|
01a7da1d95 | ||
|
|
70c09fb5b7 | ||
|
|
29084d4acf | ||
|
|
0d76941600 | ||
|
|
5dc162bc4a | ||
|
|
564b0715f1 | ||
|
|
6e710dcac9 | ||
|
|
b2883167d5 | ||
|
|
1b99ad115a | ||
|
|
9baad78435 | ||
|
|
d2ce7052ec | ||
|
|
d29c63cac9 | ||
|
|
f597e28a87 | ||
|
|
a0eff48f30 | ||
|
|
5310efb16c | ||
|
|
01239ea839 | ||
|
|
b4cbab6774 | ||
|
|
366680af1b | ||
|
|
4de49acb49 | ||
|
|
238f92ab25 | ||
|
|
71b63c29d3 | ||
|
|
e7de4ffe34 | ||
|
|
b581c7f25d | ||
|
|
d10814e808 | ||
|
|
b582869208 | ||
|
|
dd2c6b7f18 | ||
|
|
5b17b8e398 | ||
|
|
d96a54994e | ||
|
|
b80dfdc657 | ||
|
|
d06e88ce39 | ||
|
|
df9fae0c0e | ||
|
|
3fed685e79 | ||
|
|
ef4a506905 | ||
|
|
1a7d30cebf | ||
|
|
ea52c0509a | ||
|
|
01726cddc5 | ||
|
|
cd52b36d38 | ||
|
|
7ab41812ea | ||
|
|
2cab7a9c80 | ||
|
|
3ead19bdea | ||
|
|
03eeca994d | ||
|
|
b596e97926 | ||
|
|
589443a356 | ||
|
|
869a872897 | ||
|
|
48fc14c913 | ||
|
|
37f5d06973 | ||
|
|
f8d3fa0ecd | ||
|
|
f62628bf29 | ||
|
|
8301455a5b | ||
|
|
860d71d18a | ||
|
|
48384d4e47 | ||
|
|
ce177a9588 | ||
|
|
2421b9f6c2 | ||
|
|
eac07b18d9 | ||
|
|
418f3cfd4b | ||
|
|
3f0d6f85d3 | ||
|
|
027a6d9a18 | ||
|
|
58c0dbe275 | ||
|
|
2110196958 | ||
|
|
9195f3c7da | ||
|
|
4f92794cdf | ||
|
|
535561efbf | ||
|
|
5da30a5bc5 | ||
|
|
8fdba437af | ||
|
|
583cc8a963 | ||
|
|
491f06015b | ||
|
|
1aca3bef85 | ||
|
|
b4575a40fc | ||
|
|
8bc521f3e5 | ||
|
|
b1cfc3181b | ||
|
|
1ddf269c69 | ||
|
|
dc910a5317 | ||
|
|
34c8fb057d | ||
|
|
04f9369ace | ||
|
|
b0f69c8b6b | ||
|
|
dc4fd72133 | ||
|
|
20eed53d8c | ||
|
|
e2aaa2cb40 | ||
|
|
4d7899fa40 | ||
|
|
3f975a93b3 | ||
|
|
5f4476566d | ||
|
|
b7206abf11 | ||
|
|
034b17cef4 | ||
|
|
3a1053b29e | ||
|
|
fc3a613276 | ||
|
|
5a96158322 | ||
|
|
3d427bfd77 | ||
|
|
edac98d26e | ||
|
|
83c25d7eb2 | ||
|
|
2ddb2923c6 | ||
|
|
32a59f4279 | ||
|
|
fc6bacdb94 | ||
|
|
680fd91de8 | ||
|
|
288cad1c2e |
No files matched your search
+37
@@ -0,0 +1,37 @@
|
||||
sudo: false
|
||||
|
||||
language: c
|
||||
|
||||
arch:
|
||||
- AMD64
|
||||
- ppc64le
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
addons: &addons
|
||||
apt:
|
||||
packages:
|
||||
- libusb-1.0-0-dev
|
||||
- pkg-config
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
if: (branch = master) AND (type != pull_request)
|
||||
env:
|
||||
- secure: "f+qBVyDcDe/9IUmWcqlhL81s4QdY/eHeJW81Zfkfulu0Iai20Ro/lnj0PxVHeSo12cldUTG0XhY1GURYLe2RNdtB2ooe3d9JGn9uFrkyDNhmHcOuJQKY/g2XQ0gJQ9tpWkZhSzENl2C9H/uz87oGqSqwlCLdwixekk8vrmH5kpnNXtbgfK3EKWbhGN0Zub70+qeLa7jTShMN3HgJbrkDYgxUPMofqOCHp8W1xPIvUjNS4yQtN/Ahl6g7z79xopgCvGI91ZkAigSHJGBeHoq3rxG+ecoK+AprhiXuIZ8tD8bHv5IpKEi6mFGf4Fo0mQw+1b8g0HLBwWoiR5Yz7fv6fRgDhuK2AqZZmK8J6q13Lxl/DZS93hTeSJPk9FBEvJsPRwDUgy0P6HObmmEnmclERd9aqcK4RxrQkTjWK+rhHtoRg1kB2QiLz0dNpXQ/CTImv5jooYibo2TCyH6nBcEKzIxSQABvorEwpn7rx7UqL+rFqCQgLrqcRgCna615XpxpS+/W8VeScp2y1MzClwuudBaOiEAK5b6xa6HWk7RDQPkUAYmsnlFZ3zDbTiMzpKRYp/I2N6CPD50PX8lRJpxDSn6qL0HC0qCaYZqlKA+kKxl+OWbtUWM9mE9MJE3V8RRQO8g5p1mJ8NpjdOx7wwYk09BIp6YYPLXLj32hKn4kfXo="
|
||||
addons:
|
||||
<<: *addons
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "pali/0xFFFF"
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: pali.rohar@gmail.com
|
||||
build_command: make
|
||||
branch_pattern: master
|
||||
|
||||
script:
|
||||
- if [ -n "$COVERITY_SCAN_TOKEN" ]; then exit 0; fi
|
||||
- make
|
||||
@@ -0,0 +1,2 @@
|
||||
Copyright (C) 2007-2010 pancake <pancake@youterm.com>
|
||||
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
@@ -1,9 +1,15 @@
|
||||
Installation instructions:
|
||||
==========================
|
||||
|
||||
To build the flasher you will need gcc, make and libusb. For crosscompiling
|
||||
to arm you can use scratchbox. But you will probably need the libusb.so of
|
||||
the scratchbox environment to the device.
|
||||
To build the flasher you will need gcc, make and libusb-1.0 (version 1.0.16
|
||||
or newer). Compiler and linker flags for libusb-1.0 are detected by pkg-config;
|
||||
without it set LIBUSB_CFLAGS and LIBUSB_LIBS manually (see config.mk), e.g.:
|
||||
|
||||
$ make LIBUSB_CFLAGS=-I/opt/homebrew/opt/libusb/include/libusb-1.0 \
|
||||
LIBUSB_LIBS="-L/opt/homebrew/opt/libusb/lib -lusb-1.0"
|
||||
|
||||
For crosscompiling to arm you can use scratchbox. But you will probably need
|
||||
the libusb-1.0.so of the scratchbox environment to the device.
|
||||
|
||||
Just type:
|
||||
|
||||
@@ -12,11 +18,8 @@ Just type:
|
||||
The most interesting targets for make are:
|
||||
|
||||
all normal build
|
||||
allusb builds 0xFFFF without libusb dependency (embedded)
|
||||
static builds 0xFFFF statically (no need for libusb)
|
||||
|
||||
install installs into /usr/local by default
|
||||
|
||||
uninstall remove installed files
|
||||
clean clean compilation objects and generated binaries
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +1,2 @@
|
||||
PREFIX?=/usr/local
|
||||
|
||||
all: logot
|
||||
cd src && ${MAKE} all
|
||||
|
||||
static: logot
|
||||
cd libusb && ${MAKE} all
|
||||
cd src && ${MAKE} static
|
||||
|
||||
allusb: logot
|
||||
cd libusb && ${MAKE} all
|
||||
cd src && ${MAKE} allusb
|
||||
|
||||
logot:
|
||||
cd logotool && ${MAKE} all
|
||||
|
||||
clean:
|
||||
cd src && ${MAKE} clean
|
||||
cd logotool && ${MAKE} clean
|
||||
|
||||
install:
|
||||
cp src/0xFFFF ${PREFIX}/bin
|
||||
cp logotool/logotool ${PREFIX}/bin
|
||||
|
||||
deinstall:
|
||||
rm -f ${PREFIX}/bin/0xFFFF
|
||||
rm -f ${PREFIX}/bin/logotool
|
||||
all clean install uninstall:
|
||||
$(MAKE) -C src $@
|
||||
@@ -10,25 +10,37 @@
|
||||
_/ ___|_.|__|
|
||||
'`
|
||||
|
||||
The 'Free Fiasco Firmware Flasher' aka 0xFFFF utility implements a free
|
||||
(under the GPLv3 license) userspace handler for the NOLO bootloader and
|
||||
extended features for flashing, dumping and getting information for the
|
||||
Nokia Internet Tablets.
|
||||
0xFFFF is the Open Free Fiasco Firmware Flasher for Maemo devices. It supports
|
||||
generating and unpacking FIASCO images. It is useful for editing Maemo firmware
|
||||
packages before flashing. It supports flashing via USB any image type to a
|
||||
Maemo device and also \"cold\" flashing which means flashing dead device with
|
||||
erased bootloader. There is support for booting kernel via USB without flashing
|
||||
to NAND and also changing configuration of Maemo device (enable/disable R&D
|
||||
mode, changing HW revision strings, ...).
|
||||
|
||||
0xFFFF is an alternative tool to proprietary Nokia flasher-3.5 and fiasco-gen.
|
||||
0xFFFF generates compatible FIASCO images and also accepts FIASCO images
|
||||
generated by Nokia fiasco-gen.
|
||||
|
||||
Use it with CARE. This is an experimental tool and it can brick your device.
|
||||
It's not suposed to be stable, so nokia will probably release incompatible
|
||||
It's not supposed to be stable, so Nokia will probably release incompatible
|
||||
bootloaders to break this tool. USE IT AT YOUR OWN RISK.
|
||||
|
||||
PLEASE. Read carefully all the documentation inside doc/* for more information
|
||||
before building or using the flasher to avoid questions, problems or so.
|
||||
PLEASE. Read all the documentation inside doc/* carefully before building or
|
||||
using the flasher to avoid questions, problems or so.
|
||||
|
||||
Feel free to join to the mailing list and visit the homepage for more info:
|
||||
https://github.com/pali/0xFFFF
|
||||
|
||||
-----------8<---------------------------------------------------------------
|
||||
|
||||
Build:
|
||||
$ make
|
||||
|
||||
To install: (by default is /usr/local)
|
||||
$ make install PREFIX=/usr DESTDIR=/
|
||||
|
||||
0xffff@lists.nopcode.org
|
||||
http://www.nopcode.org/0xFFFF
|
||||
|
||||
|
||||
Have phun!
|
||||
|
||||
|
||||
--pancake
|
||||
--Pali
|
||||
@@ -0,0 +1,24 @@
|
||||
cal:
|
||||
* Write support
|
||||
|
||||
cold-flash:
|
||||
* Detect device from asic id
|
||||
|
||||
disk:
|
||||
* Badblock checking
|
||||
|
||||
fiasco:
|
||||
* Support for Harmattan images
|
||||
|
||||
image:
|
||||
* Support for Harmattan images
|
||||
|
||||
local:
|
||||
* Write versions
|
||||
* Badblock checking
|
||||
|
||||
mkii:
|
||||
* Support for flashing
|
||||
|
||||
nolo:
|
||||
* Implement functions for setting nolo, kernel, initfs and content versions (it is possible?)
|
||||
@@ -0,0 +1,11 @@
|
||||
VERSION = 0.10
|
||||
PREFIX = /usr/local
|
||||
|
||||
# NetBSD stuff
|
||||
#CPPFLAGS += -I/usr/pkg/include
|
||||
#LDFLAGS += -L/usr/pkg/lib -Wl,-R/usr/pkg/lib
|
||||
|
||||
# libusb-1.0 flags are detected by pkg-config, set them manually without it
|
||||
# (e.g. macOS with Homebrew libusb on Apple Silicon)
|
||||
#LIBUSB_CFLAGS = -I/opt/homebrew/opt/libusb/include/libusb-1.0
|
||||
#LIBUSB_LIBS = -L/opt/homebrew/opt/libusb/lib -lusb-1.0
|
||||
@@ -1,60 +0,0 @@
|
||||
Bug#: 1584
|
||||
Opened: 2007-06-25 23:06 GMT+3
|
||||
Reporter: Robert Schuster <thebohemian [at] gmx.net>
|
||||
Summary: provide system management software under free software licenses
|
||||
|
||||
Several applications and libraries found on the N800 internet tablet/IT OS
|
||||
2007.10 are distributed under restricted and non-free license terms according
|
||||
to the Debian Free Software Guidelines, Open Source Definition and Free
|
||||
Software definition.
|
||||
|
||||
I hereby politely ask for distributing those components under terms that are
|
||||
acceptable to the above mentioned guidelines.
|
||||
|
||||
The applications of interest are:
|
||||
from the initfs: activate_panel, bt-cal, cal-tool, fb-chaimage, text2screen,
|
||||
wlan-cal, wlan-fw-update, retu-time, show_image, dsme, battest, bootstate,
|
||||
dsmetool, dspctl, waitfordsme and the script linuxrc
|
||||
|
||||
the libraries of interest are:
|
||||
libbmeic.so, libcal.so, libdsme.so, libppu.so, libactivitymonitor.so,
|
||||
libcalmodule.so, libhwwd.so, libinactivity-blank.so, liblifeguard.so,
|
||||
libperipheral.so, libprocesswd.so, libstartup.so, libstate.so,
|
||||
libtemperature.so
|
||||
|
||||
There may be other software artifacts which are of interest for which I will
|
||||
file separate bugreports if there is a need for them.
|
||||
|
||||
Rationale:
|
||||
When Nokia/Maemo decided to use a variant of the GNU operating system and Linux
|
||||
as its kernel for implementing the Internet Tablet OS they profited from a
|
||||
wealth of knowledge and work invested in various software projects. With the
|
||||
help of free software licensing they were allowed to create a unique software
|
||||
environment which exactly implements the Maemo projects' goals. Maemo has
|
||||
gained and still gains from those software projects because they are
|
||||
independently developed further giving Maemo more possibilities in the future.
|
||||
|
||||
One of the key goals of the GNU project is to give its user's the freedom to
|
||||
implement their own ideas. This goal is to be reached by writing free software
|
||||
and sometimes (in the early days often) replacing proprietary software.
|
||||
|
||||
The non-free bits in the core infrastructure of the IT OS 2007 are a road block
|
||||
for efforts to create free operating systems/distributions besides IT OS on the
|
||||
N770/N800.
|
||||
|
||||
The reason for why it is helpful to have other operating system/distribution on
|
||||
the N800 is simple: There are hundreds of GNU/Linux distributions out there.
|
||||
Each one exists because there is a userbase that exactly likes their flavor of
|
||||
GNU/Linux.
|
||||
|
||||
For the N770/N800 Internet Tablets there exists only one such distribution: The
|
||||
Internet Tablet OS. With the sheer amount of GNU/Linux distributions for
|
||||
desktops/workstations/servers/routers/PDAs on the one hand and the single OS
|
||||
solution for the Internet Tablets on the other I doubt that it can handle all
|
||||
the possible uses people have.
|
||||
|
||||
By releasing the above mentioned programs/libraries under free software
|
||||
licenses people will be given the same possibilities the Maemo project had in
|
||||
the first place.
|
||||
|
||||
Let us be free.
|
||||
+21
-9
@@ -1,18 +1,16 @@
|
||||
<b>Dumping the firmware</b>
|
||||
Dumping the firmware:
|
||||
|
||||
This technique consists on reconstructing a firmware image dumping
|
||||
pieces at certains offsets of the device internal memory.
|
||||
pieces at certain offsets of the device internal memory.
|
||||
|
||||
<b></b>
|
||||
|
||||
<b>Technical details:</b>
|
||||
Technical details:
|
||||
|
||||
* The internal flash memory is exposed to the system as MTD devices.
|
||||
* Is possible to dump the individual sections of a flashed firmware.
|
||||
*
|
||||
* READ src/dump.c for detailed information.
|
||||
* READ src/local.c for detailed information.
|
||||
|
||||
mtd0 - contains xloader and sencodary pieces of the bootloaders
|
||||
mtd0 - contains xloader and secondary pieces of the bootloaders
|
||||
0x00000 - xloader.bin (size is 0x03600)
|
||||
0x04000 - secondary.bin (size is 0x15400)
|
||||
0x1FFFF - eof
|
||||
@@ -22,13 +20,27 @@ pieces at certains offsets of the device internal memory.
|
||||
mtd2 - starts with NOLO img\x5c\x13 and \x00 padding
|
||||
0x00800 - zImage
|
||||
|
||||
> NOLO is a four byte marker, next four bytes
|
||||
> can vary since it is kernel image size
|
||||
> NOLO is a four byte marker, next four bytes
|
||||
> can vary since it is kernel image size
|
||||
|
||||
mtd3 - initfs.jffs2 (2M) aka 0x200000 vs 0x3900000
|
||||
|
||||
mtd4 - rootfs.jffs2 (a fucking copy of the above rootfs?)
|
||||
|
||||
For dumping mtd partition is used tool nanddump. Here is example how to dump
|
||||
kernel image without padding to file zImage:
|
||||
|
||||
$ nanddump --omitoob -s 0x00000800 -l 0x001FF800 -f zImage /dev/mtd2
|
||||
|
||||
Params means:
|
||||
--omitoob - "Omit oob data"
|
||||
-s - "Start address"
|
||||
-l - "Length"
|
||||
-f - "Output file"
|
||||
|
||||
Please note that some new versions of nanddump have some options removed and
|
||||
some are enabled by default. Before using check params of your nanddump version.
|
||||
|
||||
|
||||
// Extra notes //
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
Via USB:
|
||||
|
||||
Identify device:
|
||||
$ 0xFFFF -I
|
||||
|
||||
Load kernel & initfs and boot it with cmdline:
|
||||
$ 0xFFFF -m initfs:<file> -m kernel:<file> -l -b "<cmdline>"
|
||||
|
||||
Flash kernel and reboot:
|
||||
$ 0xFFFF -m kernel:<file> -f -r
|
||||
|
||||
Flash FIASCO image and reboot:
|
||||
$ 0xFFFF -M <file> -f -r
|
||||
|
||||
Flash only kernel from FIASCO image and reboot:
|
||||
$ 0xFFFF -M <file> -t kernel -f -r
|
||||
|
||||
Cold-Flash 2nd and secondary bootloaders:
|
||||
$ 0xFFFF -m 2nd:<file> -m secondary:<file> -c
|
||||
|
||||
|
||||
On device (need nanddump from mtd-utils):
|
||||
|
||||
Dump all images to current directory:
|
||||
$ 0xFFFF -e
|
||||
|
||||
Dump all images to one FIASCO file:
|
||||
$ 0xFFFF -E <file>
|
||||
|
||||
|
||||
FIASCO packaging:
|
||||
|
||||
Show FIASCO image content:
|
||||
$ 0xFFFF -M <file> -i
|
||||
|
||||
Unpack FIASCO image to current directory:
|
||||
$ 0xFFFF -M <file> -u
|
||||
|
||||
Generate new FIASCO image image.fiasco from files xloader.bin, nolo.bin, zImage, rootfs and append device&version information (xloader for RX-51 hw revision: 2101 and 2102, version 1.0)
|
||||
$ 0xFFFF -m RX-51:2101,2102:1.0:xloader:xloader.bin -m RX-51:2101,2102:1.0:secondary:nolo.bin -m 2.6.28:kernel:zImage -m rootfs -g image.fiasco
|
||||
|
||||
Generate new FIASCO mmc image mmc_image.fiasco from layout file layout.txt and two partition files mydocs_fat32.bin (with name mydocs) and home.tar (without name) for device RX-51 with image version 1.0
|
||||
$ 0xFFFF -m RX-51:1.0:mmc:mydocs_fat32.bin@mydocs#home.tar%layout.txt -g mmc_image.fiasco
|
||||
@@ -1,79 +1,35 @@
|
||||
<b>FAQ</b>
|
||||
FAQ:
|
||||
|
||||
This file tries to collect a bunch of common questions/answers about flashing
|
||||
*) How can I set my Internet Tablet into RD mode with 0xFFFF?
|
||||
|
||||
<b>*) Why implement a free software flasher?</b>
|
||||
|
||||
The Nokia Internet Tablets are based on Free Software (software libre), but
|
||||
not everything included *is* free software, for instance, the firmware flasher
|
||||
tool.
|
||||
|
||||
The 0xFFFF project aims to feed the minds of those who really want to
|
||||
understand how these gadgets work internally, free the knowledge to
|
||||
avoid the restrictions and fill the lack of information on the most
|
||||
important part of the system.
|
||||
|
||||
That's it, now you can build and run this flasher on *BSD, w32, MacOSX on ARM,
|
||||
powerpc, x86, mips, etc...
|
||||
Just type '0xFFFF -R 1' as root
|
||||
|
||||
|
||||
<b>*) Can I brick my device?</b>
|
||||
*) How can I unpack a FIASCO firmware?
|
||||
|
||||
Of course! You're free to do what you want with your device :)
|
||||
|
||||
Seriously. Flashing a device is not a safe thing, so I give no warranty
|
||||
of what will happen to your device when using this tool.
|
||||
|
||||
BTW, after a huge number of tests I can say that these devices are hard
|
||||
to brick, but if you are scared about bricking your device you should
|
||||
use the flasher provided by Nokia, it's better for your heart's health.
|
||||
Just type '0xFFFF -M FiascoFirmware.bin -u'
|
||||
|
||||
|
||||
<b>*) What can I do with 0xFFFF?</b>
|
||||
*) How can I flash a new rootfs?
|
||||
|
||||
Actually 0xFFFF allows you to:
|
||||
|
||||
- flash separated pieces of the firmware.
|
||||
- retrieve information about the device
|
||||
- reboot de mother board
|
||||
- extract the current firmware pieces from the device (reverse flash)
|
||||
- set the USB host/slave mode
|
||||
- set the R&R mode
|
||||
- identify firmware pieces
|
||||
# 0xFFFF -m rootfs.jffs2 -f
|
||||
|
||||
|
||||
<b>*) What is NOLO?</b>
|
||||
*) How can I flash a full FIASCO image?
|
||||
|
||||
NOLO is the 'server-side' part of the flasher from Nokia. NOLO means
|
||||
NOkia LOader and it's composed by two pieces of the firmware that are
|
||||
flashed together.
|
||||
|
||||
On the n800 firmwares, these two pieces are distributed in a single
|
||||
file, but when flashing a n770, NOLO requires to provide the xloader
|
||||
(without commiting) and then the secondary piece.
|
||||
|
||||
This piece of software is closed source and is the responsable of
|
||||
handling the requests from the client-side flasher. It provides a
|
||||
query-like interface via usb control messages for doing different
|
||||
actions on the device.
|
||||
# 0xFFFF -M FiascoFirmware.fiasco -f
|
||||
|
||||
|
||||
<b>*) How can I identify my device?</b>
|
||||
Advanced commands:
|
||||
|
||||
Theorically n770 and n800 have different USB device ID, but this is not
|
||||
true at all. The first series of the n800 comes with the same usb-id
|
||||
than n770. That's weird!
|
||||
*) How to extract the firmware pieces from a running device?
|
||||
|
||||
So, the only way to identify the device is by asking nolo for the version
|
||||
information of different pieces of the firmware. This can be faked, because
|
||||
you can flash n770 stuff on n800 and viceversa, but it's not recommended
|
||||
because it wouldn't work :)
|
||||
It is possible to dump the firmware pieces from the internal MTD to reconstruct a FIASCO image.
|
||||
To do this recompile the flasher for ARM and run this command in the device:
|
||||
|
||||
# mkdir /media/mmc1/backup
|
||||
# 0xFFFF -e /media/mmc1/backup
|
||||
|
||||
<b>*) Can I unpack fiasco blobs?</b>
|
||||
To dump directly into FIASCO image run:
|
||||
|
||||
Actually the fiasco format is not yet supported and not planned in
|
||||
short term. There is no real need for supporting a proprietary
|
||||
format image containing a proprietary system.
|
||||
|
||||
We can just use tarballs containing the desired pieces.
|
||||
# 0xFFFF -E /media/mmc1/backup.fiasco
|
||||
@@ -0,0 +1,80 @@
|
||||
FAQ2:
|
||||
|
||||
This file tries to collect a bunch of common questions/answers about flashing
|
||||
|
||||
|
||||
*) Why implement a free software flasher?
|
||||
|
||||
The Nokia Internet Tablets are based on Free Software (software libre), but
|
||||
not everything included *is* free software, for instance, the firmware flasher
|
||||
tool.
|
||||
|
||||
The 0xFFFF project aims to feed the minds of those who really want to
|
||||
understand how these gadgets work internally, free the knowledge to
|
||||
avoid the restrictions and fill the lack of information on the most
|
||||
important part of the system.
|
||||
|
||||
That's it, now you can build and run this flasher on *BSD, w32, MacOSX on ARM,
|
||||
powerpc, x86, mips, etc...
|
||||
|
||||
|
||||
*) Can I brick my device?
|
||||
|
||||
Of course! You're free to do what you want with your device :)
|
||||
|
||||
Seriously. Flashing a device is not a safe thing, so I give no warranty
|
||||
of what will happen to your device when using this tool.
|
||||
|
||||
BTW, after a huge number of tests I can say that these devices are hard
|
||||
to brick, but if you are scared about bricking your device you should
|
||||
use the flasher provided by Nokia, it's better for your heart's health.
|
||||
|
||||
|
||||
*) What can I do with 0xFFFF?
|
||||
|
||||
Actually 0xFFFF allows you to:
|
||||
|
||||
- flash separated pieces of the firmware
|
||||
- flash full FIASCO image
|
||||
- load kernel & initfs without flashing
|
||||
- cold-flash bricked device (without NOLO)
|
||||
- retrieve information about the device
|
||||
- reboot de mother board
|
||||
- extract the current firmware pieces from the device (dump)
|
||||
- set the USB host/slave mode
|
||||
- set the R&R mode and flags
|
||||
- pack/unpack FIASCO firmwares
|
||||
- automatic piece identifier
|
||||
|
||||
|
||||
*) What is NOLO?
|
||||
|
||||
NOLO is the 'server-side' part of the flasher from Nokia. NOLO means
|
||||
NOkia LOader and it's composed by two pieces of the firmware that are
|
||||
flashed together.
|
||||
|
||||
On the n800 firmwares, these two pieces are distributed in a single
|
||||
file, but when flashing a 770, NOLO requires to provide the xloader
|
||||
(without committing) and then the secondary piece.
|
||||
|
||||
This piece of software is closed source and is the responsible of
|
||||
handling the requests from the client-side flasher. It provides a
|
||||
query-like interface via usb control messages for doing different
|
||||
actions on the device.
|
||||
|
||||
|
||||
*) How can I identify my device?
|
||||
|
||||
Theoretically 770 and n800 have different USB device ID, but this is not
|
||||
true at all. The first series of the n800 comes with the same usb-id
|
||||
than 770. That's weird!
|
||||
|
||||
So, the only way to identify the device is by asking nolo for the version
|
||||
information of different pieces of the firmware. This can be faked, because
|
||||
you can flash 770 stuff on n800 and viceversa, but it's not recommended
|
||||
because it wouldn't work :)
|
||||
|
||||
|
||||
*) Can I unpack FIASCO blobs?
|
||||
|
||||
Yes, last version of 0xFFFF has full support of FIASCO images.
|
||||
+98
-17
@@ -1,30 +1,111 @@
|
||||
SPECS FOR TEH FIASCO FIRMWARE FILE FORMAT ffff!
|
||||
Copyright (C) 2007-2011 pancake <pancake@youterm.com>
|
||||
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
SPECS FOR THE FIASCO FIRMWARE FILE FORMAT ffff!
|
||||
-----------------------------------------------
|
||||
|
||||
These notes has not been taken properly and may be wrong. It must
|
||||
be revised to fit the reality. But this is mostly a general idea:
|
||||
This is final working version of FIASCO format. FIASCO image which
|
||||
is generated by this spec is acceptable by Nokia flasher-3.5 and
|
||||
unpack data same as FIASCO image generated by Nokia fiasco-gen. This
|
||||
format is implemented in 0xFFFF and every image which I tested
|
||||
(generated by 0xFFFF and fiasco-gen) was properly unpacked under
|
||||
0xFFFF and flasher-3.5 with same result. Small difference is that
|
||||
fiasco-gen add some unknown subsection block to image header
|
||||
(type '4' or '/') which contains some messy characters... But if
|
||||
these sections missing, flasher-3.5 working fine too. And old FIASCO
|
||||
images (for N8x0) does not have these subsection...
|
||||
|
||||
|
||||
FILE HEADER
|
||||
|
||||
1 byte = 0xb4 -- signature
|
||||
4 bytes -- firmware name length (big endian)
|
||||
6 bytes -- versioning info ( byte 4 is format version )
|
||||
N-6 bytes -- firmware name (zero fill)
|
||||
4 bytes -- FW header length (big endian)
|
||||
|
||||
|
||||
PIECE HEADER
|
||||
FW HEADER
|
||||
|
||||
1 byte = 0x54 -- piece signature
|
||||
6 bytes -- unknown
|
||||
2 bytes -- checksum for the piece contents (xorpair)
|
||||
12 bytes -- piece name (first byte is FF if is the last)
|
||||
4 bytes -- piece size (big endian)
|
||||
4 bytes -- unknown
|
||||
4 bytes -- number of FW header blocks (big endian)
|
||||
block {
|
||||
1 byte -- if (value '1'-'9') { ..there's a comment.. }
|
||||
1 byte -- length of comment
|
||||
N bytes -- comment
|
||||
1 byte -- type of block
|
||||
0xE8 - Fiasco name
|
||||
0x31 - FW name
|
||||
1 byte -- length of block data
|
||||
N bytes -- block data
|
||||
}
|
||||
N bytes -- piece data
|
||||
|
||||
|
||||
IMAGE
|
||||
|
||||
1 byte = 0x54 -- signature
|
||||
1 byte -- number of subsection blocks
|
||||
block {
|
||||
1 byte -- type of subsection block
|
||||
0x2E - file data
|
||||
0x2F - partition info
|
||||
0x31 - version
|
||||
0x32 - device & hw revisions (size of device is 16, hw revision 8)
|
||||
0x33 - layout
|
||||
0x34 - image data part block (one block for one data part)
|
||||
1 byte -- length of subsection block
|
||||
N bytes -- subsection block data
|
||||
}
|
||||
1 byte -- checksum of subsection data without signature (0xFF - xorpair)
|
||||
N bytes -- image data
|
||||
|
||||
|
||||
FILE DATA BLOCK
|
||||
|
||||
1 byte -- asic index (always APE - 0x01)
|
||||
1 byte -- device type (always NAND - 0x01)
|
||||
1 byte -- device index (always 0x00)
|
||||
2 bytes -- checksum for the image contents (xorpair) (big endian)
|
||||
12 bytes -- image name type (first byte is FF if is the last image)
|
||||
4 bytes -- length of image data (big endian)
|
||||
4 bytes -- load address of image data (big endian, unused always zero)
|
||||
|
||||
|
||||
PARTITION INFO BLOCK
|
||||
|
||||
1 byte -- asic index (always APE - 0x01)
|
||||
1 byte -- device type (always NAND - 0x01)
|
||||
1 byte -- device index (always 0x00)
|
||||
4 bytes -- partition version (always 0x00 0x00 0x00 0x00)
|
||||
4 bytes -- spare (always 0xFF 0xFF 0xFF 0xFF)
|
||||
4 bytes -- number of partition blocks (big endian)
|
||||
block {
|
||||
1 byte -- partition type (0x03 - kernel, 0x04 - initfs, 0x05 - rootfs)
|
||||
1 byte -- partition attribute (0x01 - read/write, 0x02 - read-only)
|
||||
4 bytes -- partition size (big endian, 0 - remaining space)
|
||||
}
|
||||
|
||||
|
||||
IMAGE DATA PART BLOCK
|
||||
|
||||
4 bytes -- unknown (always 0x00 0x00 0x00 0x00)
|
||||
4 bytes -- offset (big endian)
|
||||
4 bytes -- unknown (always 0x00 0x00 0x00 0x00)
|
||||
4 bytes -- size (big endian)
|
||||
N bytes -- partition name (prefix) in layout (may be omitted)
|
||||
|
||||
|
||||
LAYOUT DATA BLOCK
|
||||
|
||||
N bytes of text data, e.g.:
|
||||
|
||||
mmc {
|
||||
name = "internal";
|
||||
partition {
|
||||
fs_type = "vfat";
|
||||
prefix = "mydocs";
|
||||
no_create = true;
|
||||
}
|
||||
partition {
|
||||
size = 2048;
|
||||
fs_type = "ext3";
|
||||
prefix = "home";
|
||||
}
|
||||
partition {
|
||||
size = 768;
|
||||
fs_type = "swap";
|
||||
}
|
||||
}
|
||||
+14
-2
@@ -9,7 +9,7 @@ The way to flash is using mtd-utils:
|
||||
|
||||
This is an specific example plagied from initfs_flasher of bootmenu.
|
||||
|
||||
The '-j' flag says that this is a jffs2 partition. Theorically this
|
||||
The '-j' flag says that this is a jffs2 partition. Theoretically this
|
||||
flag is not required for zImage, and the bootloader pieces.
|
||||
|
||||
The '-a' creates the OOB data automatically, and the '-p' flag pads
|
||||
@@ -21,4 +21,16 @@ have flashed properly every piece inside the device, but keep in mind
|
||||
that it is dangerous and you can brick your device.
|
||||
|
||||
But feel free to send feedback to provide a full support for local
|
||||
flashing on n770 and n800.
|
||||
flashing on 770 and n800.
|
||||
|
||||
|
||||
Nokia N900 using ubi layout on top of /dev/mtd5 rootfs partition. Therefor
|
||||
formatting rootfs should be done via ubiformat tool which preserve erase counters.
|
||||
|
||||
Erasing N900 rootfs:
|
||||
|
||||
$ ubiformat /dev/mtd5
|
||||
|
||||
Flashing new ubi image to N900 rootfs:
|
||||
|
||||
$ ubiformat /dev/mtd5 -s 512 -O 512 -f image.ubi
|
||||
@@ -0,0 +1,156 @@
|
||||
Copyright (C) 2012-2014 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
Mk II protocol is the only protocol which can be used to flash eMMC images.
|
||||
NOLO does not support eMMC, so flashing eMMC is done in Maemo system. NOLO
|
||||
will boot device into "update" mode and Maemo will start only softupd daemon
|
||||
(which is responsible for flashing from Maemo system) and load kernel driver
|
||||
g_softupd which handle USB communication to user space daemon. When device
|
||||
is in PC Suite mode Maemo system start softupd daemon and load kernel driver
|
||||
g_nokia which can also handle communication via Mk II protocol.
|
||||
|
||||
Default Maemo flasher (v2.5.2 (Oct 21 2009)) support only some basic functions
|
||||
via Mk II protocol - it can send eMMC image to softupd server which flash it.
|
||||
But there is unofficial Maemo flasher (flasher v2.8.2 (Jan 8 2010)) distributed
|
||||
with omap aes kernel driver for Nokia RX-51 under name "flasher.rover" which
|
||||
support more functions. So "flasher.rover" is better for RE this protocol.
|
||||
|
||||
Via Mk II protocol over usb with softupd daemon in device it is possible to
|
||||
flash any type of image except rootfs (xloader, secondary, kernel, mmc,
|
||||
cmt-2nd, cmt-algo, cmt-mcusw). Maemo system using same Mk II protocol over
|
||||
local TCP socket (server also provided by softupd) to update/flash system.
|
||||
|
||||
Over usb are used only these functions for communication:
|
||||
|
||||
usb_claim_interface (interface=1)
|
||||
usb_set_altinterface (alternate=1)
|
||||
|
||||
usb_bulk_write (ep=1, timeout=5000)
|
||||
usb_bulk_read (ep=129, timeout=5000)
|
||||
|
||||
And this function for sending raw data:
|
||||
|
||||
usb_bulk_write (ep=2, timeout=1000)
|
||||
|
||||
For every (request) message which is send by host, server send back response.
|
||||
Format of message every message is same. It has 6 bytes header and (at least)
|
||||
4 bytes body.
|
||||
|
||||
HEADER
|
||||
|
||||
4 bytes -- type of header
|
||||
0x8810001B - out (sent by host: usb_bulk_write)
|
||||
0x8800101B - in (received by host: usb_bulk_read)
|
||||
2 bytes -- size of body (big endian)
|
||||
|
||||
BODY
|
||||
|
||||
2 bytes -- unknown (always zero)
|
||||
1 byte -- or. num of message (starting with zero)
|
||||
1 byte -- type of message
|
||||
N bytes -- data
|
||||
|
||||
Reply message data always starts with char 0x00 (except pong response).
|
||||
|
||||
Message types:
|
||||
|
||||
0x00 - PING
|
||||
0x01 - GET
|
||||
0x02 - TELL
|
||||
0x0C - REBOOT
|
||||
|
||||
0x20 - RESPONCE
|
||||
|
||||
Here are some sniffed messages from Nokia RX-51. First two messages seems to
|
||||
must be always protocol version exchange (first host ask for protocol version of
|
||||
server and then host send its protocol version). On RX-51 is used version "2".
|
||||
|
||||
Ping:
|
||||
req_type = 0x00
|
||||
res_type = 0x20
|
||||
|
||||
Get protocol version:
|
||||
req_type = 0x01
|
||||
req_data = "/update/protocol_version"
|
||||
res_type = 0x21
|
||||
res_data = 0x00 "2"
|
||||
|
||||
Tell our protocol version:
|
||||
req_type = 0x02
|
||||
req_data = "/update/host_protocol_version" 0x00 "2"
|
||||
res_type = 0x22
|
||||
res_data = 0x00
|
||||
|
||||
Get device:
|
||||
req_type = 0x01
|
||||
req_data = "/device/product_code"
|
||||
res_type = 0x21
|
||||
res_data = 0x00 "RX-51"
|
||||
|
||||
Get hwrev:
|
||||
req_type = 0x01
|
||||
req_data = "/device/hw_build"
|
||||
res_type = 0x21
|
||||
res_data = 0x00 "2101"
|
||||
|
||||
Get image types:
|
||||
req_type = 0x01
|
||||
req_data = "/update/supported_images"
|
||||
res_type = 0x21
|
||||
res_data = 0x00 "xloader,secondary,kernel,mmc,cmt-2nd,cmt-algo,cmt-mcusw"
|
||||
|
||||
Reboot device:
|
||||
req_type = 0x0C
|
||||
req_data = "reboot" 0x00
|
||||
res_type = 0x2C
|
||||
res_data = 0x00
|
||||
|
||||
Send image (mmc):
|
||||
req_type = 0x03
|
||||
res_type = 0x23
|
||||
res_data = 0x00
|
||||
|
||||
req_type = 0x04
|
||||
req_data = fiasco subimage header
|
||||
res_type = 0x24
|
||||
res_data = 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00
|
||||
|
||||
req_type = 0x05
|
||||
req_data = 0x00 0x00 0x00 0x00 "usb:raw"
|
||||
res_type = 0x25
|
||||
res_data = 0x00
|
||||
|
||||
req_type = 0x06
|
||||
req_data = 0x00 0x00 0x00 0x00
|
||||
res_type = 0x26
|
||||
res_data = 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
|
||||
req_type = 0x0B
|
||||
req_data = 0x00 0x00 0x00 0x64
|
||||
res_type = 0x2B
|
||||
res_data = 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x00
|
||||
|
||||
req_type = 0x08
|
||||
req_data = 0x00 0x00 0x00 0x00 0x00 0x10 0x00 0x00
|
||||
res_type = 0x28
|
||||
res_data = 0x00
|
||||
|
||||
(raw data on ep=2 size=1048576)
|
||||
|
||||
req_type = 0x06
|
||||
req_data = 0x00 0x00 0x00 0x00
|
||||
res_type = 0x26
|
||||
res_data = 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0F 0x9F 0x2C 0x00 0x00
|
||||
|
||||
req_type = 0x0B
|
||||
req_data = 0x00 0x00 0x00 0x64
|
||||
res_type = 0x2B
|
||||
res_data = 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x01 0xF0 0x00 0x00 0x00
|
||||
|
||||
req_type = 0x08
|
||||
req_data = 0x00 0x00 0x00 0x00 0x00 0x10 0x00 0x00
|
||||
res_type = 0x28
|
||||
res_data = 0x00
|
||||
|
||||
(raw data on ep=2 size=1048576)
|
||||
|
||||
...
|
||||
+12
-19
@@ -1,4 +1,4 @@
|
||||
<b>Nokia tips</b>
|
||||
Nokia tips:
|
||||
|
||||
When developing this tool I've found some bugs and misfeatures that
|
||||
should be fixed to make flashing safer and cleaner.
|
||||
@@ -9,7 +9,7 @@ it's really hard to break the device and it works pretty nice. BTW I
|
||||
think that there are some things that should be fixed.
|
||||
|
||||
|
||||
<b>*) Flashing at low battery level</b>
|
||||
*) Flashing at low battery level
|
||||
|
||||
When the device is under a certain limit of battery it will not start,
|
||||
this is done by initfs, without any warning message or so, this really
|
||||
@@ -20,7 +20,7 @@ think that there are some things that should be fixed.
|
||||
This is *really* dangerous and not very user friendly.
|
||||
|
||||
|
||||
<b>*) Internal nolo state not reset'd</b>
|
||||
*) Internal nolo state not reset'd
|
||||
|
||||
It's possible to get nolo on a strange state that always returns error
|
||||
when flashing pieces, it's mandatory to reboot the device to recover
|
||||
@@ -29,7 +29,7 @@ think that there are some things that should be fixed.
|
||||
This is an strange and not very clear to me.
|
||||
|
||||
|
||||
<b>*) Buffer overflows</b>
|
||||
*) Buffer overflows
|
||||
|
||||
The original nokia flasher has some buffer overflow bugs that should
|
||||
be fixed. They're safe for 99.9% of cases, but bofs on critical programs
|
||||
@@ -40,31 +40,24 @@ think that there are some things that should be fixed.
|
||||
than this one.
|
||||
|
||||
|
||||
<b>*) Missing stuff</b>
|
||||
|
||||
There are some flashing options that are not working like passing arguments
|
||||
to the kernel, set the hw revision or do a cold flash (the most critical
|
||||
part is undocumented).
|
||||
|
||||
|
||||
<b>*) Weird firmware format</b>
|
||||
*) Weird firmware format
|
||||
|
||||
The (new and old) FIASCO firmware format is not a very clean format, it
|
||||
doesn't provide any checksumming facility to ensure that the contents of
|
||||
the firmware have been modified or incorrect, so i'll rather encourage
|
||||
the firmware have been modified or incorrect, so I'll rather encourage
|
||||
to design and create a standard firmware format for embedded devices with
|
||||
checksumming, signatures, handling libraries, documentation and so.
|
||||
|
||||
I'll happilly collaborate on the design of this open firmware format, and
|
||||
I'll happily collaborate on the design of this open firmware format, and
|
||||
it would be used on all the open source-based devices to aim interoperability
|
||||
between devices and flashers, providing a more standard and reliable way of
|
||||
flashing devices.
|
||||
|
||||
This will ease the development on new devices, so the information and the
|
||||
code could be revised and enhaced by zillions of eyes.
|
||||
code could be revised and enhanced by zillions of eyes.
|
||||
|
||||
|
||||
<b>*) Poor checksumming</b>
|
||||
*) Poor checksumming
|
||||
|
||||
The only checksum is a 16 bit xor of the whole firmware piece and it's only
|
||||
checked after sending the piece to the device.
|
||||
@@ -73,7 +66,7 @@ think that there are some things that should be fixed.
|
||||
algorithm. It currently performs a unique check at the end, it could be
|
||||
better to check each data block to avoid errors or invalid flashing, isn't it ?
|
||||
|
||||
<b>*) No validation of pieces before flashing</b>
|
||||
*) No validation of pieces before flashing
|
||||
|
||||
I've implemented a minimal check of the pieces to avoid flashing invalid
|
||||
pieces on the wrong place. This is done in fpid.c (firmware piece identifier).
|
||||
@@ -82,7 +75,7 @@ think that there are some things that should be fixed.
|
||||
that can (pseudo)brick the device.
|
||||
|
||||
|
||||
<b>*) Reverse flashing</b>
|
||||
*) Reverse flashing
|
||||
|
||||
If you want to test a new firmware, but you don't want to loose all the
|
||||
contents of your device. The only way to do that (afaik) is from the
|
||||
@@ -94,7 +87,7 @@ think that there are some things that should be fixed.
|
||||
case of a wrong checksumming (for example)
|
||||
|
||||
|
||||
<b>*) Documentation</b>
|
||||
*) Documentation
|
||||
|
||||
The nokia flasher comes as is, without documentation. This is not good
|
||||
to anybody, because the lack of information is always the root of problems,
|
||||
|
||||
+6
-12
@@ -8,7 +8,7 @@ defined by NOLO on the internal flash memory.
|
||||
Nokia provides a blob packed with a proprietary format called 'FIASCO'. This
|
||||
blob contains the following pieces:
|
||||
|
||||
- omap-nand - only flashable via serial jtag
|
||||
- 2nd - for Cold Flashing
|
||||
- xloader - first part of nolo
|
||||
- secondary - second part of nolo (usb support and launches kernel)
|
||||
- kernel - the kernel
|
||||
@@ -18,26 +18,20 @@ blob contains the following pieces:
|
||||
Some of these pieces are versioned to match board specific features
|
||||
(mostly xloader and secondary ones).
|
||||
|
||||
This format is not supported by 0xFFFF at this moment, but there are no
|
||||
plans for doing it in short term. This is because we only need to flash
|
||||
separated pieces. We can just distribute tarballs containing the pieces
|
||||
and meta information with a whole Free OS for the internet tablets.
|
||||
|
||||
To flash an initfs partition and reboot:
|
||||
|
||||
$ 0xFFFF -p initfs%initfs.jffs2 -R
|
||||
$ 0xFFFF -m initfs:initfs.jffs2 -f -r
|
||||
|
||||
The format of the argument is [piece-type] % [file-name] (% [version-string]).
|
||||
The format of the argument is [[[device:[hw-revision:]]verion:]piece-type:]file-name[%layout-file-name]
|
||||
|
||||
Pieces can be automatically identified by using the '-I' flag:
|
||||
Pieces can be automatically identified by using the '-i' flag:
|
||||
|
||||
$ 0xFFFF -I initfs.jffs2
|
||||
initfs.jffs2: initfs
|
||||
$ 0xFFFF -m initfs.jffs2 -i
|
||||
|
||||
You can dump these pieces from the internal memory of the internet
|
||||
tablet by using the mtd-utils over /dev/mtd* or just running:
|
||||
|
||||
n770$ 0xFFFF -e /media/mmc1
|
||||
770$ 0xFFFF -e /media/mmc1
|
||||
|
||||
There is another way for dumping pieces with extra parameters and options,
|
||||
read doc/dumping for more information.
|
||||
@@ -1,68 +0,0 @@
|
||||
<b>Usage guide</b>
|
||||
|
||||
0xFFFF is a free software implementation of the flasher for the Nokia Internet
|
||||
Tablets (n770 and n800).
|
||||
<pre>
|
||||
- flash separated pieces of the firmware.
|
||||
- retrieve information about the device
|
||||
- reboot de mother board
|
||||
- extract the current firmware pieces from the device (dump)
|
||||
- set the USB host/slave mode
|
||||
- pack/unpack fiasco firmwares
|
||||
- fine grained R&D flags support
|
||||
- identify firmware pieces
|
||||
- dump mtd partitions (embedded mtd-utils source code)
|
||||
- reconstruct initfs from a dump
|
||||
- dump config partition
|
||||
- automatic piece identifier
|
||||
- console mode (shell like)
|
||||
</pre>
|
||||
This is the help message of the tool:
|
||||
<pre>
|
||||
<b>~$ 0xFFFF -h</b>
|
||||
0xFFFF v0.3 // The Free Fiasco Firmware Flasher
|
||||
-b [arg] boots the kernel with arguments
|
||||
-c console prompt mode
|
||||
-C [/dev/mtd] check bad blocks on mtd
|
||||
-d [vid:pid] injects a usb device into the supported list
|
||||
-D [0|1|2] sets the root device to flash (0), mmc (1) or usb (2)
|
||||
-e [path] dump and extract pieces to path
|
||||
-f <flags> set the given RD flags (see '-f help')
|
||||
-F [fiasco] flash a fiasco firmware image
|
||||
-h show this help message
|
||||
-H [file] calculate hash for file
|
||||
-i show device information (let standby mode)
|
||||
-I [piece] identify a firmware piece
|
||||
-l, -L list supported usb device ids
|
||||
-p [[p%]file] piece-of-firmware % file-where-this-piece-is
|
||||
-r [0|1] disable/enable R&D mode
|
||||
-R reboot the omap board
|
||||
-s [serial] serial port console (minicom like terminal)
|
||||
-u [fiasco] unpack target fiasco image
|
||||
-U [0|1] disable/enable the usb host mode
|
||||
-v be verbose and noisy
|
||||
-V show 0xFFFF version information
|
||||
-x extract configuration entries from /dev/mtd1
|
||||
Pieces are: xloader secondary kernel initfs rootfs omap-nand
|
||||
</pre>
|
||||
|
||||
Before anything we can execute failsafe queries like getting device information:
|
||||
<pre> <b>~$ 0xFFFF -i</b></pre>
|
||||
This command will put the bootloader in standby mode, so you can now send other
|
||||
commands without having to reboot the tablet manually. To reboot the mother
|
||||
board via USB type:
|
||||
<pre> <b>~$ 0xFFFF -R</b></pre>
|
||||
You can run 'offline' commands to identify the type of the firmware pieces:
|
||||
<pre> <b>~$ 0xFFFF -I zImage -I xloader.bin -I initfs.jffs2.orig</b>
|
||||
kernel: zImage
|
||||
xloader: xloader.bin
|
||||
initfs: initfs.jffs2.orig</pre>
|
||||
If you want to backup your device firmware you can crosscompile the 0xFFFF
|
||||
utility and type this on the terminal:
|
||||
<pre> <b>~$ sudo gainroot</b>
|
||||
~# mkdir /media/mmc1/firmware
|
||||
~# ./0xFFFF -e /media/mmc1/firmware</pre>
|
||||
Now is time to flash something :) By default the flasher identifies the type
|
||||
of the piece automatically, but you can force't prefixing the filename with
|
||||
the piece-type name. To do this is just as simple as typing:
|
||||
<pre> <b>~$ 0xFFFF -p zImage</b></pre>
|
||||
@@ -1,53 +0,0 @@
|
||||
- preferences
|
||||
|
||||
* choose flasher type.
|
||||
|
||||
by default 0xFFFF is used
|
||||
|
||||
*
|
||||
|
||||
piece [file]
|
||||
|
|
||||
+-- radio
|
||||
|
|
||||
+-- nbh
|
||||
|
||||
info
|
||||
|
|
||||
+-- -i
|
||||
|
||||
reboot
|
||||
|
|
||||
+-- ???
|
||||
|
||||
----------
|
||||
|
||||
piece [file]
|
||||
|
|
||||
+-- xloader
|
||||
|
|
||||
+-- secondary
|
||||
|
|
||||
+-- kernel
|
||||
|
|
||||
+-- initfs
|
||||
|
|
||||
+-- rootfs
|
||||
|
|
||||
+-- autodetected
|
||||
|
||||
info
|
||||
|
|
||||
+-- -i
|
||||
|
||||
usb-host-mode
|
||||
|
|
||||
+-- -U [0|1]
|
||||
|
||||
rd-mode
|
||||
|
|
||||
+-- -r 0|1
|
||||
|
||||
reboot
|
||||
|
|
||||
+-- -R
|
||||
@@ -1,8 +0,0 @@
|
||||
OBJ=main.o
|
||||
BIN=goxf
|
||||
|
||||
CFLAGS=`pkg-config gladeui-1.0 libglade-2.0 --cflags`
|
||||
LDFLAGS=`pkg-config gladeui-1.0 libglade-2.0 --libs`
|
||||
|
||||
all: ${OBJ}
|
||||
${CC} ${LDFLAGS} ${OBJ} -o ${BIN}
|
||||
@@ -1,223 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<glade-interface>
|
||||
<widget class="GtkWindow" id="main_window">
|
||||
<property name="border_width">5</property>
|
||||
<property name="title" translatable="yes" context="yes">g0xFFFF</property>
|
||||
<property name="default_width">501</property>
|
||||
<property name="default_height">329</property>
|
||||
<property name="icon_name">gtk-connect</property>
|
||||
<signal name="destroy_event" handler="gtk_main_quit" object="0"/>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">3</property>
|
||||
<child>
|
||||
<widget class="GtkHButtonBox" id="hbuttonbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_START</property>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="combobox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="active">0</property>
|
||||
<property name="items" translatable="yes" context="yes">n770/n800
|
||||
HERMflasher</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="gochange">
|
||||
<property name="width_request">32</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="label" translatable="yes" context="yes">></property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="treeview1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">3</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<widget class="GtkFileChooserButton" id="filechooserbutton2">
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="combo1">
|
||||
<property name="row_span_column">0</property>
|
||||
<property name="column_span_column">0</property>
|
||||
<property name="active">0</property>
|
||||
<property name="tearoff_title">patata</property>
|
||||
<property name="items" translatable="yes" context="yes">rootfs
|
||||
initfs
|
||||
kernel
|
||||
secondary
|
||||
xloader</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox4">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="button2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" context="yes">Remove</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="add">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" context="yes">Add</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="checkbutton2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes" context="yes">USB host mode</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="checkbutton3">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes" context="yes">R&D mode</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="reboot">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes" context="yes">Reboot</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">3</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="progressbar1">
|
||||
<property name="visible">True</property>
|
||||
<property name="show_text">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox5">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkButton" id="info">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes" context="yes">gtk-dialog-info</property>
|
||||
<property name="use_stock">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="but_commit">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes" context="yes">gtk-execute</property>
|
||||
<property name="use_stock">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <glade/glade.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define U(x) printf("%d\n",x); fflush(stdout);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GtkWidget *w;
|
||||
GladeXML *xml;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
xml = glade_xml_new("g0xFFFF.glade", "main_window", "");
|
||||
//xml = glade_xml_new("test.glade", "window1", NULL);
|
||||
if(!xml) {
|
||||
g_warning("We could not load the interface!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
glade_xml_signal_autoconnect(xml);
|
||||
|
||||
w = glade_xml_get_widget(xml, "main_window");
|
||||
gtk_signal_connect(GTK_OBJECT(w), "destroy",
|
||||
GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
|
||||
gtk_widget_show_all(w);
|
||||
|
||||
gtk_object_unref(GTK_OBJECT(xml));
|
||||
|
||||
gtk_main();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#include ../config.mk
|
||||
OBJ=linux.o usb.o descriptors.o error.o
|
||||
|
||||
all: ${OBJ}
|
||||
${CC} ${CFLAGS} ${LDFLAGS} -fPIC -I . ${OBJ} -shared -o libusb.so
|
||||
|
||||
clean:
|
||||
-rm -f libusb.so ${OBJ}
|
||||
-637
@@ -1,637 +0,0 @@
|
||||
/*
|
||||
* (Free|Open|Net)BSD USB support
|
||||
*
|
||||
* Derived from Linux version by Richard Tobin.
|
||||
*
|
||||
* $Id: bsd.c,v 1.33 2006/03/04 01:16:10 jerdfelt Exp $
|
||||
* $Name: $
|
||||
*
|
||||
* This library is covered by the LGPL, read LICENSE for details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: I don't have a clue what I'm doing. I just looked at the
|
||||
* man pages and source to try and find things that did the same as
|
||||
* the Linux version. -- Richard
|
||||
*
|
||||
* johnjen@reynoldsnet.org - minor fixes with debug mode output. Consistent brace
|
||||
* use as well as indenting. More error messages put in to test for failure
|
||||
* modes with /dev/ permissions (when it happens). Note: I, like Richard, have
|
||||
* no clue what I'm doing. Patches to increase/fix functionality happily
|
||||
* accepted!
|
||||
*/
|
||||
|
||||
/* dirkx@webweaving.org - minor changes to make things actually work
|
||||
* for both read and write.
|
||||
*/
|
||||
|
||||
#if defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
|
||||
#define __FreeBSD_kernel__ __FreeBSD__
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
|
||||
#include "usbi.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OLD_DEV_USB_USB_H
|
||||
/*
|
||||
* It appears some of the BSD's (OpenBSD atleast) have switched over to a
|
||||
* new naming convention, so we setup some macro's for backward
|
||||
* compability with older versions --jerdfelt
|
||||
*/
|
||||
|
||||
/* struct usb_ctl_request */
|
||||
#define ucr_addr addr
|
||||
#define ucr_request request
|
||||
#define ucr_data data
|
||||
#define ucr_flags flags
|
||||
#define ucr_actlen actlen
|
||||
|
||||
/* struct usb_alt_interface */
|
||||
#define uai_config_index config_index
|
||||
#define uai_interface_index interface_index
|
||||
#define uai_alt_no alt_no
|
||||
|
||||
/* struct usb_config_desc */
|
||||
#define ucd_config_index config_index
|
||||
#define ucd_desc desc
|
||||
|
||||
/* struct usb_interface_desc */
|
||||
#define uid_config_index config_index
|
||||
#define uid_interface_index interface_index
|
||||
#define uid_alt_index alt_index
|
||||
#define uid_desc desc
|
||||
|
||||
/* struct usb_endpoint_desc */
|
||||
#define ued_config_index config_index
|
||||
#define ued_interface_index interface_index
|
||||
#define ued_alt_index alt_index
|
||||
#define ued_endpoint_index endpoint_index
|
||||
#define ued_desc desc
|
||||
|
||||
/* struct usb_full_desc */
|
||||
#define ufd_config_index config_index
|
||||
#define ufd_size size
|
||||
#define ufd_data data
|
||||
|
||||
/* struct usb_string_desc */
|
||||
#define usd_string_index string_index
|
||||
#define usd_language_id language_id
|
||||
#define usd_desc desc
|
||||
|
||||
/* struct usb_ctl_report_desc */
|
||||
#define ucrd_size size
|
||||
#define ucrd_data data
|
||||
|
||||
/* struct usb_device_info */
|
||||
#define udi_bus bus
|
||||
#define udi_addr addr
|
||||
#define udi_cookie cookie
|
||||
#define udi_product product
|
||||
#define udi_vendor vendor
|
||||
#define udi_release release
|
||||
#define udi_productNo productNo
|
||||
#define udi_vendorNo vendorNo
|
||||
#define udi_releaseNo releaseNo
|
||||
#define udi_class class
|
||||
#define udi_subclass subclass
|
||||
#define udi_protocol protocol
|
||||
#define udi_config config
|
||||
#define udi_lowspeed lowspeed
|
||||
#define udi_power power
|
||||
#define udi_nports nports
|
||||
#define udi_devnames devnames
|
||||
#define udi_ports ports
|
||||
|
||||
/* struct usb_ctl_report */
|
||||
#define ucr_report report
|
||||
#define ucr_data data
|
||||
|
||||
/* struct usb_device_stats */
|
||||
#define uds_requests requests
|
||||
#endif
|
||||
|
||||
static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode);
|
||||
|
||||
#define MAX_CONTROLLERS 10
|
||||
|
||||
/* This records the file descriptors for the endpoints. It doesn't seem
|
||||
to work to re-open them for each read (as well as being inefficient). */
|
||||
|
||||
struct bsd_usb_dev_handle_info {
|
||||
int ep_fd[USB_MAX_ENDPOINTS];
|
||||
};
|
||||
|
||||
int usb_os_open(usb_dev_handle *dev)
|
||||
{
|
||||
int i;
|
||||
struct bsd_usb_dev_handle_info *info;
|
||||
char ctlpath[PATH_MAX + 1];
|
||||
|
||||
info = malloc(sizeof(struct bsd_usb_dev_handle_info));
|
||||
if (!info)
|
||||
USB_ERROR(-ENOMEM);
|
||||
dev->impl_info = info;
|
||||
|
||||
#ifdef __FreeBSD_kernel__
|
||||
snprintf(ctlpath, PATH_MAX, "%s", dev->device->filename);
|
||||
#else
|
||||
snprintf(ctlpath, PATH_MAX, "%s.00", dev->device->filename);
|
||||
#endif
|
||||
dev->fd = open(ctlpath, O_RDWR);
|
||||
if (dev->fd < 0) {
|
||||
dev->fd = open(ctlpath, O_RDONLY);
|
||||
if (dev->fd < 0) {
|
||||
free(info);
|
||||
USB_ERROR_STR(-errno, "failed to open %s: %s",
|
||||
ctlpath, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark the endpoints as not yet open */
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
info->ep_fd[i] = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_os_close(usb_dev_handle *dev)
|
||||
{
|
||||
struct bsd_usb_dev_handle_info *info = dev->impl_info;
|
||||
int i;
|
||||
|
||||
/* Close any open endpoints */
|
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
if (info->ep_fd[i] >= 0) {
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_close: closing endpoint %d\n", info->ep_fd[i]);
|
||||
close(info->ep_fd[i]);
|
||||
}
|
||||
|
||||
free(info);
|
||||
|
||||
if (dev->fd <= 0)
|
||||
return 0;
|
||||
|
||||
if (close(dev->fd) == -1)
|
||||
/* Failing trying to close a file really isn't an error, so return 0 */
|
||||
USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
|
||||
strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_set_configuration(usb_dev_handle *dev, int configuration)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, USB_SET_CONFIG, &configuration);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
|
||||
strerror(errno));
|
||||
|
||||
dev->config = configuration;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_claim_interface(usb_dev_handle *dev, int interface)
|
||||
{
|
||||
/* BSD doesn't have the corresponding ioctl. It seems to
|
||||
be sufficient to open the relevant endpoints as needed. */
|
||||
|
||||
dev->interface = interface;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_release_interface(usb_dev_handle *dev, int interface)
|
||||
{
|
||||
/* See above */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_set_altinterface(usb_dev_handle *dev, int alternate)
|
||||
{
|
||||
int ret;
|
||||
struct usb_alt_interface intf;
|
||||
|
||||
if (dev->interface < 0)
|
||||
USB_ERROR(-EINVAL);
|
||||
|
||||
intf.uai_interface_index = dev->interface;
|
||||
intf.uai_alt_no = alternate;
|
||||
|
||||
ret = ioctl(dev->fd, USB_SET_ALTINTERFACE, &intf);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
|
||||
dev->interface, alternate, strerror(errno));
|
||||
|
||||
dev->altsetting = alternate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode)
|
||||
{
|
||||
struct bsd_usb_dev_handle_info *info = dev->impl_info;
|
||||
int fd;
|
||||
char buf[20];
|
||||
|
||||
/* Get the address for this endpoint; we could check
|
||||
* the mode against the direction; but we've done that
|
||||
* already in the usb_bulk_read/write.
|
||||
*/
|
||||
ep = UE_GET_ADDR(ep);
|
||||
|
||||
if (info->ep_fd[ep] < 0) {
|
||||
#ifdef __FreeBSD_kernel__
|
||||
snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->device->filename, ep);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->device->filename, ep);
|
||||
#endif
|
||||
/* Try to open it O_RDWR first for those devices which have in and out
|
||||
* endpoints with the same address (eg 0x02 and 0x82)
|
||||
*/
|
||||
fd = open(buf, O_RDWR);
|
||||
if (fd < 0 && errno == ENXIO)
|
||||
fd = open(buf, mode);
|
||||
if (fd < 0)
|
||||
USB_ERROR_STR(-errno, "can't open %s for bulk read: %s",
|
||||
buf, strerror(errno));
|
||||
info->ep_fd[ep] = fd;
|
||||
}
|
||||
|
||||
return info->ep_fd[ep];
|
||||
}
|
||||
|
||||
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
/* Ensure the endpoint address is correct */
|
||||
ep &= ~USB_ENDPOINT_IN;
|
||||
|
||||
fd = ensure_ep_open(dev, ep, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
if (usb_debug >= 2) {
|
||||
#ifdef __FreeBSD_kernel__
|
||||
fprintf (stderr, "usb_bulk_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
|
||||
#else
|
||||
fprintf (stderr, "usb_bulk_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
|
||||
#endif
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error setting timeout: %s",
|
||||
strerror(errno));
|
||||
|
||||
ret = write(fd, bytes, size);
|
||||
if (ret < 0)
|
||||
#ifdef __FreeBSD_kernel__
|
||||
USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#else
|
||||
USB_ERROR_STR(-errno, "error writing to bulk endpoint %s.%02d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#endif
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
int fd, ret, one = 1;
|
||||
|
||||
/* Ensure the endpoint address is correct */
|
||||
ep |= USB_ENDPOINT_IN;
|
||||
|
||||
fd = ensure_ep_open(dev, ep, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (usb_debug >= 2) {
|
||||
#ifdef __FreeBSD_kernel__
|
||||
fprintf (stderr, "usb_bulk_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
|
||||
#else
|
||||
fprintf (stderr, "usb_bulk_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
|
||||
#endif
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));
|
||||
|
||||
ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));
|
||||
|
||||
ret = read(fd, bytes, size);
|
||||
if (ret < 0)
|
||||
#ifdef __FreeBSD_kernel__
|
||||
USB_ERROR_STR(-errno, "error reading from bulk endpoint %s.%d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#else
|
||||
USB_ERROR_STR(-errno, "error reading from bulk endpoint %s.%02d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
int fd, ret, sent = 0;
|
||||
|
||||
/* Ensure the endpoint address is correct */
|
||||
ep &= ~USB_ENDPOINT_IN;
|
||||
|
||||
fd = ensure_ep_open(dev, ep, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
if (usb_debug >= 2) {
|
||||
#ifdef __FreeBSD_kernel__
|
||||
fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
|
||||
#else
|
||||
fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
|
||||
#endif
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error setting timeout: %s",
|
||||
strerror(errno));
|
||||
|
||||
do {
|
||||
ret = write(fd, bytes+sent, size-sent);
|
||||
if (ret < 0)
|
||||
#ifdef __FreeBSD_kernel__
|
||||
USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#else
|
||||
USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%02d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#endif
|
||||
|
||||
sent += ret;
|
||||
} while (ret > 0 && sent < size);
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
int fd, ret, retrieved = 0, one = 1;
|
||||
|
||||
/* Ensure the endpoint address is correct */
|
||||
ep |= USB_ENDPOINT_IN;
|
||||
|
||||
fd = ensure_ep_open(dev, ep, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (usb_debug >= 2) {
|
||||
#ifdef __FreeBSD_kernel__
|
||||
fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
|
||||
#else
|
||||
fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
|
||||
#endif
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));
|
||||
|
||||
ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));
|
||||
|
||||
do {
|
||||
ret = read(fd, bytes+retrieved, size-retrieved);
|
||||
if (ret < 0)
|
||||
#ifdef __FreeBSD_kernel__
|
||||
USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#else
|
||||
USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%02d: %s",
|
||||
dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
|
||||
#endif
|
||||
retrieved += ret;
|
||||
} while (ret > 0 && retrieved < size);
|
||||
|
||||
return retrieved;
|
||||
}
|
||||
|
||||
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
|
||||
int value, int index, char *bytes, int size, int timeout)
|
||||
{
|
||||
struct usb_ctl_request req;
|
||||
int ret;
|
||||
|
||||
if (usb_debug >= 3)
|
||||
fprintf(stderr, "usb_control_msg: %d %d %d %d %p %d %d\n",
|
||||
requesttype, request, value, index, bytes, size, timeout);
|
||||
|
||||
req.ucr_request.bmRequestType = requesttype;
|
||||
req.ucr_request.bRequest = request;
|
||||
USETW(req.ucr_request.wValue, value);
|
||||
USETW(req.ucr_request.wIndex, index);
|
||||
USETW(req.ucr_request.wLength, size);
|
||||
|
||||
req.ucr_data = bytes;
|
||||
req.ucr_flags = USBD_SHORT_XFER_OK;
|
||||
|
||||
ret = ioctl(dev->fd, USB_SET_TIMEOUT, &timeout);
|
||||
#if (__NetBSD__ || __OpenBSD__)
|
||||
if (ret < 0 && errno != EINVAL)
|
||||
#else
|
||||
if (ret < 0)
|
||||
#endif
|
||||
USB_ERROR_STR(-errno, "error setting timeout: %s",
|
||||
strerror(errno));
|
||||
|
||||
ret = ioctl(dev->fd, USB_DO_REQUEST, &req);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error sending control message: %s",
|
||||
strerror(errno));
|
||||
|
||||
return UGETW(req.ucr_request.wLength);
|
||||
}
|
||||
|
||||
int usb_os_find_busses(struct usb_bus **busses)
|
||||
{
|
||||
struct usb_bus *fbus = NULL;
|
||||
int controller;
|
||||
int fd;
|
||||
char buf[20];
|
||||
|
||||
for (controller = 0; controller < MAX_CONTROLLERS; controller++) {
|
||||
struct usb_bus *bus;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "/dev/usb%d", controller);
|
||||
fd = open(buf, O_RDWR);
|
||||
if (fd < 0) {
|
||||
if (usb_debug >= 2)
|
||||
if (errno != ENXIO && errno != ENOENT)
|
||||
fprintf(stderr, "usb_os_find_busses: can't open %s: %s\n",
|
||||
buf, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
bus = malloc(sizeof(*bus));
|
||||
if (!bus)
|
||||
USB_ERROR(-ENOMEM);
|
||||
|
||||
memset((void *)bus, 0, sizeof(*bus));
|
||||
|
||||
strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
|
||||
bus->dirname[sizeof(bus->dirname) - 1] = 0;
|
||||
|
||||
LIST_ADD(fbus, bus);
|
||||
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
|
||||
}
|
||||
|
||||
*busses = fbus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
|
||||
{
|
||||
struct usb_device *fdev = NULL;
|
||||
int cfd, dfd;
|
||||
int device;
|
||||
|
||||
cfd = open(bus->dirname, O_RDONLY);
|
||||
if (cfd < 0)
|
||||
USB_ERROR_STR(-errno, "couldn't open(%s): %s", bus->dirname,
|
||||
strerror(errno));
|
||||
|
||||
for (device = 1; device < USB_MAX_DEVICES; device++) {
|
||||
struct usb_device_info di;
|
||||
struct usb_device *dev;
|
||||
unsigned char device_desc[DEVICE_DESC_LENGTH];
|
||||
char buf[20];
|
||||
|
||||
di.udi_addr = device;
|
||||
if (ioctl(cfd, USB_DEVICEINFO, &di) < 0)
|
||||
continue;
|
||||
|
||||
/* There's a device; is it one we should mess with? */
|
||||
|
||||
if (strncmp(di.udi_devnames[0], "ugen", 4) != 0)
|
||||
/* best not to play with things we don't understand */
|
||||
continue;
|
||||
|
||||
#ifdef __FreeBSD_kernel__
|
||||
snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf) - 1, "/dev/%s.00", di.udi_devnames[0]);
|
||||
#endif
|
||||
|
||||
/* Open its control endpoint */
|
||||
dfd = open(buf, O_RDONLY);
|
||||
if (dfd < 0) {
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_devices: couldn't open device %s: %s\n",
|
||||
buf, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev)
|
||||
USB_ERROR(-ENOMEM);
|
||||
|
||||
memset((void *)dev, 0, sizeof(*dev));
|
||||
|
||||
dev->bus = bus;
|
||||
|
||||
/* we need to report the device name as /dev/ugenx NOT /dev/ugenx.00
|
||||
* This seemed easier than having 2 variables...
|
||||
*/
|
||||
#if (__NetBSD__ || __OpenBSD__)
|
||||
snprintf(buf, sizeof(buf) - 1, "/dev/%s", di.udi_devnames[0]);
|
||||
#endif
|
||||
|
||||
strncpy(dev->filename, buf, sizeof(dev->filename) - 1);
|
||||
dev->filename[sizeof(dev->filename) - 1] = 0;
|
||||
|
||||
if (ioctl(dfd, USB_GET_DEVICE_DESC, device_desc) < 0)
|
||||
USB_ERROR_STR(-errno, "couldn't get device descriptor for %s: %s",
|
||||
buf, strerror(errno));
|
||||
|
||||
close(dfd);
|
||||
|
||||
usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
|
||||
|
||||
LIST_ADD(fdev, dev);
|
||||
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
|
||||
dev->filename, bus->dirname);
|
||||
}
|
||||
|
||||
close(cfd);
|
||||
|
||||
*devices = fdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_os_determine_children(struct usb_bus *bus)
|
||||
{
|
||||
/* Nothing yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_os_init(void)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
int usb_resetep(usb_dev_handle *dev, unsigned int ep)
|
||||
{
|
||||
/* Not yet done, because I haven't needed it. */
|
||||
|
||||
USB_ERROR_STR(-ENOSYS, "usb_resetep called, unimplemented on BSD");
|
||||
}
|
||||
|
||||
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
|
||||
{
|
||||
/* Not yet done, because I haven't needed it. */
|
||||
|
||||
USB_ERROR_STR(-ENOSYS, "usb_clear_halt called, unimplemented on BSD");
|
||||
}
|
||||
|
||||
int usb_reset(usb_dev_handle *dev)
|
||||
{
|
||||
/* Not yet done, because I haven't needed it. */
|
||||
|
||||
USB_ERROR_STR(-ENOSYS, "usb_reset called, unimplemented on BSD");
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/* config.h. Generated by configure. */
|
||||
/* config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
#define LINUX_API 1
|
||||
#define BSD_API 0
|
||||
#define DARWIN_API 0
|
||||
|
||||
/* #undef HAVE_OLD_DEV_USB_USB_H */
|
||||
|
||||
#define HAVE_LIMITS_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_VALUES_H 1
|
||||
|
||||
#define LIBUSB_MAJOR_VERSION 0
|
||||
#define LIBUSB_MINOR_VERSION 1
|
||||
#define LIBUSB_MICRO_VERSION 12
|
||||
#define LIBUSB_INTERFACE_AGE 4
|
||||
#define LIBUSB_BINARY_AGE 8
|
||||
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
/* #undef HAVE_DOPRNT */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the <values.h> header file. */
|
||||
#define HAVE_VALUES_H 1
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
/* #undef NO_MINUS_C_MINUS_O */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "libusb"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "libusb"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "libusb 0.1.12"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libusb"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "0.1.12"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.1.12"
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
/* #undef WORDS_BIGENDIAN */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
-1209
File diff suppressed because it is too large.
Load diff
@@ -1,520 +0,0 @@
|
||||
/*
|
||||
* Parses descriptors
|
||||
*
|
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is covered by the LGPL, read LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "usbi.h"
|
||||
|
||||
int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
|
||||
unsigned char type, unsigned char index, void *buf, int size)
|
||||
{
|
||||
memset(buf, 0, size);
|
||||
|
||||
return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
|
||||
(type << 8) + index, 0, buf, size, 1000);
|
||||
}
|
||||
|
||||
int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
|
||||
unsigned char index, void *buf, int size)
|
||||
{
|
||||
memset(buf, 0, size);
|
||||
|
||||
return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
|
||||
(type << 8) + index, 0, buf, size, 1000);
|
||||
}
|
||||
|
||||
int usb_parse_descriptor(unsigned char *source, char *description, void *dest)
|
||||
{
|
||||
unsigned char *sp = source, *dp = dest;
|
||||
uint16_t w;
|
||||
uint32_t d;
|
||||
char *cp;
|
||||
|
||||
for (cp = description; *cp; cp++) {
|
||||
switch (*cp) {
|
||||
case 'b': /* 8-bit byte */
|
||||
*dp++ = *sp++;
|
||||
break;
|
||||
case 'w': /* 16-bit word, convert from little endian to CPU */
|
||||
w = (sp[1] << 8) | sp[0]; sp += 2;
|
||||
dp += ((unsigned long)dp & 1); /* Align to word boundary */
|
||||
*((uint16_t *)dp) = w; dp += 2;
|
||||
break;
|
||||
case 'd': /* 32-bit dword, convert from little endian to CPU */
|
||||
d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4;
|
||||
dp += ((unsigned long)dp & 2); /* Align to dword boundary */
|
||||
*((uint32_t *)dp) = d; dp += 4;
|
||||
break;
|
||||
/* These two characters are undocumented and just a hack for Linux */
|
||||
case 'W': /* 16-bit word, keep CPU endianess */
|
||||
dp += ((unsigned long)dp & 1); /* Align to word boundary */
|
||||
memcpy(dp, sp, 2); sp += 2; dp += 2;
|
||||
break;
|
||||
case 'D': /* 32-bit dword, keep CPU endianess */
|
||||
dp += ((unsigned long)dp & 2); /* Align to dword boundary */
|
||||
memcpy(dp, sp, 4); sp += 4; dp += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sp - source;
|
||||
}
|
||||
|
||||
/*
|
||||
* This code looks surprisingly similar to the code I wrote for the Linux
|
||||
* kernel. It's not a coincidence :)
|
||||
*/
|
||||
|
||||
static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
|
||||
{
|
||||
struct usb_descriptor_header header;
|
||||
unsigned char *begin;
|
||||
int parsed = 0, len, numskipped;
|
||||
|
||||
usb_parse_descriptor(buffer, "bb", &header);
|
||||
|
||||
/* Everything should be fine being passed into here, but we sanity */
|
||||
/* check JIC */
|
||||
if (header.bLength > size) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "ran out of descriptors parsing\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header.bDescriptorType != USB_DT_ENDPOINT) {
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n",
|
||||
header.bDescriptorType, USB_DT_ENDPOINT);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
|
||||
usb_parse_descriptor(buffer, "bbbbwbbb", endpoint);
|
||||
else if (header.bLength >= ENDPOINT_DESC_LENGTH)
|
||||
usb_parse_descriptor(buffer, "bbbbwb", endpoint);
|
||||
|
||||
buffer += header.bLength;
|
||||
size -= header.bLength;
|
||||
parsed += header.bLength;
|
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor Specific */
|
||||
/* descriptors */
|
||||
begin = buffer;
|
||||
numskipped = 0;
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
usb_parse_descriptor(buffer, "bb", &header);
|
||||
|
||||
if (header.bLength < 2) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
|
||||
(header.bDescriptorType == USB_DT_INTERFACE) ||
|
||||
(header.bDescriptorType == USB_DT_CONFIG) ||
|
||||
(header.bDescriptorType == USB_DT_DEVICE))
|
||||
break;
|
||||
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
|
||||
numskipped++;
|
||||
|
||||
buffer += header.bLength;
|
||||
size -= header.bLength;
|
||||
parsed += header.bLength;
|
||||
}
|
||||
|
||||
if (numskipped && usb_debug >= 2)
|
||||
fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for drivers */
|
||||
/* to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (!len) {
|
||||
endpoint->extra = NULL;
|
||||
endpoint->extralen = 0;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
endpoint->extra = malloc(len);
|
||||
if (!endpoint->extra) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n");
|
||||
endpoint->extralen = 0;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
memcpy(endpoint->extra, begin, len);
|
||||
endpoint->extralen = len;
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static int usb_parse_interface(struct usb_interface *interface,
|
||||
unsigned char *buffer, int size)
|
||||
{
|
||||
int i, len, numskipped, retval, parsed = 0;
|
||||
struct usb_descriptor_header header;
|
||||
struct usb_interface_descriptor *ifp;
|
||||
unsigned char *begin;
|
||||
|
||||
interface->num_altsetting = 0;
|
||||
|
||||
while (size >= INTERFACE_DESC_LENGTH) {
|
||||
interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1));
|
||||
if (!interface->altsetting) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "couldn't malloc interface->altsetting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ifp = interface->altsetting + interface->num_altsetting;
|
||||
interface->num_altsetting++;
|
||||
|
||||
usb_parse_descriptor(buffer, "bbbbbbbbb", ifp);
|
||||
|
||||
/* Skip over the interface */
|
||||
buffer += ifp->bLength;
|
||||
parsed += ifp->bLength;
|
||||
size -= ifp->bLength;
|
||||
|
||||
begin = buffer;
|
||||
numskipped = 0;
|
||||
|
||||
/* Skip over any interface, class or vendor descriptors */
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
usb_parse_descriptor(buffer, "bb", &header);
|
||||
|
||||
if (header.bLength < 2) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if ((header.bDescriptorType == USB_DT_INTERFACE) ||
|
||||
(header.bDescriptorType == USB_DT_ENDPOINT) ||
|
||||
(header.bDescriptorType == USB_DT_CONFIG) ||
|
||||
(header.bDescriptorType == USB_DT_DEVICE))
|
||||
break;
|
||||
|
||||
numskipped++;
|
||||
|
||||
buffer += header.bLength;
|
||||
parsed += header.bLength;
|
||||
size -= header.bLength;
|
||||
}
|
||||
|
||||
if (numskipped && usb_debug >= 2)
|
||||
fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped);
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for */
|
||||
/* drivers to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (!len) {
|
||||
ifp->extra = NULL;
|
||||
ifp->extralen = 0;
|
||||
} else {
|
||||
ifp->extra = malloc(len);
|
||||
if (!ifp->extra) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n");
|
||||
ifp->extralen = 0;
|
||||
return -1;
|
||||
}
|
||||
memcpy(ifp->extra, begin, len);
|
||||
ifp->extralen = len;
|
||||
}
|
||||
|
||||
/* Did we hit an unexpected descriptor? */
|
||||
usb_parse_descriptor(buffer, "bb", &header);
|
||||
if ((size >= DESC_HEADER_LENGTH) &&
|
||||
((header.bDescriptorType == USB_DT_CONFIG) ||
|
||||
(header.bDescriptorType == USB_DT_DEVICE)))
|
||||
return parsed;
|
||||
|
||||
if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "too many endpoints\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifp->bNumEndpoints > 0) {
|
||||
ifp->endpoint = (struct usb_endpoint_descriptor *)
|
||||
malloc(ifp->bNumEndpoints *
|
||||
sizeof(struct usb_endpoint_descriptor));
|
||||
if (!ifp->endpoint) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(ifp->endpoint, 0, ifp->bNumEndpoints *
|
||||
sizeof(struct usb_endpoint_descriptor));
|
||||
|
||||
for (i = 0; i < ifp->bNumEndpoints; i++) {
|
||||
usb_parse_descriptor(buffer, "bb", &header);
|
||||
|
||||
if (header.bLength > size) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "ran out of descriptors parsing\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
buffer += retval;
|
||||
parsed += retval;
|
||||
size -= retval;
|
||||
}
|
||||
} else
|
||||
ifp->endpoint = NULL;
|
||||
|
||||
/* We check to see if it's an alternate to this one */
|
||||
ifp = (struct usb_interface_descriptor *)buffer;
|
||||
if (size < USB_DT_INTERFACE_SIZE ||
|
||||
ifp->bDescriptorType != USB_DT_INTERFACE ||
|
||||
!ifp->bAlternateSetting)
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
int usb_parse_configuration(struct usb_config_descriptor *config,
|
||||
unsigned char *buffer)
|
||||
{
|
||||
int i, retval, size;
|
||||
struct usb_descriptor_header header;
|
||||
|
||||
usb_parse_descriptor(buffer, "bbwbbbbb", config);
|
||||
size = config->wTotalLength;
|
||||
|
||||
if (config->bNumInterfaces > USB_MAXINTERFACES) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "too many interfaces\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
config->interface = (struct usb_interface *)
|
||||
malloc(config->bNumInterfaces *
|
||||
sizeof(struct usb_interface));
|
||||
if (!config->interface) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface));
|
||||
|
||||
buffer += config->bLength;
|
||||
size -= config->bLength;
|
||||
|
||||
config->extra = NULL;
|
||||
config->extralen = 0;
|
||||
|
||||
for (i = 0; i < config->bNumInterfaces; i++) {
|
||||
int numskipped, len;
|
||||
unsigned char *begin;
|
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor */
|
||||
/* Specific descriptors */
|
||||
begin = buffer;
|
||||
numskipped = 0;
|
||||
while (size >= DESC_HEADER_LENGTH) {
|
||||
usb_parse_descriptor(buffer, "bb", &header);
|
||||
|
||||
if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If we find another "proper" descriptor then we're done */
|
||||
if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
|
||||
(header.bDescriptorType == USB_DT_INTERFACE) ||
|
||||
(header.bDescriptorType == USB_DT_CONFIG) ||
|
||||
(header.bDescriptorType == USB_DT_DEVICE))
|
||||
break;
|
||||
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
|
||||
numskipped++;
|
||||
|
||||
buffer += header.bLength;
|
||||
size -= header.bLength;
|
||||
}
|
||||
|
||||
if (numskipped && usb_debug >= 2)
|
||||
fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
|
||||
|
||||
/* Copy any unknown descriptors into a storage area for */
|
||||
/* drivers to later parse */
|
||||
len = (int)(buffer - begin);
|
||||
if (len) {
|
||||
/* FIXME: We should realloc and append here */
|
||||
if (!config->extralen) {
|
||||
config->extra = malloc(len);
|
||||
if (!config->extra) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "couldn't allocate memory for config extra descriptors\n");
|
||||
config->extralen = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(config->extra, begin, len);
|
||||
config->extralen = len;
|
||||
}
|
||||
}
|
||||
|
||||
retval = usb_parse_interface(config->interface + i, buffer, size);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
buffer += retval;
|
||||
size -= retval;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void usb_destroy_configuration(struct usb_device *dev)
|
||||
{
|
||||
int c, i, j, k;
|
||||
|
||||
if (!dev->config)
|
||||
return;
|
||||
|
||||
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
|
||||
struct usb_config_descriptor *cf = &dev->config[c];
|
||||
|
||||
if (!cf->interface)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < cf->bNumInterfaces; i++) {
|
||||
struct usb_interface *ifp = &cf->interface[i];
|
||||
|
||||
if (!ifp->altsetting)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < ifp->num_altsetting; j++) {
|
||||
struct usb_interface_descriptor *as = &ifp->altsetting[j];
|
||||
|
||||
if (as->extra)
|
||||
free(as->extra);
|
||||
|
||||
if (!as->endpoint)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < as->bNumEndpoints; k++) {
|
||||
if (as->endpoint[k].extra)
|
||||
free(as->endpoint[k].extra);
|
||||
}
|
||||
free(as->endpoint);
|
||||
}
|
||||
|
||||
free(ifp->altsetting);
|
||||
}
|
||||
|
||||
free(cf->interface);
|
||||
}
|
||||
|
||||
free(dev->config);
|
||||
}
|
||||
|
||||
void usb_fetch_and_parse_descriptors(usb_dev_handle *udev)
|
||||
{
|
||||
struct usb_device *dev = udev->device;
|
||||
int i;
|
||||
|
||||
if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->descriptor.bNumConfigurations < 1) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
|
||||
if (!dev->config) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "Unable to allocate memory for config descriptor\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
|
||||
sizeof(struct usb_config_descriptor));
|
||||
|
||||
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
|
||||
unsigned char buffer[8], *bigbuffer;
|
||||
struct usb_config_descriptor config;
|
||||
int res;
|
||||
|
||||
/* Get the first 8 bytes so we can figure out what the total length is */
|
||||
res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8);
|
||||
if (res < 8) {
|
||||
if (usb_debug >= 1) {
|
||||
if (res < 0)
|
||||
fprintf(stderr, "Unable to get descriptor (%d)\n", res);
|
||||
else
|
||||
fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res);
|
||||
}
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
usb_parse_descriptor(buffer, "bbw", &config);
|
||||
|
||||
bigbuffer = malloc(config.wTotalLength);
|
||||
if (!bigbuffer) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "Unable to allocate memory for descriptors\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength);
|
||||
if (res < config.wTotalLength) {
|
||||
if (usb_debug >= 1) {
|
||||
if (res < 0)
|
||||
fprintf(stderr, "Unable to get descriptor (%d)\n", res);
|
||||
else
|
||||
fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res);
|
||||
}
|
||||
|
||||
free(bigbuffer);
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = usb_parse_configuration(&dev->config[i], bigbuffer);
|
||||
if (usb_debug >= 2) {
|
||||
if (res > 0)
|
||||
fprintf(stderr, "Descriptor data still left\n");
|
||||
else if (res < 0)
|
||||
fprintf(stderr, "Unable to parse descriptors\n");
|
||||
}
|
||||
|
||||
free(bigbuffer);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
free(dev->config);
|
||||
|
||||
dev->config = NULL;
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* USB Error messages
|
||||
*
|
||||
* Copyright (c) 2000-2001 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is covered by the LGPL, read LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "error.h"
|
||||
|
||||
char usb_error_str[1024] = "";
|
||||
int usb_error_errno = 0;
|
||||
usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE;
|
||||
|
||||
char *usb_strerror(void)
|
||||
{
|
||||
switch (usb_error_type) {
|
||||
case USB_ERROR_TYPE_NONE:
|
||||
return "No error";
|
||||
case USB_ERROR_TYPE_STRING:
|
||||
return usb_error_str;
|
||||
case USB_ERROR_TYPE_ERRNO:
|
||||
if (usb_error_errno > -USB_ERROR_BEGIN)
|
||||
return strerror(usb_error_errno);
|
||||
else
|
||||
/* Any error we don't know falls under here */
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef _ERROR_H_
|
||||
#define _ERROR_H_
|
||||
|
||||
typedef enum {
|
||||
USB_ERROR_TYPE_NONE = 0,
|
||||
USB_ERROR_TYPE_STRING,
|
||||
USB_ERROR_TYPE_ERRNO,
|
||||
} usb_error_type_t;
|
||||
|
||||
extern char usb_error_str[1024];
|
||||
extern int usb_error_errno;
|
||||
extern usb_error_type_t usb_error_type;
|
||||
|
||||
#define USB_ERROR(x) \
|
||||
do { \
|
||||
usb_error_type = USB_ERROR_TYPE_ERRNO; \
|
||||
usb_error_errno = x; \
|
||||
return x; \
|
||||
} while (0)
|
||||
|
||||
#define USB_ERROR_STR(x, format, args...) \
|
||||
do { \
|
||||
usb_error_type = USB_ERROR_TYPE_STRING; \
|
||||
snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
|
||||
if (usb_debug >= 2) \
|
||||
fprintf(stderr, "USB error: %s\n", usb_error_str); \
|
||||
return x; \
|
||||
} while (0)
|
||||
|
||||
#endif /* _ERROR_H_ */
|
||||
|
||||
-733
@@ -1,733 +0,0 @@
|
||||
/*
|
||||
* Linux USB support
|
||||
*
|
||||
* Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is covered by the LGPL, read LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* getenv, etc */
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "linux.h"
|
||||
#include "usbi.h"
|
||||
|
||||
static char usb_path[PATH_MAX + 1] = "";
|
||||
|
||||
static int device_open(struct usb_device *dev)
|
||||
{
|
||||
char filename[PATH_MAX + 1];
|
||||
int fd;
|
||||
|
||||
snprintf(filename, sizeof(filename) - 1, "%s/%s/%s",
|
||||
usb_path, dev->bus->dirname, dev->filename);
|
||||
|
||||
fd = open(filename, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
USB_ERROR_STR(-errno, "failed to open %s: %s",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int usb_os_open(usb_dev_handle *dev)
|
||||
{
|
||||
dev->fd = device_open(dev->device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_os_close(usb_dev_handle *dev)
|
||||
{
|
||||
if (dev->fd < 0)
|
||||
return 0;
|
||||
|
||||
if (close(dev->fd) == -1)
|
||||
/* Failing trying to close a file really isn't an error, so return 0 */
|
||||
USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
|
||||
strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_set_configuration(usb_dev_handle *dev, int configuration)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
|
||||
strerror(errno));
|
||||
|
||||
dev->config = configuration;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_claim_interface(usb_dev_handle *dev, int interface)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);
|
||||
if (ret < 0) {
|
||||
if (errno == EBUSY && usb_debug > 0)
|
||||
fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename);
|
||||
|
||||
USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
dev->interface = interface;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_release_interface(usb_dev_handle *dev, int interface)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "could not release intf %d: %s", interface,
|
||||
strerror(errno));
|
||||
|
||||
dev->interface = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_set_altinterface(usb_dev_handle *dev, int alternate)
|
||||
{
|
||||
int ret;
|
||||
struct usb_setinterface setintf;
|
||||
|
||||
if (dev->interface < 0)
|
||||
USB_ERROR(-EINVAL);
|
||||
|
||||
setintf.interface = dev->interface;
|
||||
setintf.altsetting = alternate;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
|
||||
dev->interface, alternate, strerror(errno));
|
||||
|
||||
dev->altsetting = alternate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux usbfs has a limit of one page size for synchronous bulk read/write.
|
||||
* 4096 is the most portable maximum we can do for now.
|
||||
* Linux usbfs has a limit of 16KB for the URB interface. We use this now
|
||||
* to get better performance for USB 2.0 devices.
|
||||
*/
|
||||
#define MAX_READ_WRITE (16 * 1024)
|
||||
|
||||
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
|
||||
int value, int index, char *bytes, int size, int timeout)
|
||||
{
|
||||
struct usb_ctrltransfer ctrl;
|
||||
int ret;
|
||||
|
||||
ctrl.bRequestType = requesttype;
|
||||
ctrl.bRequest = request;
|
||||
ctrl.wValue = value;
|
||||
ctrl.wIndex = index;
|
||||
ctrl.wLength = size;
|
||||
|
||||
ctrl.data = bytes;
|
||||
ctrl.timeout = timeout;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl);
|
||||
if (ret < 0)
|
||||
USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define URB_USERCONTEXT_COOKIE ((void *)0x1)
|
||||
|
||||
/* Reading and writing are the same except for the endpoint */
|
||||
static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype,
|
||||
char *bytes, int size, int timeout)
|
||||
{
|
||||
struct usb_urb urb;
|
||||
int bytesdone = 0, requested;
|
||||
struct timeval tv, tv_ref, tv_now;
|
||||
struct usb_urb *context;
|
||||
int ret, waiting;
|
||||
|
||||
/*
|
||||
* HACK: The use of urb.usercontext is a hack to get threaded applications
|
||||
* sort of working again. Threaded support is still not recommended, but
|
||||
* this should allow applications to work in the common cases. Basically,
|
||||
* if we get the completion for an URB we're not waiting for, then we update
|
||||
* the usercontext pointer to 1 for the other threads URB and it will see
|
||||
* the change after it wakes up from the the timeout. Ugly, but it works.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get actual time, and add the timeout value. The result is the absolute
|
||||
* time where we have to quit waiting for an message.
|
||||
*/
|
||||
gettimeofday(&tv_ref, NULL);
|
||||
tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000;
|
||||
tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000;
|
||||
|
||||
if (tv_ref.tv_usec > 1000000) {
|
||||
tv_ref.tv_usec -= 1000000;
|
||||
tv_ref.tv_sec++;
|
||||
}
|
||||
|
||||
do {
|
||||
fd_set writefds;
|
||||
|
||||
requested = size - bytesdone;
|
||||
if (requested > MAX_READ_WRITE)
|
||||
requested = MAX_READ_WRITE;
|
||||
|
||||
urb.type = urbtype;
|
||||
urb.endpoint = ep;
|
||||
urb.flags = 0;
|
||||
urb.buffer = bytes + bytesdone;
|
||||
urb.buffer_length = requested;
|
||||
urb.signr = 0;
|
||||
urb.actual_length = 0;
|
||||
urb.number_of_packets = 0; /* don't do isochronous yet */
|
||||
urb.usercontext = NULL;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);
|
||||
if (ret < 0) {
|
||||
USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(dev->fd, &writefds);
|
||||
|
||||
restart:
|
||||
waiting = 1;
|
||||
context = NULL;
|
||||
while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000; // 1 msec
|
||||
select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
|
||||
|
||||
if (timeout) {
|
||||
/* compare with actual time, as the select timeout is not that precise */
|
||||
gettimeofday(&tv_now, NULL);
|
||||
|
||||
if ((tv_now.tv_sec > tv_ref.tv_sec) ||
|
||||
((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
|
||||
waiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (context && context != &urb) {
|
||||
context->usercontext = URB_USERCONTEXT_COOKIE;
|
||||
/* We need to restart since we got a successful URB, but not ours */
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was an error, that wasn't EAGAIN (no completion), then
|
||||
* something happened during the reaping and we should return that
|
||||
* error now
|
||||
*/
|
||||
if (ret < 0 && !urb.usercontext && errno != EAGAIN)
|
||||
USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno));
|
||||
|
||||
bytesdone += urb.actual_length;
|
||||
} while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
|
||||
|
||||
/* If the URB didn't complete in success or error, then let's unlink it */
|
||||
if (ret < 0 && !urb.usercontext) {
|
||||
int rc;
|
||||
|
||||
if (!waiting)
|
||||
rc = -ETIMEDOUT;
|
||||
else
|
||||
rc = urb.status;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb);
|
||||
if (ret < 0 && errno != EINVAL && usb_debug >= 1)
|
||||
fprintf(stderr, "error discarding URB: %s", strerror(errno));
|
||||
|
||||
/*
|
||||
* When the URB is unlinked, it gets moved to the completed list and
|
||||
* then we need to reap it or else the next time we call this function,
|
||||
* we'll get the previous completion and exit early
|
||||
*/
|
||||
ioctl(dev->fd, IOCTL_USB_REAPURB, &context);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return bytesdone;
|
||||
}
|
||||
|
||||
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
/* Ensure the endpoint address is correct */
|
||||
return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
|
||||
timeout);
|
||||
}
|
||||
|
||||
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
/* Ensure the endpoint address is correct */
|
||||
ep |= USB_ENDPOINT_IN;
|
||||
return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
|
||||
timeout);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked
|
||||
* 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need
|
||||
* to lookup the endpoint packet size and packetize appropriately here.
|
||||
*/
|
||||
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
/* Ensure the endpoint address is correct */
|
||||
return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
|
||||
timeout);
|
||||
}
|
||||
|
||||
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout)
|
||||
{
|
||||
/* Ensure the endpoint address is correct */
|
||||
ep |= USB_ENDPOINT_IN;
|
||||
return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
|
||||
timeout);
|
||||
}
|
||||
|
||||
int usb_os_find_busses(struct usb_bus **busses)
|
||||
{
|
||||
struct usb_bus *fbus = NULL;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
dir = opendir(usb_path);
|
||||
if (!dir)
|
||||
USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path,
|
||||
strerror(errno));
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
struct usb_bus *bus;
|
||||
|
||||
/* Skip anything starting with a . */
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) {
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n",
|
||||
entry->d_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
bus = malloc(sizeof(*bus));
|
||||
if (!bus)
|
||||
USB_ERROR(-ENOMEM);
|
||||
|
||||
memset((void *)bus, 0, sizeof(*bus));
|
||||
|
||||
strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1);
|
||||
bus->dirname[sizeof(bus->dirname) - 1] = 0;
|
||||
|
||||
LIST_ADD(fbus, bus);
|
||||
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
*busses = fbus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
|
||||
{
|
||||
struct usb_device *fdev = NULL;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
char dirpath[PATH_MAX + 1];
|
||||
|
||||
snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);
|
||||
|
||||
dir = opendir(dirpath);
|
||||
if (!dir)
|
||||
USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath,
|
||||
strerror(errno));
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
unsigned char device_desc[DEVICE_DESC_LENGTH];
|
||||
char filename[PATH_MAX + 1];
|
||||
struct usb_device *dev;
|
||||
struct usb_connectinfo connectinfo;
|
||||
int i, fd, ret;
|
||||
|
||||
/* Skip anything starting with a . */
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev)
|
||||
USB_ERROR(-ENOMEM);
|
||||
|
||||
memset((void *)dev, 0, sizeof(*dev));
|
||||
|
||||
dev->bus = bus;
|
||||
|
||||
strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1);
|
||||
dev->filename[sizeof(dev->filename) - 1] = 0;
|
||||
|
||||
snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name);
|
||||
fd = open(filename, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n",
|
||||
filename);
|
||||
|
||||
free(dev);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the device number */
|
||||
ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);
|
||||
if (ret < 0) {
|
||||
if (usb_debug)
|
||||
fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n");
|
||||
} else
|
||||
dev->devnum = connectinfo.devnum;
|
||||
|
||||
ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);
|
||||
if (ret < 0) {
|
||||
if (usb_debug)
|
||||
fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n");
|
||||
|
||||
free(dev);
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Linux kernel converts the words in this descriptor to CPU endian, so
|
||||
* we use the undocumented W character for usb_parse_descriptor() that
|
||||
* doesn't convert endianess when parsing the descriptor
|
||||
*/
|
||||
usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor);
|
||||
|
||||
LIST_ADD(fdev, dev);
|
||||
|
||||
if (usb_debug >= 2)
|
||||
fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
|
||||
dev->filename, bus->dirname);
|
||||
|
||||
/* Now try to fetch the rest of the descriptors */
|
||||
if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
|
||||
/* Silent since we'll try again later */
|
||||
goto err;
|
||||
|
||||
if (dev->descriptor.bNumConfigurations < 1)
|
||||
/* Silent since we'll try again later */
|
||||
goto err;
|
||||
|
||||
dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
|
||||
if (!dev->config)
|
||||
/* Silent since we'll try again later */
|
||||
goto err;
|
||||
|
||||
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
|
||||
sizeof(struct usb_config_descriptor));
|
||||
|
||||
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
|
||||
unsigned char buffer[8], *bigbuffer;
|
||||
struct usb_config_descriptor config;
|
||||
|
||||
/* Get the first 8 bytes so we can figure out what the total length is */
|
||||
ret = read(fd, (void *)buffer, 8);
|
||||
if (ret < 8) {
|
||||
if (usb_debug >= 1) {
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
|
||||
else
|
||||
fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret);
|
||||
}
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
usb_parse_descriptor(buffer, "bbw", &config);
|
||||
|
||||
bigbuffer = malloc(config.wTotalLength);
|
||||
if (!bigbuffer) {
|
||||
if (usb_debug >= 1)
|
||||
fprintf(stderr, "Unable to allocate memory for descriptors\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Read the rest of the config descriptor */
|
||||
memcpy(bigbuffer, buffer, 8);
|
||||
|
||||
ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8);
|
||||
if (ret < config.wTotalLength - 8) {
|
||||
if (usb_debug >= 1) {
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
|
||||
else
|
||||
fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret);
|
||||
}
|
||||
|
||||
free(bigbuffer);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = usb_parse_configuration(&dev->config[i], bigbuffer);
|
||||
if (usb_debug >= 2) {
|
||||
if (ret > 0)
|
||||
fprintf(stderr, "Descriptor data still left\n");
|
||||
else if (ret < 0)
|
||||
fprintf(stderr, "Unable to parse descriptors\n");
|
||||
}
|
||||
|
||||
free(bigbuffer);
|
||||
}
|
||||
|
||||
err:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
*devices = fdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_os_determine_children(struct usb_bus *bus)
|
||||
{
|
||||
struct usb_device *dev, *devices[256];
|
||||
struct usb_ioctl command;
|
||||
int ret, i, i1;
|
||||
|
||||
/* Create a list of devices first */
|
||||
memset(devices, 0, sizeof(devices));
|
||||
for (dev = bus->devices; dev; dev = dev->next)
|
||||
if (dev->devnum)
|
||||
devices[dev->devnum] = dev;
|
||||
|
||||
/* Now fetch the children for each device */
|
||||
for (dev = bus->devices; dev; dev = dev->next) {
|
||||
struct usb_hub_portinfo portinfo;
|
||||
int fd;
|
||||
|
||||
fd = device_open(dev);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
/* Query the hub driver for the children of this device */
|
||||
if (dev->config && dev->config->interface && dev->config->interface->altsetting)
|
||||
command.ifno = dev->config->interface->altsetting->bInterfaceNumber;
|
||||
else
|
||||
command.ifno = 0;
|
||||
command.ioctl_code = IOCTL_USB_HUB_PORTINFO;
|
||||
command.data = &portinfo;
|
||||
ret = ioctl(fd, IOCTL_USB_IOCTL, &command);
|
||||
if (ret < 0) {
|
||||
/* errno == ENOSYS means the device probably wasn't a hub */
|
||||
if (errno != ENOSYS && usb_debug > 1)
|
||||
fprintf(stderr, "error obtaining child information: %s\n",
|
||||
strerror(errno));
|
||||
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev->num_children = 0;
|
||||
for (i = 0; i < portinfo.numports; i++)
|
||||
if (portinfo.port[i])
|
||||
dev->num_children++;
|
||||
|
||||
/* Free any old children first */
|
||||
free(dev->children);
|
||||
|
||||
dev->children = malloc(sizeof(struct usb_device *) * dev->num_children);
|
||||
if (!dev->children) {
|
||||
if (usb_debug > 1)
|
||||
fprintf(stderr, "error allocating %zu bytes memory for dev->children\n",
|
||||
sizeof(struct usb_device *) * dev->num_children);
|
||||
|
||||
dev->num_children = 0;
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0, i1 = 0; i < portinfo.numports; i++) {
|
||||
if (!portinfo.port[i])
|
||||
continue;
|
||||
|
||||
dev->children[i1++] = devices[portinfo.port[i]];
|
||||
|
||||
devices[portinfo.port[i]] = NULL;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* There should be one device left in the devices list and that should be
|
||||
* the root device
|
||||
*/
|
||||
for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
|
||||
if (devices[i])
|
||||
bus->root_dev = devices[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_usb_vfs(const char *dirname)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int found = 0;
|
||||
|
||||
dir = opendir(dirname);
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
/* Skip anything starting with a . */
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
/* We assume if we find any files that it must be the right place */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void usb_os_init(void)
|
||||
{
|
||||
/* Find the path to the virtual filesystem */
|
||||
if (getenv("USB_DEVFS_PATH")) {
|
||||
if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) {
|
||||
strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1);
|
||||
usb_path[sizeof(usb_path) - 1] = 0;
|
||||
} else if (usb_debug)
|
||||
fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n");
|
||||
}
|
||||
|
||||
if (!usb_path[0]) {
|
||||
if (check_usb_vfs("/dev/bus/usb")) {
|
||||
strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1);
|
||||
usb_path[sizeof(usb_path) - 1] = 0;
|
||||
} else if (check_usb_vfs("/proc/bus/usb")) {
|
||||
strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1);
|
||||
usb_path[sizeof(usb_path) - 1] = 0;
|
||||
} else
|
||||
usb_path[0] = 0; /* No path, no USB support */
|
||||
}
|
||||
|
||||
if (usb_debug) {
|
||||
if (usb_path[0])
|
||||
fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path);
|
||||
else
|
||||
fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n");
|
||||
}
|
||||
}
|
||||
|
||||
int usb_resetep(usb_dev_handle *dev, unsigned int ep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep);
|
||||
if (ret)
|
||||
USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep,
|
||||
strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep);
|
||||
if (ret)
|
||||
USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep,
|
||||
strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_reset(usb_dev_handle *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL);
|
||||
if (ret)
|
||||
USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
|
||||
unsigned int namelen)
|
||||
{
|
||||
struct usb_getdriver getdrv;
|
||||
int ret;
|
||||
|
||||
getdrv.interface = interface;
|
||||
ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv);
|
||||
if (ret)
|
||||
USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno));
|
||||
|
||||
strncpy(name, getdrv.driver, namelen - 1);
|
||||
name[namelen - 1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
|
||||
{
|
||||
struct usb_ioctl command;
|
||||
int ret;
|
||||
|
||||
command.ifno = interface;
|
||||
command.ioctl_code = IOCTL_USB_DISCONNECT;
|
||||
command.data = NULL;
|
||||
|
||||
ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command);
|
||||
if (ret)
|
||||
USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s",
|
||||
interface, strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
#ifndef __LINUX_H__
|
||||
#define __LINUX_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
struct usb_ctrltransfer {
|
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
|
||||
u_int8_t bRequestType;
|
||||
u_int8_t bRequest;
|
||||
u_int16_t wValue;
|
||||
u_int16_t wIndex;
|
||||
u_int16_t wLength;
|
||||
|
||||
u_int32_t timeout; /* in milliseconds */
|
||||
|
||||
/* pointer to data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct usb_bulktransfer {
|
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
|
||||
unsigned int ep;
|
||||
unsigned int len;
|
||||
unsigned int timeout; /* in milliseconds */
|
||||
|
||||
/* pointer to data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct usb_setinterface {
|
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
|
||||
unsigned int interface;
|
||||
unsigned int altsetting;
|
||||
};
|
||||
|
||||
#define USB_MAXDRIVERNAME 255
|
||||
|
||||
struct usb_getdriver {
|
||||
unsigned int interface;
|
||||
char driver[USB_MAXDRIVERNAME + 1];
|
||||
};
|
||||
|
||||
#define USB_URB_DISABLE_SPD 1
|
||||
#define USB_URB_ISO_ASAP 2
|
||||
#define USB_URB_QUEUE_BULK 0x10
|
||||
|
||||
#define USB_URB_TYPE_ISO 0
|
||||
#define USB_URB_TYPE_INTERRUPT 1
|
||||
#define USB_URB_TYPE_CONTROL 2
|
||||
#define USB_URB_TYPE_BULK 3
|
||||
|
||||
struct usb_iso_packet_desc {
|
||||
unsigned int length;
|
||||
unsigned int actual_length;
|
||||
unsigned int status;
|
||||
};
|
||||
|
||||
struct usb_urb {
|
||||
unsigned char type;
|
||||
unsigned char endpoint;
|
||||
int status;
|
||||
unsigned int flags;
|
||||
void *buffer;
|
||||
int buffer_length;
|
||||
int actual_length;
|
||||
int start_frame;
|
||||
int number_of_packets;
|
||||
int error_count;
|
||||
unsigned int signr; /* signal to be sent on error, -1 if none should be sent */
|
||||
void *usercontext;
|
||||
struct usb_iso_packet_desc iso_frame_desc[0];
|
||||
};
|
||||
|
||||
struct usb_connectinfo {
|
||||
unsigned int devnum;
|
||||
unsigned char slow;
|
||||
};
|
||||
|
||||
struct usb_ioctl {
|
||||
int ifno; /* interface 0..N ; negative numbers reserved */
|
||||
int ioctl_code; /* MUST encode size + direction of data so the
|
||||
* macros in <asm/ioctl.h> give correct values */
|
||||
void *data; /* param buffer (in, or out) */
|
||||
};
|
||||
|
||||
struct usb_hub_portinfo {
|
||||
unsigned char numports;
|
||||
unsigned char port[127]; /* port to device num mapping */
|
||||
};
|
||||
|
||||
#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer)
|
||||
#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer)
|
||||
#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int)
|
||||
#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface)
|
||||
#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int)
|
||||
#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver)
|
||||
#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb)
|
||||
#define IOCTL_USB_DISCARDURB _IO('U', 11)
|
||||
#define IOCTL_USB_REAPURB _IOW('U', 12, void *)
|
||||
#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *)
|
||||
#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int)
|
||||
#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int)
|
||||
#define IOCTL_USB_CONNECTINFO _IOW('U', 17, struct usb_connectinfo)
|
||||
#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl)
|
||||
#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct usb_hub_portinfo)
|
||||
#define IOCTL_USB_RESET _IO('U', 20)
|
||||
#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int)
|
||||
#define IOCTL_USB_DISCONNECT _IO('U', 22)
|
||||
#define IOCTL_USB_CONNECT _IO('U', 23)
|
||||
|
||||
/*
|
||||
* IOCTL_USB_HUB_PORTINFO, IOCTL_USB_DISCONNECT and IOCTL_USB_CONNECT
|
||||
* all work via IOCTL_USB_IOCTL
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
-307
@@ -1,307 +0,0 @@
|
||||
/*
|
||||
* Main API entry point
|
||||
*
|
||||
* Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is covered by the LGPL, read LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h> /* getenv */
|
||||
#include <stdio.h> /* stderr */
|
||||
#include <string.h> /* strcmp */
|
||||
#include <errno.h>
|
||||
|
||||
#include "usbi.h"
|
||||
|
||||
int usb_debug = 0;
|
||||
struct usb_bus *usb_busses = NULL;
|
||||
|
||||
int usb_find_busses(void)
|
||||
{
|
||||
struct usb_bus *busses, *bus;
|
||||
int ret, changes = 0;
|
||||
|
||||
ret = usb_os_find_busses(&busses);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Now walk through all of the busses we know about and compare against
|
||||
* this new list. Any duplicates will be removed from the new list.
|
||||
* If we don't find it in the new list, the bus was removed. Any
|
||||
* busses still in the new list, are new to us.
|
||||
*/
|
||||
bus = usb_busses;
|
||||
while (bus) {
|
||||
int found = 0;
|
||||
struct usb_bus *nbus, *tbus = bus->next;
|
||||
|
||||
nbus = busses;
|
||||
while (nbus) {
|
||||
struct usb_bus *tnbus = nbus->next;
|
||||
|
||||
if (!strcmp(bus->dirname, nbus->dirname)) {
|
||||
/* Remove it from the new busses list */
|
||||
LIST_DEL(busses, nbus);
|
||||
|
||||
usb_free_bus(nbus);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
nbus = tnbus;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* The bus was removed from the system */
|
||||
LIST_DEL(usb_busses, bus);
|
||||
usb_free_bus(bus);
|
||||
changes++;
|
||||
}
|
||||
|
||||
bus = tbus;
|
||||
}
|
||||
|
||||
/*
|
||||
* Anything on the *busses list is new. So add them to usb_busses and
|
||||
* process them like the new bus it is.
|
||||
*/
|
||||
bus = busses;
|
||||
while (bus) {
|
||||
struct usb_bus *tbus = bus->next;
|
||||
|
||||
/*
|
||||
* Remove it from the temporary list first and add it to the real
|
||||
* usb_busses list.
|
||||
*/
|
||||
LIST_DEL(busses, bus);
|
||||
|
||||
LIST_ADD(usb_busses, bus);
|
||||
|
||||
changes++;
|
||||
|
||||
bus = tbus;
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
int usb_find_devices(void)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
int ret, changes = 0;
|
||||
|
||||
for (bus = usb_busses; bus; bus = bus->next) {
|
||||
struct usb_device *devices, *dev;
|
||||
|
||||
/* Find all of the devices and put them into a temporary list */
|
||||
ret = usb_os_find_devices(bus, &devices);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Now walk through all of the devices we know about and compare
|
||||
* against this new list. Any duplicates will be removed from the new
|
||||
* list. If we don't find it in the new list, the device was removed.
|
||||
* Any devices still in the new list, are new to us.
|
||||
*/
|
||||
dev = bus->devices;
|
||||
while (dev) {
|
||||
int found = 0;
|
||||
struct usb_device *ndev, *tdev = dev->next;
|
||||
|
||||
ndev = devices;
|
||||
while (ndev) {
|
||||
struct usb_device *tndev = ndev->next;
|
||||
|
||||
if (!strcmp(dev->filename, ndev->filename)) {
|
||||
/* Remove it from the new devices list */
|
||||
LIST_DEL(devices, ndev);
|
||||
|
||||
usb_free_dev(ndev);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ndev = tndev;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* The device was removed from the system */
|
||||
LIST_DEL(bus->devices, dev);
|
||||
usb_free_dev(dev);
|
||||
changes++;
|
||||
}
|
||||
|
||||
dev = tdev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Anything on the *devices list is new. So add them to bus->devices and
|
||||
* process them like the new device it is.
|
||||
*/
|
||||
dev = devices;
|
||||
while (dev) {
|
||||
struct usb_device *tdev = dev->next;
|
||||
|
||||
/*
|
||||
* Remove it from the temporary list first and add it to the real
|
||||
* bus->devices list.
|
||||
*/
|
||||
LIST_DEL(devices, dev);
|
||||
|
||||
LIST_ADD(bus->devices, dev);
|
||||
|
||||
/*
|
||||
* Some ports fetch the descriptors on scanning (like Linux) so we don't
|
||||
* need to fetch them again.
|
||||
*/
|
||||
if (!dev->config) {
|
||||
usb_dev_handle *udev;
|
||||
|
||||
udev = usb_open(dev);
|
||||
if (udev) {
|
||||
usb_fetch_and_parse_descriptors(udev);
|
||||
|
||||
usb_close(udev);
|
||||
}
|
||||
}
|
||||
|
||||
changes++;
|
||||
|
||||
dev = tdev;
|
||||
}
|
||||
|
||||
usb_os_determine_children(bus);
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
void usb_set_debug(int level)
|
||||
{
|
||||
if (usb_debug || level)
|
||||
fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
|
||||
level, level ? "on" : "off");
|
||||
|
||||
usb_debug = level;
|
||||
}
|
||||
|
||||
void usb_init(void)
|
||||
{
|
||||
if (getenv("USB_DEBUG"))
|
||||
usb_set_debug(atoi(getenv("USB_DEBUG")));
|
||||
|
||||
usb_os_init();
|
||||
}
|
||||
|
||||
usb_dev_handle *usb_open(struct usb_device *dev)
|
||||
{
|
||||
usb_dev_handle *udev;
|
||||
|
||||
udev = malloc(sizeof(*udev));
|
||||
if (!udev)
|
||||
return NULL;
|
||||
|
||||
udev->fd = -1;
|
||||
udev->device = dev;
|
||||
udev->bus = dev->bus;
|
||||
udev->config = udev->interface = udev->altsetting = -1;
|
||||
|
||||
if (usb_os_open(udev) < 0) {
|
||||
free(udev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return udev;
|
||||
}
|
||||
|
||||
int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
/*
|
||||
* We can't use usb_get_descriptor() because it's lacking the index
|
||||
* parameter. This will be fixed in libusb 1.0
|
||||
*/
|
||||
return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
|
||||
(USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
|
||||
}
|
||||
|
||||
int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
|
||||
{
|
||||
char tbuf[255]; /* Some devices choke on size > 255 */
|
||||
int ret, langid, si, di;
|
||||
|
||||
/*
|
||||
* Asking for the zero'th index is special - it returns a string
|
||||
* descriptor that contains all the language IDs supported by the
|
||||
* device. Typically there aren't many - often only one. The
|
||||
* language IDs are 16 bit numbers, and they start at the third byte
|
||||
* in the descriptor. See USB 2.0 specification, section 9.6.7, for
|
||||
* more information on this. */
|
||||
ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret < 4)
|
||||
return -EIO;
|
||||
|
||||
langid = tbuf[2] | (tbuf[3] << 8);
|
||||
|
||||
ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (tbuf[1] != USB_DT_STRING)
|
||||
return -EIO;
|
||||
|
||||
if (tbuf[0] > ret)
|
||||
return -EFBIG;
|
||||
|
||||
for (di = 0, si = 2; si < tbuf[0]; si += 2) {
|
||||
if (di >= (buflen - 1))
|
||||
break;
|
||||
|
||||
if (tbuf[si + 1]) /* high byte */
|
||||
buf[di++] = '?';
|
||||
else
|
||||
buf[di++] = tbuf[si];
|
||||
}
|
||||
|
||||
buf[di] = 0;
|
||||
|
||||
return di;
|
||||
}
|
||||
|
||||
int usb_close(usb_dev_handle *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_os_close(dev);
|
||||
free(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct usb_device *usb_device(usb_dev_handle *dev)
|
||||
{
|
||||
return dev->device;
|
||||
}
|
||||
|
||||
void usb_free_dev(struct usb_device *dev)
|
||||
{
|
||||
usb_destroy_configuration(dev);
|
||||
free(dev->children);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
struct usb_bus *usb_get_busses(void)
|
||||
{
|
||||
return usb_busses;
|
||||
}
|
||||
|
||||
void usb_free_bus(struct usb_bus *bus)
|
||||
{
|
||||
free(bus);
|
||||
}
|
||||
|
||||
-337
@@ -1,337 +0,0 @@
|
||||
/*
|
||||
* Prototypes, structure definitions and macros.
|
||||
*
|
||||
* Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is covered by the LGPL, read LICENSE for details.
|
||||
*
|
||||
* This file (and only this file) may alternatively be licensed under the
|
||||
* BSD license as well, read LICENSE for details.
|
||||
*/
|
||||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
/*
|
||||
* USB spec information
|
||||
*
|
||||
* This is all stuff grabbed from various USB specs and is pretty much
|
||||
* not subject to change
|
||||
*/
|
||||
|
||||
/*
|
||||
* Device and/or Interface Class codes
|
||||
*/
|
||||
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
|
||||
#define USB_CLASS_AUDIO 1
|
||||
#define USB_CLASS_COMM 2
|
||||
#define USB_CLASS_HID 3
|
||||
#define USB_CLASS_PRINTER 7
|
||||
#define USB_CLASS_PTP 6
|
||||
#define USB_CLASS_MASS_STORAGE 8
|
||||
#define USB_CLASS_HUB 9
|
||||
#define USB_CLASS_DATA 10
|
||||
#define USB_CLASS_VENDOR_SPEC 0xff
|
||||
|
||||
/*
|
||||
* Descriptor types
|
||||
*/
|
||||
#define USB_DT_DEVICE 0x01
|
||||
#define USB_DT_CONFIG 0x02
|
||||
#define USB_DT_STRING 0x03
|
||||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
|
||||
#define USB_DT_HID 0x21
|
||||
#define USB_DT_REPORT 0x22
|
||||
#define USB_DT_PHYSICAL 0x23
|
||||
#define USB_DT_HUB 0x29
|
||||
|
||||
/*
|
||||
* Descriptor sizes per descriptor type
|
||||
*/
|
||||
#define USB_DT_DEVICE_SIZE 18
|
||||
#define USB_DT_CONFIG_SIZE 9
|
||||
#define USB_DT_INTERFACE_SIZE 9
|
||||
#define USB_DT_ENDPOINT_SIZE 7
|
||||
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
|
||||
#define USB_DT_HUB_NONVAR_SIZE 7
|
||||
|
||||
/* All standard descriptors have these 2 fields in common */
|
||||
struct usb_descriptor_header {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
};
|
||||
|
||||
/* String descriptor */
|
||||
struct usb_string_descriptor {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
u_int16_t wData[1];
|
||||
};
|
||||
|
||||
/* HID descriptor */
|
||||
struct usb_hid_descriptor {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
u_int16_t bcdHID;
|
||||
u_int8_t bCountryCode;
|
||||
u_int8_t bNumDescriptors;
|
||||
/* u_int8_t bReportDescriptorType; */
|
||||
/* u_int16_t wDescriptorLength; */
|
||||
/* ... */
|
||||
};
|
||||
|
||||
/* Endpoint descriptor */
|
||||
#define USB_MAXENDPOINTS 32
|
||||
struct usb_endpoint_descriptor {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
u_int8_t bEndpointAddress;
|
||||
u_int8_t bmAttributes;
|
||||
u_int16_t wMaxPacketSize;
|
||||
u_int8_t bInterval;
|
||||
u_int8_t bRefresh;
|
||||
u_int8_t bSynchAddress;
|
||||
|
||||
unsigned char *extra; /* Extra descriptors */
|
||||
int extralen;
|
||||
};
|
||||
|
||||
#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
|
||||
#define USB_ENDPOINT_DIR_MASK 0x80
|
||||
|
||||
#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */
|
||||
#define USB_ENDPOINT_TYPE_CONTROL 0
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
|
||||
#define USB_ENDPOINT_TYPE_BULK 2
|
||||
#define USB_ENDPOINT_TYPE_INTERRUPT 3
|
||||
|
||||
/* Interface descriptor */
|
||||
#define USB_MAXINTERFACES 32
|
||||
struct usb_interface_descriptor {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
u_int8_t bInterfaceNumber;
|
||||
u_int8_t bAlternateSetting;
|
||||
u_int8_t bNumEndpoints;
|
||||
u_int8_t bInterfaceClass;
|
||||
u_int8_t bInterfaceSubClass;
|
||||
u_int8_t bInterfaceProtocol;
|
||||
u_int8_t iInterface;
|
||||
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
|
||||
unsigned char *extra; /* Extra descriptors */
|
||||
int extralen;
|
||||
};
|
||||
|
||||
#define USB_MAXALTSETTING 128 /* Hard limit */
|
||||
struct usb_interface {
|
||||
struct usb_interface_descriptor *altsetting;
|
||||
|
||||
int num_altsetting;
|
||||
};
|
||||
|
||||
/* Configuration descriptor information.. */
|
||||
#define USB_MAXCONFIG 8
|
||||
struct usb_config_descriptor {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
u_int16_t wTotalLength;
|
||||
u_int8_t bNumInterfaces;
|
||||
u_int8_t bConfigurationValue;
|
||||
u_int8_t iConfiguration;
|
||||
u_int8_t bmAttributes;
|
||||
u_int8_t MaxPower;
|
||||
|
||||
struct usb_interface *interface;
|
||||
|
||||
unsigned char *extra; /* Extra descriptors */
|
||||
int extralen;
|
||||
};
|
||||
|
||||
/* Device descriptor */
|
||||
struct usb_device_descriptor {
|
||||
u_int8_t bLength;
|
||||
u_int8_t bDescriptorType;
|
||||
u_int16_t bcdUSB;
|
||||
u_int8_t bDeviceClass;
|
||||
u_int8_t bDeviceSubClass;
|
||||
u_int8_t bDeviceProtocol;
|
||||
u_int8_t bMaxPacketSize0;
|
||||
u_int16_t idVendor;
|
||||
u_int16_t idProduct;
|
||||
u_int16_t bcdDevice;
|
||||
u_int8_t iManufacturer;
|
||||
u_int8_t iProduct;
|
||||
u_int8_t iSerialNumber;
|
||||
u_int8_t bNumConfigurations;
|
||||
};
|
||||
|
||||
struct usb_ctrl_setup {
|
||||
u_int8_t bRequestType;
|
||||
u_int8_t bRequest;
|
||||
u_int16_t wValue;
|
||||
u_int16_t wIndex;
|
||||
u_int16_t wLength;
|
||||
};
|
||||
|
||||
/*
|
||||
* Standard requests
|
||||
*/
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
/* 0x02 is reserved */
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
/* 0x04 is reserved */
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
|
||||
#define USB_TYPE_STANDARD (0x00 << 5)
|
||||
#define USB_TYPE_CLASS (0x01 << 5)
|
||||
#define USB_TYPE_VENDOR (0x02 << 5)
|
||||
#define USB_TYPE_RESERVED (0x03 << 5)
|
||||
|
||||
#define USB_RECIP_DEVICE 0x00
|
||||
#define USB_RECIP_INTERFACE 0x01
|
||||
#define USB_RECIP_ENDPOINT 0x02
|
||||
#define USB_RECIP_OTHER 0x03
|
||||
|
||||
/*
|
||||
* Various libusb API related stuff
|
||||
*/
|
||||
|
||||
#define USB_ENDPOINT_IN 0x80
|
||||
#define USB_ENDPOINT_OUT 0x00
|
||||
|
||||
/* Error codes */
|
||||
#define USB_ERROR_BEGIN 500000
|
||||
|
||||
/*
|
||||
* This is supposed to look weird. This file is generated from autoconf
|
||||
* and I didn't want to make this too complicated.
|
||||
*/
|
||||
#if 0
|
||||
#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0)
|
||||
#else
|
||||
#define USB_LE16_TO_CPU(x)
|
||||
#endif
|
||||
|
||||
/* Data types */
|
||||
struct usb_device;
|
||||
struct usb_bus;
|
||||
|
||||
/*
|
||||
* To maintain compatibility with applications already built with libusb,
|
||||
* we must only add entries to the end of this structure. NEVER delete or
|
||||
* move members and only change types if you really know what you're doing.
|
||||
*/
|
||||
struct usb_device {
|
||||
struct usb_device *next, *prev;
|
||||
|
||||
char filename[PATH_MAX + 1];
|
||||
|
||||
struct usb_bus *bus;
|
||||
|
||||
struct usb_device_descriptor descriptor;
|
||||
struct usb_config_descriptor *config;
|
||||
|
||||
void *dev; /* Darwin support */
|
||||
|
||||
u_int8_t devnum;
|
||||
|
||||
unsigned char num_children;
|
||||
struct usb_device **children;
|
||||
};
|
||||
|
||||
struct usb_bus {
|
||||
struct usb_bus *next, *prev;
|
||||
|
||||
char dirname[PATH_MAX + 1];
|
||||
|
||||
struct usb_device *devices;
|
||||
u_int32_t location;
|
||||
|
||||
struct usb_device *root_dev;
|
||||
};
|
||||
|
||||
struct usb_dev_handle;
|
||||
typedef struct usb_dev_handle usb_dev_handle;
|
||||
|
||||
/* Variables */
|
||||
extern struct usb_bus *usb_busses;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/* usb.c */
|
||||
usb_dev_handle *usb_open(struct usb_device *dev);
|
||||
int usb_close(usb_dev_handle *dev);
|
||||
int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
|
||||
size_t buflen);
|
||||
int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
/* descriptors.c */
|
||||
int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
|
||||
unsigned char type, unsigned char index, void *buf, int size);
|
||||
int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
|
||||
unsigned char index, void *buf, int size);
|
||||
|
||||
/* <arch>.c */
|
||||
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
|
||||
int value, int index, char *bytes, int size, int timeout);
|
||||
int usb_set_configuration(usb_dev_handle *dev, int configuration);
|
||||
int usb_claim_interface(usb_dev_handle *dev, int interface);
|
||||
int usb_release_interface(usb_dev_handle *dev, int interface);
|
||||
int usb_set_altinterface(usb_dev_handle *dev, int alternate);
|
||||
int usb_resetep(usb_dev_handle *dev, unsigned int ep);
|
||||
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
|
||||
int usb_reset(usb_dev_handle *dev);
|
||||
|
||||
#if 1
|
||||
#define LIBUSB_HAS_GET_DRIVER_NP 1
|
||||
int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
|
||||
unsigned int namelen);
|
||||
#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1
|
||||
int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
|
||||
#endif
|
||||
|
||||
char *usb_strerror(void);
|
||||
|
||||
void usb_init(void);
|
||||
void usb_set_debug(int level);
|
||||
int usb_find_busses(void);
|
||||
int usb_find_devices(void);
|
||||
struct usb_device *usb_device(usb_dev_handle *dev);
|
||||
struct usb_bus *usb_get_busses(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USB_H__ */
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#ifndef _USBI_H_
|
||||
#define _USBI_H_
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#include "error.h"
|
||||
|
||||
extern int usb_debug;
|
||||
|
||||
/* Some quick and generic macros for the simple kind of lists we use */
|
||||
#define LIST_ADD(begin, ent) \
|
||||
do { \
|
||||
if (begin) { \
|
||||
ent->next = begin; \
|
||||
ent->next->prev = ent; \
|
||||
} else \
|
||||
ent->next = NULL; \
|
||||
ent->prev = NULL; \
|
||||
begin = ent; \
|
||||
} while(0)
|
||||
|
||||
#define LIST_DEL(begin, ent) \
|
||||
do { \
|
||||
if (ent->prev) \
|
||||
ent->prev->next = ent->next; \
|
||||
else \
|
||||
begin = ent->next; \
|
||||
if (ent->next) \
|
||||
ent->next->prev = ent->prev; \
|
||||
ent->prev = NULL; \
|
||||
ent->next = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define DESC_HEADER_LENGTH 2
|
||||
#define DEVICE_DESC_LENGTH 18
|
||||
#define CONFIG_DESC_LENGTH 9
|
||||
#define INTERFACE_DESC_LENGTH 9
|
||||
#define ENDPOINT_DESC_LENGTH 7
|
||||
#define ENDPOINT_AUDIO_DESC_LENGTH 9
|
||||
|
||||
struct usb_dev_handle {
|
||||
int fd;
|
||||
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *device;
|
||||
|
||||
int config;
|
||||
int interface;
|
||||
int altsetting;
|
||||
|
||||
/* Added by RMT so implementations can store other per-open-device data */
|
||||
void *impl_info;
|
||||
};
|
||||
|
||||
/* descriptors.c */
|
||||
int usb_parse_descriptor(unsigned char *source, char *description, void *dest);
|
||||
int usb_parse_configuration(struct usb_config_descriptor *config,
|
||||
unsigned char *buffer);
|
||||
void usb_fetch_and_parse_descriptors(usb_dev_handle *udev);
|
||||
void usb_destroy_configuration(struct usb_device *dev);
|
||||
|
||||
/* OS specific routines */
|
||||
int usb_os_find_busses(struct usb_bus **busses);
|
||||
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices);
|
||||
int usb_os_determine_children(struct usb_bus *bus);
|
||||
void usb_os_init(void);
|
||||
int usb_os_open(usb_dev_handle *dev);
|
||||
int usb_os_close(usb_dev_handle *dev);
|
||||
|
||||
void usb_free_dev(struct usb_device *dev);
|
||||
void usb_free_bus(struct usb_bus *bus);
|
||||
|
||||
#endif /* _USBI_H_ */
|
||||
|
||||
-855
@@ -1,855 +0,0 @@
|
||||
// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*-
|
||||
#ifndef __USBPP_HEADER__
|
||||
#define __USBPP_HEADER__
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
/*
|
||||
* The following usb.h function is not wrapped yet:
|
||||
* char *usb_strerror(void);
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \brief Classes to access Universal Serial Bus devices
|
||||
*
|
||||
* The USB Namespace provides a number of classes to work
|
||||
* with Universal Serial Bus (USB) devices attached to the
|
||||
* system.
|
||||
*
|
||||
* \author Brad Hards
|
||||
*/
|
||||
namespace USB {
|
||||
|
||||
class Device;
|
||||
|
||||
/**
|
||||
* \brief Class representing a device endpoint
|
||||
*
|
||||
* This class represents a device endpoint. You need this class to
|
||||
* perform bulk reads and writes.
|
||||
*
|
||||
*/
|
||||
class Endpoint {
|
||||
/**
|
||||
* Busses is a friend because it fills in the descriptor type
|
||||
* information on initialisation and rescan.
|
||||
*/
|
||||
friend class Busses;
|
||||
public:
|
||||
Endpoint() {};
|
||||
|
||||
#ifdef USE_UNTESTED_LIBUSBPP_METHODS
|
||||
/**
|
||||
* \brief Bulk write
|
||||
*
|
||||
* This method performs a bulk transfer to the endpoint.
|
||||
*
|
||||
* \param message is the message to be sent.
|
||||
* \param timeout is the USB transaction timeout in milliseconds
|
||||
*
|
||||
* \returns the number of bytes sent, or a negative value on
|
||||
* failure
|
||||
*/
|
||||
int bulkWrite(QByteArray message, int timeout = 100);
|
||||
|
||||
/**
|
||||
* \brief Bulk read
|
||||
*
|
||||
* This method performs a bulk transfer from the endpoint.
|
||||
*
|
||||
* \param length is the maximum data transfer required.
|
||||
* \param message is the message that was received.
|
||||
* \param timeout is the USB transaction timeout in milliseconds
|
||||
*
|
||||
* \returns the number of bytes received, or a negative value on
|
||||
* failure
|
||||
*/
|
||||
int bulkRead(int length, unsigned char *message, int timeout = 100);
|
||||
|
||||
/**
|
||||
* \brief Reset endpoint
|
||||
*
|
||||
* This method resets the endpoint.
|
||||
*/
|
||||
int reset(void);
|
||||
|
||||
/**
|
||||
* \brief Clear halt
|
||||
*
|
||||
* This method clears a halt (stall) on the endpoint.
|
||||
*/
|
||||
int clearHalt(void);
|
||||
|
||||
#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
|
||||
|
||||
/**
|
||||
* \brief Endpoint descriptor information output
|
||||
*
|
||||
* This method dumps out the various characteristics
|
||||
* of the endpoint to standard output.
|
||||
*
|
||||
* It is mostly useful for debugging.
|
||||
*/
|
||||
void dumpDescriptor(void);
|
||||
|
||||
private:
|
||||
void setDescriptor(struct usb_endpoint_descriptor);
|
||||
void setParent(Device *parent);
|
||||
u_int8_t m_Length;
|
||||
u_int8_t m_DescriptorType;
|
||||
u_int8_t m_EndpointAddress;
|
||||
u_int8_t m_Attributes;
|
||||
u_int16_t m_MaxPacketSize;
|
||||
u_int8_t m_Interval;
|
||||
u_int8_t m_Refresh;
|
||||
u_int8_t m_SynchAddress;
|
||||
Device *m_parent;
|
||||
};
|
||||
|
||||
class AltSetting : public std::list<Endpoint *> {
|
||||
/**
|
||||
* Busses is a friend because it fills in the descriptor type
|
||||
* information on initialisation and rescan.
|
||||
*/
|
||||
friend class Busses;
|
||||
public:
|
||||
AltSetting() {};
|
||||
u_int8_t numEndpoints(void);
|
||||
|
||||
/**
|
||||
* \brief AltSetting descriptor information output
|
||||
*
|
||||
* This method dumps out the various characteristics
|
||||
* of the alternate setting to standard output.
|
||||
*
|
||||
* It is mostly useful for debugging.
|
||||
*/
|
||||
void dumpDescriptor(void);
|
||||
|
||||
Endpoint *firstEndpoint(void);
|
||||
Endpoint *nextEndpoint(void);
|
||||
Endpoint *lastEndpoint(void);
|
||||
|
||||
private:
|
||||
std::list<Endpoint *>::const_iterator iter;
|
||||
|
||||
void setDescriptor(struct usb_interface_descriptor);
|
||||
/* we don't use a normal usb_interface_descriptor */
|
||||
/* because that would bring in the endpoint list */
|
||||
u_int8_t m_Length;
|
||||
u_int8_t m_DescriptorType;
|
||||
u_int8_t m_InterfaceNumber;
|
||||
u_int8_t m_AlternateSetting;
|
||||
u_int8_t m_NumEndpoints;
|
||||
u_int8_t m_InterfaceClass;
|
||||
u_int8_t m_InterfaceSubClass;
|
||||
u_int8_t m_InterfaceProtocol;
|
||||
u_int8_t m_Interface;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class representing an interface of a Device
|
||||
*
|
||||
* The Interface class represents a USB interface
|
||||
* for a device attached to a Universal Serial Bus.
|
||||
*
|
||||
* Interfaces are the main element of the USB class
|
||||
* structure.
|
||||
*
|
||||
* \author Brad Hards
|
||||
*/
|
||||
class Interface : public std::list<AltSetting *> {
|
||||
/**
|
||||
* Busses is a friend because it fills in the descriptor type
|
||||
* information on initialisation and rescan.
|
||||
*/
|
||||
friend class Busses;
|
||||
public:
|
||||
Interface() {};
|
||||
|
||||
#ifdef LIBUSB_HAS_GET_DRIVER_NP
|
||||
/**
|
||||
* \brief get the current driver for an interface
|
||||
*
|
||||
* \param driver a string containing the name of the current
|
||||
* driver for the interface. You can typically pass in an empty
|
||||
* string for this.
|
||||
*
|
||||
* \return length of string, or 0 on error.
|
||||
*/
|
||||
int driverName(std::string &driver);
|
||||
#endif
|
||||
|
||||
#ifdef USE_UNTESTED_LIBUSBPP_METHODS
|
||||
/**
|
||||
* \brief Claim this interface
|
||||
*
|
||||
* This method claims the interface. You have to claim the
|
||||
* interface before performing any operations on the interface (or
|
||||
* on endpoints that are part of the interface).
|
||||
*
|
||||
* \return 0 on success or negative number on error.
|
||||
*/
|
||||
int claim(void);
|
||||
|
||||
/**
|
||||
* \brief Release this interface
|
||||
*
|
||||
* This method releases the interface. You should release the
|
||||
* interface after all operations on it (and any lower level
|
||||
* endpoints) are completed.
|
||||
*
|
||||
* \return 0 on success or negative number on error.
|
||||
*/
|
||||
int release(void);
|
||||
|
||||
/**
|
||||
* \brief Set interface alternate setting
|
||||
*
|
||||
* This method sets the interface to a particular AltSetting.
|
||||
*
|
||||
* \param altSettingNumber the AltSetting that the interface
|
||||
* should be changed to.
|
||||
*
|
||||
* \return 0 on success, or a negative number in case of error.
|
||||
*/
|
||||
int setAltSetting(int altSettingNumber);
|
||||
#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
|
||||
|
||||
/**
|
||||
* \brief Number of Alternative Settings that this interface has
|
||||
*
|
||||
* This is a simple accessor method that specifies the number
|
||||
* alternative settings that this device interface has.
|
||||
*/
|
||||
u_int8_t numAltSettings(void);
|
||||
|
||||
/**
|
||||
* \brief First AltSetting for the Interface
|
||||
*
|
||||
* This method returns a pointer to the first AltSetting
|
||||
* for the Interface.
|
||||
*
|
||||
* See nextAltSetting() for an example of how it might be
|
||||
* used.
|
||||
*
|
||||
* \see nextAltSetting(), lastAltSetting(), numAltSettings()
|
||||
*/
|
||||
AltSetting *firstAltSetting(void);
|
||||
|
||||
/**
|
||||
* \brief Next AltSetting for the Interface
|
||||
*
|
||||
* This method returns a pointer to the next AltSetting
|
||||
* for the Interface.
|
||||
*
|
||||
* If you want to iterate through each AltSetting on
|
||||
* a device, you can use something like the following:
|
||||
* \code
|
||||
* USB::Configuration *this_Configuration;
|
||||
* this_Configuration = device->firstConfiguration();
|
||||
* for (i=0; i < device->numConfigurations(); i++) {
|
||||
* this_Configuration->dumpDescriptor();
|
||||
* USB::Interface *this_Interface;
|
||||
* this_Interface = this_Configuration->firstInterface();
|
||||
* for (j=0; j < this_Configuration->numInterfaces(); j++) {
|
||||
* USB::AltSetting *this_AltSetting;
|
||||
* this_AltSetting = this_Interface->firstAltSetting();
|
||||
* for (k=0; k < this_Interface->numAltSettings(); k++) {
|
||||
* // do something with this_AltSetting
|
||||
* this_AltSetting = this_Interface->nextAltSetting();
|
||||
* }
|
||||
* this_Interface = this_Configuration->nextInterface();
|
||||
* }
|
||||
* this_Configuration = device->nextConfiguration();
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \see firstAltSetting(), lastAltSetting(), numAltSettings()
|
||||
*/
|
||||
AltSetting *nextAltSetting(void);
|
||||
|
||||
/**
|
||||
* \brief Last AltSetting for the Interface
|
||||
*
|
||||
* This method returns a pointer to the last AltSetting
|
||||
* for the Interface.
|
||||
*
|
||||
* \see firstAltSetting(), nextAltSetting(), numAltSettings()
|
||||
*/
|
||||
|
||||
AltSetting *lastAltSetting(void);
|
||||
|
||||
private:
|
||||
std::list<AltSetting *>::const_iterator iter;
|
||||
|
||||
void setNumAltSettings(u_int8_t);
|
||||
void setParent(Device *parent);
|
||||
u_int8_t m_numAltSettings;
|
||||
Device *m_parent;
|
||||
|
||||
/* index representing the interface, in this configuration */
|
||||
int m_interfaceNumber;
|
||||
void setInterfaceNumber(int interfaceNumber);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class representing a configuration of a Device
|
||||
*
|
||||
* The Configuration class represents a single configuration
|
||||
* of a device attached to a Universal Serial Bus.
|
||||
*
|
||||
* \author Brad Hards
|
||||
*/
|
||||
class Configuration : public std::list<Interface *> {
|
||||
/**
|
||||
* Busses is a friend because it fills in the descriptor type
|
||||
* information on initialisation and rescan.
|
||||
*/
|
||||
friend class Busses;
|
||||
public:
|
||||
Configuration() {};
|
||||
|
||||
/**
|
||||
* \brief Configuration descriptor information output
|
||||
*
|
||||
* This method dumps out the various characteristics
|
||||
* of the configuration to standard output.
|
||||
*
|
||||
* It is mostly useful for debugging.
|
||||
*/
|
||||
void dumpDescriptor(void);
|
||||
|
||||
/**
|
||||
* \brief Number of Interfaces that this device has
|
||||
*
|
||||
* This is a simple accessor method that specifies the number
|
||||
* Interfaces that this device configuration has.
|
||||
*/
|
||||
u_int8_t numInterfaces(void);
|
||||
|
||||
/**
|
||||
* \brief First Interface for the Configuration
|
||||
*
|
||||
* This method returns a pointer to the first Interface
|
||||
* for the Configuration.
|
||||
*
|
||||
* See nextInterface() for an example of how it might be
|
||||
* used.
|
||||
*
|
||||
* \see nextInterface(), lastInterface(), numInterfaces()
|
||||
*/
|
||||
Interface *firstInterface(void);
|
||||
|
||||
/**
|
||||
* \brief Next Interface for the Configuration
|
||||
*
|
||||
* This method returns a pointer to the next Interface
|
||||
* for the Configuration.
|
||||
*
|
||||
* If you want to iterate through each Interface on
|
||||
* a device, you can use something like the following:
|
||||
* \code
|
||||
* USB::Configuration *this_Configuration;
|
||||
* this_Configuration = device->firstConfiguration();
|
||||
* for (i=0; i < device->numConfigurations(); i++) {
|
||||
* this_Interface = this_Configuration->firstInterface();
|
||||
* for (j=0; j < this_Configuration->numInterfaces(); j++) {
|
||||
* // do something with this_Interface
|
||||
* this_Interface = this_Configuration->nextInterface();
|
||||
* }
|
||||
* this_Configuration->nextConfiguration();
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \see firstInterface(), lastInterface(), numInterfaces()
|
||||
*/
|
||||
Interface *nextInterface(void);
|
||||
|
||||
/**
|
||||
* \brief Last Interface for the Configuration
|
||||
*
|
||||
* This method returns a pointer to the last Interface
|
||||
* for the Configuration.
|
||||
*
|
||||
* \see firstInterface(), nextInterface(), numInterfaces()
|
||||
*/
|
||||
Interface *lastInterface(void);
|
||||
|
||||
private:
|
||||
std::list<Interface *>::const_iterator iter;
|
||||
|
||||
void setDescriptor(struct usb_config_descriptor);
|
||||
/* we don't use a normal usb_config_descriptor */
|
||||
/* because that would bring in the interface list */
|
||||
u_int8_t m_Length;
|
||||
u_int8_t m_DescriptorType;
|
||||
u_int16_t m_TotalLength;
|
||||
u_int8_t m_NumInterfaces;
|
||||
u_int8_t m_ConfigurationValue;
|
||||
u_int8_t m_Configuration;
|
||||
u_int8_t m_Attributes;
|
||||
u_int8_t m_MaxPower;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class representing a Device on the Bus
|
||||
*
|
||||
* The Device class represents a single device
|
||||
* attached to a Universal Serial Bus.
|
||||
*
|
||||
* \author Brad Hards
|
||||
*/
|
||||
class Device : public std::list<Configuration *> {
|
||||
/**
|
||||
* Busses is a friend because it fills in the descriptor type
|
||||
* information on initialisation and rescan.
|
||||
*/
|
||||
friend class Busses;
|
||||
/**
|
||||
* Interface is a friend because it needs the handle() function to
|
||||
* perform claim(), release().
|
||||
*/
|
||||
friend class Interface;
|
||||
/**
|
||||
* Endpoint is a friend because it needs the handle() function to
|
||||
* perform reads, writes, and other transactions.
|
||||
*/
|
||||
friend class Endpoint;
|
||||
|
||||
public:
|
||||
Device() {};
|
||||
~Device();
|
||||
|
||||
/**
|
||||
* \brief OS representation of filename for this device
|
||||
*
|
||||
* libusb++ provides a uniform way of accessing USB
|
||||
* devices irrespective of the underlying Operation System
|
||||
* representation. If you want to map the libusb++ representation
|
||||
* to the Operating System representation, you can do this
|
||||
* with filename().
|
||||
*
|
||||
* On Linux, the filename is usually something like 002, which
|
||||
* represents the second device (usually the first real device,
|
||||
* after the root hub pseudo-device) on the bus.
|
||||
*
|
||||
* \see Bus::directoryName()
|
||||
*/
|
||||
std::string fileName(void);
|
||||
|
||||
/**
|
||||
* \brief The vendor ID number, as provided by the device.
|
||||
*
|
||||
* This method returns a number containing the vendor
|
||||
* (manufacturer) identification number. These are allocated
|
||||
* by the USB Implementers Forum, and you can construct a
|
||||
* lookup based on the number to get the manufacturer's name,
|
||||
* even if the device does not contain a vendor string.
|
||||
*
|
||||
* \see Vendor()
|
||||
*/
|
||||
u_int16_t idVendor(void);
|
||||
|
||||
/**
|
||||
* \brief The product ID number, as provided by the device.
|
||||
*
|
||||
* This method returns a number containing the product
|
||||
* identification number. These are allocated
|
||||
* by the manufacturer, and should be different on each device.
|
||||
*
|
||||
* \see Product()
|
||||
*/
|
||||
u_int16_t idProduct(void);
|
||||
|
||||
/**
|
||||
* \brief The product's revision ID, as provided by the device.
|
||||
*
|
||||
* This method returns a number containing the product's revision.
|
||||
* This revision level is nominally binary coded decimal, but
|
||||
* hexadecimal revision levels are not uncommon. The binary coded
|
||||
* decimal version nominally has a major version in the high byte,
|
||||
* and a minor version in the low byte.
|
||||
*/
|
||||
u_int16_t idRevision(void);
|
||||
|
||||
/**
|
||||
* \brief The device's USB class, as provided by the device.
|
||||
*
|
||||
* This method returns a number containing the device's class.
|
||||
* These are defined by the USB Implementer's Forum.
|
||||
*
|
||||
* A code of Zero is special (and common) - it means that the
|
||||
* class is found in the Interface descriptor, rather than in the
|
||||
* Device descriptor.
|
||||
*
|
||||
* A code of 0xFF is also special (and far too common) - it means
|
||||
* that the manufacturer didn't conform to one of the defined
|
||||
* class specifications, and chose to implement a vendor specified
|
||||
* protocol.
|
||||
*
|
||||
*/
|
||||
u_int8_t devClass(void);
|
||||
|
||||
/**
|
||||
* \brief The device's USB subclass, as provided by the device.
|
||||
*
|
||||
* This method returns a number containing the device's subclass.
|
||||
* These subclasses are defined by the USB Implementer's Forum,
|
||||
* and only have meaning in the context of a specified class.
|
||||
*/
|
||||
u_int8_t devSubClass(void);
|
||||
|
||||
/**
|
||||
* \brief The device's USB protocol, as provided by the device.
|
||||
*
|
||||
* This method returns a number containing the device's protocol.
|
||||
* These protocols are defined by the USB Implementer's Forum, and
|
||||
* only have meaning in the context of a specified class and
|
||||
* subclass.
|
||||
*/
|
||||
u_int8_t devProtocol(void);
|
||||
|
||||
|
||||
/**
|
||||
* \brief The vendor name string, as provided by the device.
|
||||
*
|
||||
* This method returns a string containing the name of the
|
||||
* device's vendor (manufacturer), as encoded into the device.
|
||||
*
|
||||
* Note that not all devices contain a vendor name, and also
|
||||
* that under some operating systems you may not be able to
|
||||
* read the vendor name without elevated privledges (typically
|
||||
* root privledges).
|
||||
*
|
||||
* \see idVendor()
|
||||
**/
|
||||
std::string Vendor(void);
|
||||
|
||||
/**
|
||||
* \brief The product name string, as provided by the device.
|
||||
*
|
||||
* This method returns a string containing the name of the
|
||||
* device's product name, as encoded into the device.
|
||||
*
|
||||
* Note that not all devices contain a product name, and also
|
||||
* that under some operating systems you may not be able to
|
||||
* read the vendor name without elevated privledges (typically
|
||||
* root privledges).
|
||||
*
|
||||
* \see idProduct()
|
||||
**/
|
||||
std::string Product(void);
|
||||
|
||||
/**
|
||||
* \brief The serial number string, as provided by the device.
|
||||
*
|
||||
* This method returns a string containing a serial number for
|
||||
* the device, as encoded into the device.
|
||||
*
|
||||
* Note that few devices contain a serial number string, and also
|
||||
* that under some operating systems you may not be able to
|
||||
* read the serial number without elevated privledges (typically
|
||||
* root privledges). The USB specification requires that serial
|
||||
* numbers are unique if they are provided, but adherence to this
|
||||
* requirement by manufacturers is not universal.
|
||||
**/
|
||||
std::string SerialNumber(void);
|
||||
|
||||
/**
|
||||
* \brief Number of Configurations that this device has
|
||||
*
|
||||
* This is a simple accessor method that specifies the number
|
||||
* configurations that this device has.
|
||||
*/
|
||||
u_int8_t numConfigurations(void);
|
||||
|
||||
/**
|
||||
* \brief fetch an arbitrary string from the device
|
||||
*
|
||||
* \param string the string from the device. You can typically
|
||||
* pass in an empty string for this.
|
||||
* \param index the index of the string required
|
||||
* \param lang the language ID to use. Defaults to using the
|
||||
* first language ID.
|
||||
*
|
||||
* \return length of string, or 0 on error.
|
||||
*/
|
||||
int string(std::string &buf, int index, u_int16_t lang=0);
|
||||
|
||||
/**
|
||||
* \brief First Configuration for the Device
|
||||
*
|
||||
* This method returns a pointer to the first Configuration
|
||||
* for the Device.
|
||||
*
|
||||
* See nextConfiguration() for an example of how it might be
|
||||
* used.
|
||||
*/
|
||||
Configuration *firstConfiguration(void);
|
||||
|
||||
/**
|
||||
* \brief Next Configuration for the Device
|
||||
*
|
||||
* This method returns a pointer to the next Configuration
|
||||
* for the Device.
|
||||
*
|
||||
* If you want to iterate through each Configuration on
|
||||
* a device, you can use something like the following:
|
||||
* \code
|
||||
* USB::Configuration *this_Configuration;
|
||||
* this_Configuration = device->firstConfiguration();
|
||||
* for (i=0; i < device->numConfigurations(); i++) {
|
||||
* // do something with this_Configuration
|
||||
* this_Configuration->nextConfiguration();
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
Configuration *nextConfiguration(void);
|
||||
|
||||
/**
|
||||
* \brief Last Configuration for the Device
|
||||
*
|
||||
* This method returns a pointer to the last Configuration
|
||||
* for the Device.
|
||||
*
|
||||
*/
|
||||
Configuration *lastConfiguration(void);
|
||||
|
||||
/**
|
||||
* \brief USB control transfer
|
||||
*
|
||||
* This method performs a standard control transfer to the default
|
||||
* endpoint. See the USB specification for more details on this.
|
||||
*
|
||||
* \param requestType corresponds to the bmRequestType field
|
||||
* in the transfer
|
||||
* \param request corresponds to the bRequest field in the
|
||||
* transfer
|
||||
* \param value corresponds to the wValue field in the transfer
|
||||
* \param index corresponds to the wIndex field in the transfer
|
||||
* \param length corresponds to the wLength field in the transfer
|
||||
* \param payload corresponds to the data phase of a control
|
||||
* transfer
|
||||
* \param timeout is the timeout period for the control transfer,
|
||||
* in milliseconds
|
||||
*
|
||||
* \return number of bytes sent or received, or a negative number
|
||||
* in case of error.
|
||||
*/
|
||||
int controlTransfer(u_int8_t requestType, u_int8_t request,
|
||||
u_int16_t value, u_int16_t index, u_int16_t length,
|
||||
unsigned char *payload,
|
||||
int timeout = 100);
|
||||
|
||||
#ifdef USE_UNTESTED_LIBUSBPP_METHODS
|
||||
/**
|
||||
* \brief USB device reset
|
||||
*
|
||||
* This method performs a device reset - see USB Specification
|
||||
* 9.1 for how this changes the device state to the Default state.
|
||||
*
|
||||
* \return 0 on success, or a negative number in case of error.
|
||||
*/
|
||||
int reset(void);
|
||||
|
||||
/**
|
||||
* \brief Set device configuration
|
||||
*
|
||||
* This method sets the device to a particular Configuration.
|
||||
*
|
||||
* \param configurationNumber the configuration that the device
|
||||
* should be changed to.
|
||||
*
|
||||
* \return 0 on success, or a negative number in case of error.
|
||||
*/
|
||||
int setConfiguration(int configurationNumber);
|
||||
#endif /* USE_UNTESTED_LIBUSBPP_METHODS */
|
||||
|
||||
private:
|
||||
std::list<Configuration *>::const_iterator iter;
|
||||
|
||||
struct usb_dev_handle *handle();
|
||||
void setFileName(std::string);
|
||||
void setDescriptor(struct usb_device_descriptor);
|
||||
void setVendor(std::string);
|
||||
void setProduct(std::string);
|
||||
void setSerialNumber(std::string);
|
||||
void setDevHandle(struct usb_dev_handle *);
|
||||
std::string m_fileName;
|
||||
std::string m_Vendor;
|
||||
std::string m_Product;
|
||||
std::string m_SerialNumber;
|
||||
struct usb_device *m_dev;
|
||||
struct usb_dev_handle *m_handle;
|
||||
struct usb_device_descriptor m_descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class representing a single bus on the machine
|
||||
*
|
||||
* This class is essentially a list of Device class instances
|
||||
*/
|
||||
class Bus : public std::list<Device *> {
|
||||
/**
|
||||
* Busses is a friend because it fills in the directory name
|
||||
* information on initialisation and rescan.
|
||||
*/
|
||||
friend class Busses;
|
||||
public:
|
||||
Bus() {};
|
||||
/**
|
||||
* \brief OS representation of directory name for this Bus
|
||||
*
|
||||
* libusb++ provides a uniform way of accessing USB
|
||||
* busses irrespective of the underlying Operation System
|
||||
* representation. If you want to map the libusb++ representation
|
||||
* to the Operating System representation, you can do this
|
||||
* with directory name().
|
||||
*
|
||||
* On Linux, the directoryname is usually something like 003, which
|
||||
* represents the third bus on the host.
|
||||
*
|
||||
* \see Directory::filename()
|
||||
*/
|
||||
std::string directoryName(void);
|
||||
private:
|
||||
std::list<Device *>::const_iterator iter;
|
||||
|
||||
void setDirectoryName(std::string);
|
||||
std::string m_directoryName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A vendor/product ID pair
|
||||
*
|
||||
* DeviceID provides a list of (vendor, product) identification
|
||||
* pairs. It is intended for use in a list of device numbers to
|
||||
* search for, but there is no reason why it couldn't be used for a
|
||||
* general purpose (vendor,product) tuple if you had some reason for
|
||||
* this.
|
||||
*
|
||||
* The description for Busses::match() provides an example of how
|
||||
* this class might be used.
|
||||
*
|
||||
* \see DeviceIDList, Busses::match()
|
||||
*/
|
||||
class DeviceID {
|
||||
public:
|
||||
DeviceID() {};
|
||||
/**
|
||||
* \brief Standard constructor
|
||||
*
|
||||
* This constructor takes (vendor, product) tuple, which are
|
||||
* stored away.
|
||||
*
|
||||
* \param vendor the 16 bit vendor number for the device
|
||||
* \param product the 16 bit product number for the device
|
||||
*/
|
||||
DeviceID(u_int16_t vendor, u_int16_t product);
|
||||
|
||||
/**
|
||||
* \brief vendor number for the device
|
||||
*
|
||||
* This method returns the 16 bit vendor number.
|
||||
*/
|
||||
u_int16_t vendor(void);
|
||||
|
||||
/**
|
||||
* \brief product number for the device
|
||||
*
|
||||
* This method returns the 16 bit product number.
|
||||
*/
|
||||
u_int16_t product(void);
|
||||
|
||||
private:
|
||||
u_int16_t m_vendor;
|
||||
u_int16_t m_product;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A list of vendor/product pairs
|
||||
*
|
||||
* DeviceIDList provides a list of DeviceID classes, which is
|
||||
* essentially a list of (vendor, product) identification pairs.
|
||||
*
|
||||
* \see DeviceID
|
||||
*/
|
||||
typedef std::list<DeviceID> DeviceIDList;
|
||||
|
||||
/**
|
||||
* \brief Class representing all the busses on the machine
|
||||
*
|
||||
* This class is essentially a list of Bus class instances
|
||||
*/
|
||||
class Busses : public std::list<Bus *> {
|
||||
public:
|
||||
Busses();
|
||||
|
||||
/**
|
||||
* \brief Update method
|
||||
*
|
||||
* This method can be called to rescan the various devices
|
||||
* attached to the various busses. You should use it to
|
||||
* update if things change. Unfortunately there is no
|
||||
* way to automatically detect this change in a portable way,
|
||||
* so worst case is that you need to call this using some
|
||||
* kind of timer in the background.
|
||||
*/
|
||||
void rescan(void);
|
||||
|
||||
/**
|
||||
* \brief find all devices with matching device class designator
|
||||
*
|
||||
* This method searches every device on every bus, and returns a
|
||||
* list of pointers to the devices that have a matching device
|
||||
* class code
|
||||
*/
|
||||
std::list<Device *> match(u_int8_t Class);
|
||||
|
||||
/**
|
||||
* \brief find all devices with matching device IDs
|
||||
*
|
||||
* This method searches every device on every bus, and returns a
|
||||
* list of pointers to the devices that have a matching device
|
||||
* ID. That is, if the (vendor, product) tuple of a device matches
|
||||
* one of the tuples on the list, then the device will be added to
|
||||
* the list of matches.
|
||||
*
|
||||
* An example of usage is shown below:
|
||||
* \code
|
||||
* USB::Busses buslist;
|
||||
* USB::Device *device;
|
||||
* std::list<USB::Device> miceFound;
|
||||
* USB::DeviceIDList mouseList;
|
||||
*
|
||||
* mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC00E)); // Wheel Mouse Optical
|
||||
* mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC012)); // MouseMan Dual Optical
|
||||
* mouseList.append(USB::DeviceID(VENDOR_LOGITECH, 0xC506)); // MX700 Optical Mouse
|
||||
*
|
||||
* miceFound = buslist.match(mouseList);
|
||||
*
|
||||
* for ( device = miceFound.first(); device; device = miceFound.next() ) {
|
||||
* // do something with each mouse that matched
|
||||
* }
|
||||
* FIXME: This is incorrect now
|
||||
* \endcode
|
||||
*/
|
||||
std::list<Device *> match(DeviceIDList);
|
||||
|
||||
private:
|
||||
std::list<Bus *>::const_iterator iter;
|
||||
};
|
||||
|
||||
class Error {
|
||||
public:
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* __USBPP_HEADER__ */
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
OBJ=logotool.o compress.o uncompress.o rgb2yuv.o
|
||||
CFLAGS=-Wall -g
|
||||
|
||||
all: ${OBJ}
|
||||
${CC} ${OBJ} -o logotool
|
||||
|
||||
clean:
|
||||
rm -f ${OBJ} logotool
|
||||
@@ -1,17 +0,0 @@
|
||||
Compressing/Uncompressing images
|
||||
================================
|
||||
|
||||
To compress your image type:
|
||||
|
||||
$ gimp -> create an image and save as raw rgb (24 bits)
|
||||
$ logotool -w 300 -h 200 -c MyImage.rgb
|
||||
|
||||
This command will create MyImage.rgb.logo
|
||||
|
||||
You can check if the image is fine typing:
|
||||
|
||||
$ logotool -u MyImage.rgb.logo
|
||||
|
||||
To see the image you'll need mplayer and type this:
|
||||
|
||||
$ `logotool -u MyImage.rgb.logo`
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* logotool - tool to modify logo images with simple compression
|
||||
* Copyright (C) 2007
|
||||
* pancake <pancake@youterm.com>
|
||||
* esteve <esteve@eslack.org>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
extern int rgba;
|
||||
|
||||
int isbe()
|
||||
{
|
||||
int a=1; char *b=(char *)&a;
|
||||
return (int)b[0];
|
||||
}
|
||||
|
||||
void ememcpy(char *dst, char *src)
|
||||
{
|
||||
char buffer[4];
|
||||
memcpy(buffer, src, 4);
|
||||
dst[0] = buffer[3]; dst[1] = buffer[2];
|
||||
dst[2] = buffer[1]; dst[3] = buffer[0];
|
||||
}
|
||||
|
||||
int compress_image(char *srcf, char *dstf, int w, int h)
|
||||
{
|
||||
char buf[256];
|
||||
char tmp[256];
|
||||
int fdout;
|
||||
FILE *fd;
|
||||
int i,ret;
|
||||
|
||||
fd = fopen(srcf, "rb");
|
||||
if (fd == NULL) {
|
||||
printf("Cannot open file '%s' \n", srcf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fdout = open( dstf, O_TRUNC | O_CREAT | O_WRONLY , 0660 );
|
||||
if (fdout == -1) {
|
||||
printf("Cannot open file '%s' for writing\n", dstf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isbe()) {
|
||||
char oop[4];
|
||||
ememcpy((char *)&oop, (char *)&w);
|
||||
write(fdout, &oop, 4);
|
||||
ememcpy((char *)&oop, (char *)&h);
|
||||
write(fdout, &oop, 4);
|
||||
} else {
|
||||
write(fdout, &w, 4);
|
||||
write(fdout, &h, 4);
|
||||
}
|
||||
|
||||
fseek(fd, 0, SEEK_END);
|
||||
if (!rgba && ftell(fd)%3) {
|
||||
fprintf(stderr, "Oops..looks like RGBA..forcing -a\n");
|
||||
rgba = 1;
|
||||
}
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
|
||||
#define MAX 3*80
|
||||
if (rgba) {
|
||||
for(;;) {
|
||||
unsigned char c;
|
||||
ret = fread(&buf, 1, MAX, fd);
|
||||
if (ret <= 0) break;
|
||||
c = ret/4;
|
||||
write(fdout,&c, 1);
|
||||
for(i=0;i<ret;i+=4) {
|
||||
tmp[0] = buf[i+0]&0xf8;
|
||||
tmp[0] |= buf[i+1]&0x07;
|
||||
tmp[1] = buf[i+1]&0xe0;
|
||||
tmp[1] |= buf[i+2]&0x1f;
|
||||
write(fdout, tmp, 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(;;) {
|
||||
unsigned char c;
|
||||
ret = fread(buf, 1, MAX, fd);
|
||||
if (ret <= 0) break;
|
||||
c = ret/3;
|
||||
write(fdout,&c, 1);
|
||||
for(i=0;i<ret;i+=3) {
|
||||
tmp[0] = buf[i+0]&0xf8;
|
||||
tmp[0] |= buf[i+1]&0x07;
|
||||
tmp[1] = buf[i+1]&0xe0;
|
||||
tmp[1] |= buf[i+2]&0x1f;
|
||||
write(fdout, tmp, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
close(fdout);
|
||||
printf("eval PATH=$PWD:$PATH logotool -u %s\n", dstf);
|
||||
return 1;
|
||||
}
|
||||
#if 0
|
||||
// TODO: compression stuff
|
||||
/* is a repeated block? */
|
||||
c = buf[0];
|
||||
for(i=1;i<MAX&&buf[i]==c&&buf[i+1]==c;i+=2);
|
||||
printf("memcpy %d -> %d (ret %d)\n",i,ret-i, ret);
|
||||
for(i=0;i<ret-i;i++)
|
||||
printf(" %02x ", (unsigned char)buf[i]);
|
||||
printf("\n");
|
||||
if (i>5) {
|
||||
// if (i==MAX) {
|
||||
if (0x80>ret) printf("PRON\n");
|
||||
c = 0x80 | ret; //(int)((2*ret/3)>>1);
|
||||
write(fdout,&c, 1);
|
||||
tmp[0] = buf[i+0]&0xf8;
|
||||
tmp[0] |= buf[i+1]&0x07;
|
||||
tmp[1] = buf[i+1]&0xe0;
|
||||
tmp[1] |= buf[i+1]&0x1f;
|
||||
write(fdout, tmp, 2);
|
||||
// restore state
|
||||
memcpy(buf,buf+i,ret-i);
|
||||
ret -= i;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* logotool - tool to modify logo images with simple compression
|
||||
* Copyright (C) 2007
|
||||
* pancake <pancake@youterm.com>
|
||||
* esteve <esteve@eslack.org>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
int uncompress_image(char *srcf, char *dstf);
|
||||
int compress_image(char *srcf, char *dstf, int w, int h);
|
||||
int rgb2yuv(char *from, char *to, int width, int height);
|
||||
int rgba = 0;
|
||||
|
||||
static int show_usage()
|
||||
{
|
||||
printf("Usage: logotool [-flags]\n");
|
||||
printf(" -u [img] uncompress image to img.rgb\n");
|
||||
printf(" -c [img] compres a 24 bit rgb raw image to a 16(565) one\n");
|
||||
printf(" -m [img] show image using mplayer (dumps to <img>.yuv)\n");
|
||||
printf(" -v [img] view uncompressed image using the 'display'\n");
|
||||
printf(" command from ImageMagick (in monochrome)\n");
|
||||
printf(" -w specify width (required for -v and -c)\n");
|
||||
printf(" -a force RGBA instead of RGB when compressing (use with -c)\n");
|
||||
printf(" -h specify height (required for -v and -c)\n");
|
||||
printf(" -V version number\n");
|
||||
printf("\n");
|
||||
printf("Example:\n");
|
||||
printf(" $ `logotool -u logo-file` # uncompress and display a logo\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main ( int argc , char** argv )
|
||||
{
|
||||
int c;
|
||||
int w=0,h=0;
|
||||
char *mimg = NULL;
|
||||
char *cimg = NULL;
|
||||
char *uimg = NULL;
|
||||
char *view = NULL;
|
||||
|
||||
while((c = getopt(argc, argv, "w:h:Vv:u:c:m:a")) != -1) {
|
||||
switch(c) {
|
||||
case 'V': printf("%s\n", VERSION); return 0;
|
||||
case 'u': uimg = optarg; break;
|
||||
case 'c': cimg = optarg; break;
|
||||
case 'm': mimg = optarg; break;
|
||||
case 'a': rgba = 1; break;
|
||||
case 'w': w = atoi(optarg); break;
|
||||
case 'h': h = atoi(optarg); break;
|
||||
case 'v': view = optarg; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mimg) {
|
||||
char *buf;
|
||||
if (w==0||h==0) {
|
||||
printf("You must specify width and height with '-w' and '-h'.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf = (char *)malloc(strlen(mimg)+128);
|
||||
sprintf(buf, "%s.rgb", mimg);
|
||||
|
||||
if ( rgb2yuv(mimg, buf, w,h ) ) {
|
||||
sprintf(buf, "echo pause | mplayer %s.rgb -slave -demuxer rawvideo -rawvideo fps=1:w=%d:h=%d", mimg, w,h);
|
||||
system(buf);
|
||||
} else {
|
||||
printf("Oops\n");
|
||||
}
|
||||
free(buf);
|
||||
} else
|
||||
if (view) {
|
||||
char *buf;
|
||||
|
||||
if (w==0||h==0) {
|
||||
printf("You must specify width and height with '-w' and '-h'.\n");
|
||||
return 1;
|
||||
}
|
||||
buf = (char *)malloc(strlen(view)+128);
|
||||
sprintf(buf, "display -size %dx%d -depth 16 %s", w,h,view);
|
||||
printf("%s\n", buf);
|
||||
system(buf);
|
||||
free(buf);
|
||||
} else
|
||||
if (uimg) {
|
||||
char *dst = (char*)malloc(strlen(uimg)+5);
|
||||
strcpy(dst, uimg);
|
||||
strcat(dst, ".gray");
|
||||
uncompress_image(uimg, dst);
|
||||
free(dst);
|
||||
} else
|
||||
if (cimg) {
|
||||
char *dst;
|
||||
if (w==0||h==0) {
|
||||
printf("You must specify width and height with '-w' and '-h'.\n");
|
||||
return 1;
|
||||
}
|
||||
dst = (char*)malloc(strlen(cimg)+6);
|
||||
strcpy(dst, cimg);
|
||||
strcat(dst, ".logo");
|
||||
compress_image(cimg, dst, w, h);
|
||||
free(dst);
|
||||
} else
|
||||
show_usage();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* logotool - tool to modify logo images with simple compression
|
||||
* Copyright (C) 2007
|
||||
* esteve <esteve@eslack.org>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
void RGBtoYUV(unsigned short in565, unsigned char *yuv)
|
||||
{
|
||||
/* 2 bytes, 565
|
||||
* RRRRR GGGGGG BBBBB
|
||||
*/
|
||||
|
||||
int i;
|
||||
i = (in565>>8)&0xFF;
|
||||
in565 = (in565<<8)&0xFF00;
|
||||
in565 |= i;
|
||||
|
||||
int rgb[3];
|
||||
|
||||
rgb[0] = (in565>>11)&0x1F;
|
||||
rgb[1] = (in565>>5)&0x3F;
|
||||
rgb[2] = (in565)&0x1F;
|
||||
|
||||
rgb[0] = (rgb[0]<<3) | 0x7;
|
||||
rgb[1] = (rgb[1]<<2) | 0x3;
|
||||
rgb[2] = (rgb[2]<<3) | 0x7;
|
||||
|
||||
/*yuv[0] = 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2];
|
||||
yuv[1] = (rgb[2]-yuv[0])*0.565 + 128;
|
||||
yuv[2] = (rgb[0]-yuv[0])*0.713 + 128;*/
|
||||
|
||||
yuv[0] = (0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16;
|
||||
yuv[1] = 128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]);
|
||||
yuv[2] = 128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]);
|
||||
}
|
||||
// mplayer caca.yuv -demuxer rawvideo -rawvideo fps=1:w=416:h=70 //:i420
|
||||
|
||||
|
||||
int rgb2yuv(char *from, char *to, int width, int height)
|
||||
{
|
||||
int fd=open (from, O_RDONLY );
|
||||
int fout= open ( to, O_CREAT| O_WRONLY , 0660 );
|
||||
int fsize;
|
||||
unsigned char* src;
|
||||
unsigned char* dstY;
|
||||
unsigned char* dstU;
|
||||
unsigned char* dstV;
|
||||
unsigned char YUV[3];
|
||||
unsigned short inP;
|
||||
int i,j;
|
||||
|
||||
if (fd == -1) {
|
||||
printf("cannot open %s\n", from);
|
||||
return 0;
|
||||
}
|
||||
if (fout == -1) {
|
||||
printf("cannot open %s\n", to);
|
||||
return 0;
|
||||
}
|
||||
fsize = lseek ( fd, 0,SEEK_END);
|
||||
fsize = lseek ( fd, 0,SEEK_CUR);
|
||||
lseek ( fd,0, SEEK_SET);
|
||||
|
||||
src=malloc ( fsize );
|
||||
dstY=malloc ( (fsize/2) );
|
||||
dstU=malloc ( (fsize/2) );
|
||||
dstV=malloc ( (fsize/2) );
|
||||
|
||||
|
||||
for ( i = 0 ; i < fsize; i+=2 ) {
|
||||
read ( fd, &inP, 2 );
|
||||
RGBtoYUV ( inP, YUV );
|
||||
dstY[i>>1]=YUV[0];
|
||||
dstU[i>>1]=YUV[1];
|
||||
dstV[i>>1]=YUV[2];
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < (fsize/2); i++ )
|
||||
write ( fout,&dstY[i], 1);
|
||||
|
||||
for ( i = 0 ; i < height ; i+=2 )
|
||||
for ( j = 0; j < width ; j +=2 )
|
||||
write ( fout,&dstU[j+(i*width)], 1);
|
||||
|
||||
for ( i = 0 ; i < height ; i+=2 )
|
||||
for ( j = 0; j < width ; j +=2 )
|
||||
write ( fout,&dstV[j+(i*width)], 1);
|
||||
return 1;
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* logotool - tool to modify logo images with simple compression
|
||||
* Copyright (C) 2007
|
||||
* pancake <pancake@youterm.com>
|
||||
* esteve <esteve@eslack.org>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int uncompress_image(char *srcf, char *dstf)
|
||||
{
|
||||
int fd;
|
||||
int fout;
|
||||
int width,height;
|
||||
int fsize;
|
||||
char* src;
|
||||
char* dst;
|
||||
char* src2;
|
||||
char* eof;
|
||||
char *deof;
|
||||
char* dst2 = NULL;
|
||||
unsigned char byte;
|
||||
|
||||
fd = open( srcf, O_RDONLY );
|
||||
|
||||
if (fd == -1) {
|
||||
printf("Cannot open file '%s'\n", srcf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fout = open( dstf, O_CREAT | O_WRONLY , 0660 );
|
||||
|
||||
if (fout == -1) {
|
||||
printf("Cannot open file '%s' for writing\n", dstf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Input file: %s\n", srcf);
|
||||
fprintf(stderr, "Output file: %s\n", dstf);
|
||||
fsize = lseek ( fd, 0,SEEK_END);
|
||||
fsize = lseek ( fd, 0,SEEK_CUR);
|
||||
lseek ( fd,0, SEEK_SET);
|
||||
|
||||
fsize -= 8;
|
||||
|
||||
read ( fd, &width, 4 );
|
||||
read ( fd, &height, 4 );
|
||||
|
||||
fprintf(stderr, "Width: %d\nHeight: %d\n",width, height);
|
||||
fprintf(stderr, "Input Size: %d\n",fsize);
|
||||
src = malloc ( fsize );
|
||||
dst = malloc ( width*height*2 );
|
||||
deof = dst+width*height*2;
|
||||
if ((int)src == -1 || (int)dst == -1 ) {
|
||||
printf("Cannot malloc\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(dst,'\0', width*height*2);
|
||||
|
||||
read(fd, src, fsize);
|
||||
eof = src+fsize;
|
||||
|
||||
for(dst2 = dst, src2 = src; src2<eof;) {
|
||||
//byte = src2[0] & 0xff;
|
||||
//src2 = src2 + 1;
|
||||
byte=(*src2++)&0xff;
|
||||
// [1xxxyyyy] [char] [char]
|
||||
// copies xxxyyyy times two chars
|
||||
if (byte > 0x7f) {
|
||||
int i,j = byte&0x7f;
|
||||
for(i=0; i++<j; dst2+=2)
|
||||
memcpy(dst2, src2, 2);
|
||||
src2+=2;
|
||||
} else {
|
||||
if ( byte != 0x00 ) {
|
||||
byte<<=1;
|
||||
// fprintf(stderr, "COPYING: %d %d\n", byte, (eof-src2));
|
||||
if ((dst2+byte >= deof || (src2+byte >= eof))) {
|
||||
fprintf(stderr, "Break\n");
|
||||
break;
|
||||
}
|
||||
memcpy(dst2, src2, byte);
|
||||
src2+=byte; dst2+=byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Output Size: %d\n",dst2-dst);
|
||||
|
||||
if ((dst2-dst)!=(width*height*2))
|
||||
fprintf(stderr, "failed?\n");
|
||||
|
||||
write ( fout, dst, width*height*2);
|
||||
|
||||
close(fout);
|
||||
close(fd);
|
||||
|
||||
//printf("./logotool -w %d -h %d -v %s || \n", width, height, dstf);
|
||||
//printf("logotool -w %d -h %d -v %s\n", width, height, dstf);
|
||||
printf("eval PATH=$PWD:$PATH logotool -w %d -h %d -m %s\n", width, height, dstf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+52
-15
@@ -1,20 +1,57 @@
|
||||
VERSION=0.3
|
||||
OBJ=main.o fiasco.o hexdump.o dump.o flash.o serial.o
|
||||
OBJ+=hash.o fpid.o query.o pieces.o utils.o devices.o console.o
|
||||
BIN=0xFFFF
|
||||
CFLAGS+=-DVERSION=\"${VERSION}\" -Wall -g -I .
|
||||
CFLAGS+=-pedantic -std=c99
|
||||
USBOBJ=../libusb/error.o ../libusb/usb.o ../libusb/descriptors.o
|
||||
USBOBJ+=../libusb/linux.o ## XXX not portable
|
||||
include ../config.mk
|
||||
|
||||
all: ${OBJ}
|
||||
${CC} ${LDFLAGS} -o ${BIN} ${OBJ} -lusb
|
||||
PREFIX ?= /usr/local
|
||||
INSTALL ?= install
|
||||
|
||||
allusb: ${OBJ}
|
||||
${CC} ${LDFLAGS} -o ${BIN} ${OBJ} ${USBOBJ}
|
||||
BUILD_DATE ?= $(shell LC_ALL=C date '+%b %e %Y')
|
||||
|
||||
static: ${OBJ}
|
||||
${CC} ${LDFLAGS} -o ${BIN} -static ${OBJ} ${USBOBJ}
|
||||
CC ?= cc
|
||||
CROSS_CC ?= $(CROSS_COMPILE)$(CC)
|
||||
HOST_CC ?= $(HOST_COMPILE)$(CC)
|
||||
|
||||
PKG_CONFIG ?= pkg-config
|
||||
LIBUSB_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags libusb-1.0 2>/dev/null)
|
||||
LIBUSB_LIBS ?= $(shell $(PKG_CONFIG) --libs libusb-1.0 2>/dev/null || echo -lusb-1.0)
|
||||
|
||||
CPPFLAGS += -DVERSION=\"$(VERSION)\" -DBUILD_DATE="\"$(BUILD_DATE)\"" -D_POSIX_C_SOURCE=200809L -D_FILE_OFFSET_BITS=64
|
||||
CFLAGS += -W -Wall -O2 -pedantic -std=c99
|
||||
LIBS += $(LIBUSB_LIBS)
|
||||
|
||||
DEPENDS = Makefile ../config.mk
|
||||
|
||||
OBJS = main.o nolo.o printf-utils.o image.o fiasco.o device.o usb-device.o cold-flash.o operations.o local.o mkii.o disk.o cal.o
|
||||
BIN = 0xFFFF
|
||||
MANGEN = mangen
|
||||
|
||||
all: $(BIN) $(BIN).1
|
||||
|
||||
$(BIN): $(OBJS) $(DEPENDS)
|
||||
$(CROSS_CC) $(CFLAGS) $(LDFLAGS) -o $(BIN) $(OBJS) $(LIBS)
|
||||
|
||||
$(MANGEN): $(MANGEN).c $(DEPENDS)
|
||||
$(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
$(BIN).1: $(BIN) $(MANGEN) $(DEPENDS) ../doc/examples
|
||||
./$(MANGEN) > $@.tmp
|
||||
(printf '.SH EXAMPLES\n.\n.PP\n.B\n'; cat ../doc/examples) | sed 's/^$$/.fi\n.\n.PP\n.B/' | sed '/^\.PP$$/N;/\.B/N;/\.fi/N;s/^\.PP\n\.B\n\.fi\n//' | sed '/^\.B/N;s/\n/ /;/^\.B/s/$$/\n.nf/' | sed '/^\.nf/N;/^\.fi/N;s/^\.nf\n.fi/./' >> $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
libusb-sniff-32.so: libusb-sniff.c $(DEPENDS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -fPIC $< -ldl -shared -m32 -o $@
|
||||
|
||||
libusb-sniff-64.so: libusb-sniff.c $(DEPENDS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -fPIC $< -ldl -shared -m64 -o $@
|
||||
|
||||
%.o: %.c $(DEPENDS)
|
||||
$(CROSS_CC) $(CFLAGS) $(CPPFLAGS) $(LIBUSB_CFLAGS) -c -o $@ $<
|
||||
|
||||
install: $(BIN) $(BIN).1
|
||||
$(INSTALL) -D -m 755 $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN)
|
||||
$(INSTALL) -D -m 644 $(BIN).1 $(DESTDIR)$(PREFIX)/share/man/man1/$(BIN).1
|
||||
|
||||
uninstall:
|
||||
$(RM) $(DESTDIR)$(PREFIX)/bin/$(BIN)
|
||||
$(RM) $(DESTDIR)$(PREFIX)/share/man/man1/$(BIN).1
|
||||
|
||||
clean:
|
||||
-rm -f ${OBJ} ${BIN}
|
||||
-$(RM) $(OBJS) $(BIN) $(MANGEN) $(BIN).1 $(BIN).1.tmp libusb-sniff-32.so libusb-sniff-64.so
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
/* This is simple CAL parser form Calvaria */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "cal.h"
|
||||
|
||||
#define MAX_SIZE 393216
|
||||
#define INDEX_LAST (0xFF + 1)
|
||||
#define HDR_MAGIC "ConF"
|
||||
|
||||
struct cal {
|
||||
ssize_t size;
|
||||
void * mem;
|
||||
};
|
||||
|
||||
struct header {
|
||||
char magic[4]; /* Magic sequence */
|
||||
uint8_t type; /* Type number */
|
||||
uint8_t index; /* Index number */
|
||||
uint16_t flags; /* Flags */
|
||||
char name[16]; /* Human readable section name */
|
||||
uint32_t length; /* Payload length */
|
||||
uint32_t datasum; /* Data CRC32 checksum */
|
||||
uint32_t hdrsum; /* Header CRC32 checksum */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
int cal_init_file(const char * file, struct cal ** cal_out) {
|
||||
|
||||
int fd = -1;
|
||||
uint64_t blksize = 0;
|
||||
ssize_t size = 0;
|
||||
void * mem = NULL;
|
||||
struct cal * cal = NULL;
|
||||
struct stat st;
|
||||
#ifdef __linux__
|
||||
mtd_info_t mtd_info;
|
||||
#else
|
||||
off_t lsize = 0;
|
||||
#endif
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
|
||||
if ( fd < 0 )
|
||||
return -1;
|
||||
|
||||
if ( fstat(fd, &st) != 0 )
|
||||
goto err;
|
||||
|
||||
if ( S_ISREG(st.st_mode) )
|
||||
size = st.st_size;
|
||||
else if ( S_ISBLK(st.st_mode) ) {
|
||||
#ifdef __linux__
|
||||
if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 )
|
||||
goto err;
|
||||
#else
|
||||
lsize = lseek(fd, 0, SEEK_END);
|
||||
if ( lsize == (off_t)-1 )
|
||||
goto err;
|
||||
if ( lseek(fd, 0, SEEK_SET) == (off_t)-1 )
|
||||
goto err;
|
||||
blksize = lsize;
|
||||
#endif
|
||||
#ifdef SSIZE_MAX
|
||||
if ( blksize > SSIZE_MAX )
|
||||
goto err;
|
||||
#endif
|
||||
size = blksize;
|
||||
} else {
|
||||
#ifdef __linux__
|
||||
if ( S_ISCHR(st.st_mode) && major(st.st_rdev) == 90 ) {
|
||||
if ( ioctl(fd, MEMGETINFO, &mtd_info) != 0 )
|
||||
goto err;
|
||||
size = mtd_info.size;
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
#else
|
||||
goto err;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( size == 0 || size > MAX_SIZE )
|
||||
goto err;
|
||||
|
||||
mem = malloc(size);
|
||||
|
||||
if ( ! mem )
|
||||
goto err;
|
||||
|
||||
if ( read(fd, mem, size) != size )
|
||||
goto err;
|
||||
|
||||
cal = malloc(sizeof(struct cal));
|
||||
|
||||
if ( ! cal )
|
||||
goto err;
|
||||
|
||||
cal->mem = mem;
|
||||
cal->size = size;
|
||||
|
||||
close(fd);
|
||||
|
||||
*cal_out = cal;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
close(fd);
|
||||
free(mem);
|
||||
free(cal);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int cal_init(struct cal ** cal_out) {
|
||||
|
||||
return cal_init_file("/dev/mtd1ro", cal_out);
|
||||
|
||||
}
|
||||
|
||||
void cal_finish(struct cal * cal) {
|
||||
|
||||
if ( cal ) {
|
||||
free(cal->mem);
|
||||
free(cal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint32_t crc32(uint32_t crc, const void * _data, size_t size) {
|
||||
|
||||
const uint8_t * data = _data;
|
||||
uint8_t value;
|
||||
unsigned int bit;
|
||||
size_t i;
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
|
||||
for ( i = 0; i < size; i++ ) {
|
||||
value = data[i];
|
||||
for ( bit = 8; bit; bit-- ) {
|
||||
if ( (crc & 1) != (value & 1) )
|
||||
crc = (crc >> 1) ^ poly;
|
||||
else
|
||||
crc >>= 1;
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
|
||||
}
|
||||
|
||||
static int is_header(void *data, size_t size) {
|
||||
|
||||
struct header * hdr = data;
|
||||
|
||||
if ( size < sizeof(struct header) )
|
||||
return 0;
|
||||
|
||||
if ( memcmp(hdr->magic, HDR_MAGIC, sizeof(hdr->magic)) != 0 )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int64_t find_section(void *start, uint64_t count, int want_index, const char *want_name) {
|
||||
|
||||
int64_t offset = 0, found_offset = -1;
|
||||
uint8_t * data = start;
|
||||
struct header *hdr;
|
||||
char sectname[sizeof(hdr->name) + 1] = { 0, };
|
||||
uint32_t payload_len;
|
||||
int previous_index = -1;
|
||||
|
||||
while ( 1 ) {
|
||||
|
||||
/* Find header start */
|
||||
if ( count < sizeof(struct header) )
|
||||
break;
|
||||
|
||||
if ( ! is_header(data + offset, count) ) {
|
||||
count--;
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
hdr = (struct header *)(data + offset);
|
||||
payload_len = hdr->length;
|
||||
|
||||
if ( count - sizeof(struct header) < payload_len )
|
||||
return -1;
|
||||
|
||||
memcpy(sectname, hdr->name, sizeof(hdr->name));
|
||||
|
||||
if ( want_index == INDEX_LAST ) {
|
||||
if ( (int)hdr->index <= previous_index )
|
||||
goto next;
|
||||
} else {
|
||||
if ( want_index >= 0 && want_index != hdr->index )
|
||||
goto next;
|
||||
}
|
||||
|
||||
if ( want_name && strcmp(sectname, want_name) != 0 )
|
||||
goto next;
|
||||
|
||||
/* Found it */
|
||||
found_offset = offset;
|
||||
if ( want_index == INDEX_LAST )
|
||||
previous_index = hdr->index;
|
||||
else
|
||||
break;
|
||||
|
||||
next:
|
||||
count -= sizeof(struct header) + payload_len;
|
||||
offset += sizeof(struct header) + payload_len;
|
||||
|
||||
}
|
||||
|
||||
return found_offset;
|
||||
|
||||
}
|
||||
|
||||
int cal_read_block(struct cal * cal, const char * name, void ** ptr, unsigned long * len, unsigned long flags) {
|
||||
|
||||
int64_t find_offset;
|
||||
uint64_t filelen = cal->size;
|
||||
uint8_t * data = cal->mem;
|
||||
struct header * hdr;
|
||||
void * offset;
|
||||
|
||||
find_offset = find_section(data, filelen, INDEX_LAST, name);
|
||||
if ( find_offset < 0 )
|
||||
return -1;
|
||||
|
||||
hdr = (struct header *)(data + find_offset);
|
||||
|
||||
if ( flags && hdr->flags != flags )
|
||||
return -1;
|
||||
|
||||
if ( crc32(0, hdr, sizeof(*hdr) - 4) != hdr->hdrsum )
|
||||
return -1;
|
||||
|
||||
offset = data + find_offset + sizeof(struct header);
|
||||
|
||||
if ( crc32(0, offset, hdr->length) != hdr->datasum )
|
||||
return -1;
|
||||
|
||||
*ptr = malloc(hdr->length);
|
||||
if (!*ptr)
|
||||
return -1;
|
||||
|
||||
memcpy(*ptr, offset, hdr->length);
|
||||
*len = hdr->length;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CAL_H
|
||||
#define CAL_H
|
||||
|
||||
#define CAL_MAX_NAME_LEN 16
|
||||
#define CAL_FLAG_USER 0x0001
|
||||
#define CAL_FLAG_WRITE_ONCE 0x0002
|
||||
|
||||
struct cal;
|
||||
|
||||
int cal_init(struct cal ** cal_out);
|
||||
int cal_init_file(const char * file, struct cal ** cal_out);
|
||||
void cal_finish(struct cal * cal);
|
||||
int cal_read_block(struct cal * cal, const char * name, void ** ptr, unsigned long * len, unsigned long flags);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
cold-flash.c - Cold flashing
|
||||
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "cold-flash.h"
|
||||
#include "image.h"
|
||||
#include "usb-device.h"
|
||||
#include "printf-utils.h"
|
||||
|
||||
#define READ_TIMEOUT 500
|
||||
#define WRITE_TIMEOUT 3000
|
||||
|
||||
static uint32_t tab[256];
|
||||
|
||||
static void crc32_gentab(void) {
|
||||
|
||||
int i, j;
|
||||
uint32_t crc;
|
||||
uint32_t poly = 0xEDB88320L;
|
||||
|
||||
for ( i = 0; i < 256; i++) {
|
||||
|
||||
crc = i;
|
||||
|
||||
for ( j = 8; j > 0; j-- ) {
|
||||
|
||||
if ( crc & 1 )
|
||||
crc = (crc >> 1) ^ poly;
|
||||
else
|
||||
crc >>= 1;
|
||||
|
||||
}
|
||||
|
||||
tab[i] = crc;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint32_t crc32(unsigned char * bytes, size_t size, uint32_t crc) {
|
||||
|
||||
static int gen = 0;
|
||||
uint32_t i;
|
||||
|
||||
if ( ! gen ) {
|
||||
crc32_gentab();
|
||||
gen = 1;
|
||||
}
|
||||
|
||||
for ( i = 0; i < size; ++i )
|
||||
crc = (crc >> 8) ^ tab[(crc ^ bytes[i]) & 0xff];
|
||||
|
||||
return crc;
|
||||
|
||||
}
|
||||
|
||||
/* Omap Boot Messages */
|
||||
/* See spruf98v.pdf (page 3444): OMAP35x Technical Reference Manual - 25.4.5 Peripheral Booting */
|
||||
|
||||
/* Omap Peripheral boot message */
|
||||
static const uint32_t omap_peripheral_msg = 0xF0030002;
|
||||
|
||||
/* Unused */
|
||||
#if 0
|
||||
/* Omap Void (no device) boot message */
|
||||
static const uint32_t omap_void_msg = 0xF0030006;
|
||||
|
||||
/* Omap XIP memory boot message */
|
||||
static const uint32_t omap_xip_msg = 0xF0030106;
|
||||
|
||||
/* Omap Nand boot message */
|
||||
static const uint32_t omap_nand_msg = 0xF0030206;
|
||||
|
||||
/* Omap OneNAND boot message */
|
||||
static const uint32_t omap_onenand_msg = 0xF0030306;
|
||||
|
||||
/* Omap DOC boot message */
|
||||
static const uint32_t omap_doc_msg = 0xF0030406;
|
||||
|
||||
/* Omap MMC/SD2 boot message */
|
||||
static const uint32_t omap_mmc2_msg = 0xF0030506;
|
||||
|
||||
/* Omap MMC/SD1 boot message */
|
||||
static const uint32_t omap_mmc1_msg = 0xF0030606;
|
||||
|
||||
/* Omap XIP memory with wait monitoring boot message */
|
||||
static const uint32_t omap_xipwait_msg = 0xF0030706;
|
||||
|
||||
/* Omap UART boot message */
|
||||
static const uint32_t omap_uart_msg = 0xF0031006;
|
||||
|
||||
/* Omap HS USB boot message */
|
||||
static const uint32_t omap_hsusb_msg = 0xF0031106;
|
||||
|
||||
/* Omap next device boot message */
|
||||
static const uint32_t omap_next_msg = 0xFFFFFFFF;
|
||||
#endif
|
||||
|
||||
/* Omap memory boot message */
|
||||
static const uint32_t omap_memory_msg = 0;
|
||||
|
||||
|
||||
/* Nokia X-Loader messages */
|
||||
|
||||
/* Structure of X-Loader message */
|
||||
struct xloader_msg {
|
||||
uint32_t type; /* 4 bytes - type of message */
|
||||
uint32_t size; /* 4 bytes - size of file */
|
||||
uint32_t crc1; /* 4 bytes - crc32 of file */
|
||||
uint32_t crc2; /* 4 bytes - crc32 of first 12 bytes of message */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define XLOADER_MSG_TYPE_PING 0x6301326E
|
||||
#define XLOADER_MSG_TYPE_SEND 0x6302326E
|
||||
|
||||
struct xloader_msg xloader_msg_create(uint32_t type, struct image * image) {
|
||||
|
||||
struct xloader_msg msg;
|
||||
uint32_t need, sent;
|
||||
int ret;
|
||||
uint8_t buffer[1024];
|
||||
|
||||
msg.type = type;
|
||||
msg.size = 0;
|
||||
msg.crc1 = 0;
|
||||
|
||||
if ( image ) {
|
||||
msg.size = image->size;
|
||||
image_seek(image, 0);
|
||||
sent = 0;
|
||||
while ( sent < image->size ) {
|
||||
need = image->size - sent;
|
||||
if ( need > sizeof(buffer) )
|
||||
need = sizeof(buffer);
|
||||
ret = image_read(image, buffer, need);
|
||||
if ( ret == 0 )
|
||||
break;
|
||||
msg.crc1 = crc32(buffer, ret, msg.crc1);
|
||||
sent += ret;
|
||||
}
|
||||
}
|
||||
|
||||
msg.crc2 = crc32((unsigned char *)&msg, 12, 0);
|
||||
|
||||
return msg;
|
||||
|
||||
}
|
||||
|
||||
static int read_asic(libusb_device_handle * udev, uint8_t * asic_buffer, int size, int asic_size) {
|
||||
|
||||
int ret;
|
||||
|
||||
printf("Waiting for ASIC ID...\n");
|
||||
ret = usb_bulk_recv(udev, USB_READ_EP, asic_buffer, size, READ_TIMEOUT);
|
||||
if ( ret != asic_size )
|
||||
ERROR_RETURN("Invalid size of ASIC ID", -1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int send_2nd(libusb_device_handle * udev, struct image * image) {
|
||||
|
||||
uint8_t buffer[1024];
|
||||
uint32_t need, sent;
|
||||
int ret;
|
||||
|
||||
printf("Sending OMAP peripheral boot message...\n");
|
||||
ret = usb_bulk_send(udev, USB_WRITE_EP, &omap_peripheral_msg, sizeof(omap_peripheral_msg), WRITE_TIMEOUT);
|
||||
if ( ret != sizeof(omap_peripheral_msg) )
|
||||
ERROR_RETURN("Sending OMAP peripheral boot message failed", -1);
|
||||
|
||||
MSLEEP(5);
|
||||
|
||||
printf("Sending 2nd X-Loader image size...\n");
|
||||
ret = usb_bulk_send(udev, USB_WRITE_EP, &image->size, 4, WRITE_TIMEOUT);
|
||||
if ( ret != 4 )
|
||||
ERROR_RETURN("Sending 2nd X-Loader image size failed", -1);
|
||||
|
||||
MSLEEP(5);
|
||||
|
||||
printf("Sending 2nd X-Loader image...\n");
|
||||
printf_progressbar(0, image->size);
|
||||
image_seek(image, 0);
|
||||
sent = 0;
|
||||
while ( sent < image->size ) {
|
||||
need = image->size - sent;
|
||||
if ( need > sizeof(buffer) )
|
||||
need = sizeof(buffer);
|
||||
ret = image_read(image, buffer, need);
|
||||
if ( ret == 0 )
|
||||
break;
|
||||
if ( usb_bulk_send(udev, USB_WRITE_EP, buffer, ret, WRITE_TIMEOUT) != ret )
|
||||
PRINTF_ERROR_RETURN("Sending 2nd X-Loader image failed", -1);
|
||||
sent += ret;
|
||||
printf_progressbar(sent, image->size);
|
||||
}
|
||||
|
||||
MSLEEP(50);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int send_secondary(libusb_device_handle * udev, struct image * image) {
|
||||
|
||||
struct xloader_msg init_msg;
|
||||
uint8_t buffer[1024];
|
||||
uint32_t need, sent;
|
||||
int ret;
|
||||
|
||||
init_msg = xloader_msg_create(XLOADER_MSG_TYPE_SEND, image);
|
||||
|
||||
printf("Sending X-Loader init message...\n");
|
||||
ret = usb_bulk_send(udev, USB_WRITE_EP, &init_msg, sizeof(init_msg), WRITE_TIMEOUT);
|
||||
if ( ret != sizeof(init_msg) )
|
||||
ERROR_RETURN("Sending X-Loader init message failed", -1);
|
||||
|
||||
printf("Waiting for X-Loader response...\n");
|
||||
MSLEEP(5);
|
||||
ret = usb_bulk_recv(udev, USB_READ_EP, &buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */
|
||||
if ( ret != 4 )
|
||||
ERROR_RETURN("No response", -1);
|
||||
|
||||
printf("Sending Secondary image...\n");
|
||||
printf_progressbar(0, image->size);
|
||||
image_seek(image, 0);
|
||||
sent = 0;
|
||||
while ( sent < image->size ) {
|
||||
need = image->size - sent;
|
||||
if ( need > sizeof(buffer) )
|
||||
need = sizeof(buffer);
|
||||
ret = image_read(image, buffer, need);
|
||||
if ( ret == 0 )
|
||||
break;
|
||||
if ( usb_bulk_send(udev, USB_WRITE_EP, buffer, ret, WRITE_TIMEOUT) != ret )
|
||||
PRINTF_ERROR_RETURN("Sending Secondary image failed", -1);
|
||||
sent += ret;
|
||||
printf_progressbar(sent, image->size);
|
||||
}
|
||||
|
||||
printf("Waiting for X-Loader response...\n");
|
||||
MSLEEP(5);
|
||||
ret = usb_bulk_recv(udev, USB_READ_EP, &buffer, 4, READ_TIMEOUT); /* 4 bytes - dummy value */
|
||||
if ( ret != 4 )
|
||||
ERROR_RETURN("No response", -1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int ping_timeout(libusb_device_handle * udev) {
|
||||
|
||||
int ret;
|
||||
int pong = 0;
|
||||
int try_ping = 10;
|
||||
|
||||
while ( try_ping > 0 ) {
|
||||
|
||||
struct xloader_msg ping_msg = xloader_msg_create(XLOADER_MSG_TYPE_PING, NULL);
|
||||
int try_read = 4;
|
||||
|
||||
printf("Sending X-Loader ping message\n");
|
||||
ret = usb_bulk_send(udev, USB_WRITE_EP, &ping_msg, sizeof(ping_msg), WRITE_TIMEOUT);
|
||||
if ( ret != sizeof(ping_msg) )
|
||||
ERROR_RETURN("Sending X-Loader ping message failed", -1);
|
||||
|
||||
printf("Waiting for X-Loader pong response...\n");
|
||||
while ( try_read > 0 ) {
|
||||
|
||||
uint32_t ping_read;
|
||||
ret = usb_bulk_recv(udev, USB_READ_EP, &ping_read, sizeof(ping_read), READ_TIMEOUT);
|
||||
if ( ret == sizeof(ping_read) ) {
|
||||
printf("Got it\n");
|
||||
pong = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
MSLEEP(5);
|
||||
--try_read;
|
||||
|
||||
}
|
||||
|
||||
if ( pong )
|
||||
break;
|
||||
|
||||
printf("Response timeout\n");
|
||||
--try_ping;
|
||||
|
||||
}
|
||||
|
||||
if ( pong )
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int init_cold_flash(struct usb_device_info * dev) {
|
||||
|
||||
uint8_t asic_buffer[127];
|
||||
int asic_size = 69;
|
||||
const char * chip = NULL;
|
||||
int revision;
|
||||
int i;
|
||||
|
||||
if ( dev->flash_device->protocol != FLASH_COLD )
|
||||
ERROR_RETURN("Device is not in Cold Flash mode", -1);
|
||||
|
||||
if ( read_asic(dev->udev, asic_buffer, sizeof(asic_buffer), asic_size) != 0 )
|
||||
ERROR_RETURN("Reading ASIC ID failed", -1);
|
||||
|
||||
if ( verbose ) {
|
||||
printf("Got ASIC ID:");
|
||||
for ( i = 0; i < asic_size; ++i )
|
||||
printf(" 0x%.2X", (unsigned int)asic_buffer[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* TODO: Detect device from asic id */
|
||||
|
||||
/* ASIC ID specification: http://processors.wiki.ti.com/index.php/OMAP35x_and_AM/DM37x_Initialization#UART.2FUSB_Booting */
|
||||
|
||||
/* Number of subblocks */
|
||||
if ( asic_buffer[0] != 0x05 )
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
/* 1. ID Subblock - header */
|
||||
if ( memcmp(asic_buffer+1, "\x01\x05\x01", 3) != 0 )
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
/* 1. ID Subblock - OMAP chip version (check for OMAP3430 or 3630) */
|
||||
if ( memcmp(asic_buffer+4, "\x34\x30\x07", 3) == 0 )
|
||||
chip = "OMAP3430";
|
||||
else if ( memcmp(asic_buffer+4, "\x36\x30\x07", 3) == 0 )
|
||||
chip = "OMAP3630";
|
||||
else
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
/* 1. ID Subblock - OMAP chip revision */
|
||||
revision = asic_buffer[7];
|
||||
|
||||
/* 2. Secure Mode Subblock - header */
|
||||
if ( memcmp(asic_buffer+8, "\x13\x02\x01", 3) != 0 )
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
/* 3. 2nd ID Subblock - header */
|
||||
if ( memcmp(asic_buffer+12, "\x12\x15\x01", 3) != 0 )
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
/* 4. Root Key Hash Subblock - header */
|
||||
if ( memcmp(asic_buffer+35, "\x14\x15\x01", 3) != 0 )
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
/* 5. Checksum subblock - header */
|
||||
if ( memcmp(asic_buffer+58, "\x15\x09\x01", 3) != 0 )
|
||||
ERROR_RETURN("Invalid ASIC ID", -1);
|
||||
|
||||
printf("Detected %s chip (revision %d)\n", chip, revision);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int cold_flash(struct usb_device_info * dev, struct image * x2nd, struct image * secondary) {
|
||||
|
||||
if ( x2nd->type != IMAGE_2ND )
|
||||
ERROR_RETURN("Image type is not 2nd X-Loader", -1);
|
||||
|
||||
if ( secondary->type != IMAGE_SECONDARY )
|
||||
ERROR_RETURN("Image type is not Secondary", -1);
|
||||
|
||||
if ( send_2nd(dev->udev, x2nd) != 0 )
|
||||
ERROR_RETURN("Sending 2nd X-Loader image failed", -1);
|
||||
|
||||
if ( ping_timeout(dev->udev) != 0 )
|
||||
ERROR_RETURN("Sending X-Loader ping message failed", -1);
|
||||
|
||||
if ( send_secondary(dev->udev, secondary) != 0 )
|
||||
ERROR_RETURN("Sending Secondary image failed", -1);
|
||||
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int leave_cold_flash(struct usb_device_info * dev) {
|
||||
|
||||
int ret;
|
||||
|
||||
printf("Sending OMAP memory boot message...\n");
|
||||
ret = usb_bulk_send(dev->udev, USB_WRITE_EP, &omap_memory_msg, sizeof(omap_memory_msg), WRITE_TIMEOUT);
|
||||
if ( ret != sizeof(omap_memory_msg) )
|
||||
ERROR_RETURN("Sending OMAP memory boot message failed", -1);
|
||||
|
||||
MSLEEP(250);
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
cold-flash.h - Cold flashing
|
||||
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef COLD_FLASH_H
|
||||
#define COLD_FLASH_H
|
||||
|
||||
#include "image.h"
|
||||
#include "usb-device.h"
|
||||
|
||||
/* Initialize Cold Flash mde */
|
||||
int init_cold_flash(struct usb_device_info * dev);
|
||||
|
||||
/* Flash 2nd and secondary image in Cold Flash mode. After flashing device will boot secondary image */
|
||||
int cold_flash(struct usb_device_info * dev, struct image * x2nd, struct image * secondary);
|
||||
|
||||
/* Leave Cold Flashing mode and continue booting */
|
||||
int leave_cold_flash(struct usb_device_info * dev);
|
||||
|
||||
#endif
|
||||
-166
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "query.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
||||
void cmd_exit(char *line)
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void cmd_help(char *line)
|
||||
{
|
||||
printf("connect connects via usb to nolo\n");
|
||||
printf("reboot reboots remote host\n");
|
||||
printf("info shows info of the remote system\n");
|
||||
printf("linfo shows info of the local system\n");
|
||||
printf("shell opens a shell (/bin/sh)\n");
|
||||
printf("badblocks [dev] checks bad blocks on mtd (/dev/mtd1)\n");
|
||||
printf("dump [dir] dumps the contents of /dev/mtd to dir\n");
|
||||
printf("nanddump [dev] [start] [len] [out] [ignore-badblocks] [ignore-oob]\n");
|
||||
printf(" f.ex: nanddump /dev/mtd0 0x0 0x4000 xloader.bin 1 1\n");
|
||||
printf("exit exits the shell\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void cmd_info(char *line)
|
||||
{
|
||||
get_hw_revision(); // get hardware revision:
|
||||
get_root_device(); // only for flashing
|
||||
get_usb_mode();
|
||||
get_rd_mode();
|
||||
get_rd_flags();
|
||||
}
|
||||
|
||||
void cmd_nanddump(char *line)
|
||||
{
|
||||
char dev[128];
|
||||
int from;
|
||||
int length;
|
||||
char out[128];
|
||||
int ignbb;
|
||||
int ignoob = -1;
|
||||
|
||||
sscanf(line, "%127s 0x%x 0x%x %127s %d %d",
|
||||
(char *)&dev, (unsigned int*)&from, (unsigned int *)&length,
|
||||
(char *)&out, (int*)&ignbb, (int *)&ignoob);
|
||||
|
||||
if (ignoob == -1) {
|
||||
eprintf("Invalid arguments.\n");
|
||||
eprintf("nanddump [dev] [start] [len] [out] [ignore-badblocks] [ignore-oob]\n");
|
||||
eprintf(" f.ex: nanddump /dev/mtd0 0x0 0x4000 xloader.bin 1 1\n");
|
||||
} else
|
||||
nanddump(dev, from, length, out, ignbb, ignoob);
|
||||
}
|
||||
|
||||
void cmd_dump(char *line)
|
||||
{
|
||||
if (!line[0]) {
|
||||
printf("Usage: dump [path]\n");
|
||||
return;
|
||||
}
|
||||
while(line[0]==' ') line = line +1;
|
||||
reverse_extract_pieces(line);
|
||||
}
|
||||
|
||||
void cmd_badblocks(char *line)
|
||||
{
|
||||
if (!line[0]) {
|
||||
printf("Usage: dump [path]\n");
|
||||
return;
|
||||
}
|
||||
while(line[0]==' ') line = line +1;
|
||||
check_badblocks(line);
|
||||
}
|
||||
|
||||
void cmd_connect(char *line)
|
||||
{
|
||||
connect_via_usb();
|
||||
}
|
||||
|
||||
void cmd_reboot(char *line)
|
||||
{
|
||||
reboot_board();
|
||||
}
|
||||
|
||||
void cmd_shell(char *line)
|
||||
{
|
||||
system("/bin/sh");
|
||||
}
|
||||
|
||||
#define CMDS 11
|
||||
#define IS_CMD(x) !strcmp(console_commands[i].name, x)
|
||||
#define CALL_CMD(x) console_commands[x].callback((char *)line)
|
||||
#define FOREACH_CMD(x) for(x=0;x<CMDS;x++)
|
||||
|
||||
struct cmd_t {
|
||||
char *name;
|
||||
void (*callback)(char *);
|
||||
} console_commands[CMDS] = {
|
||||
{ .name = "exit", .callback = &cmd_exit },
|
||||
{ .name = "q", .callback = &cmd_exit },
|
||||
{ .name = "connect", .callback = &cmd_connect },
|
||||
{ .name = "reboot", .callback = &cmd_reboot },
|
||||
{ .name = "badblocks", .callback = &cmd_badblocks},
|
||||
{ .name = "help", .callback = &cmd_help },
|
||||
{ .name = "?", .callback = &cmd_help },
|
||||
{ .name = "info", .callback = &cmd_info },
|
||||
{ .name = "dump", .callback = &cmd_dump },
|
||||
{ .name = "nanddump", .callback = &cmd_nanddump },
|
||||
{ .name = "shell", .callback = &cmd_shell }
|
||||
};
|
||||
|
||||
static int console_command(const char *line)
|
||||
{
|
||||
int i;
|
||||
char command[11];
|
||||
|
||||
command[0] = '\0';
|
||||
sscanf(line, "%10s", command);
|
||||
line = line + strlen(command);
|
||||
|
||||
FOREACH_CMD(i)
|
||||
if (IS_CMD(command))
|
||||
CALL_CMD(i);
|
||||
//
|
||||
return 1;
|
||||
}
|
||||
|
||||
int console_prompt()
|
||||
{
|
||||
char line[1024];
|
||||
|
||||
do {
|
||||
write(1, "0xFFFF> ", 8);
|
||||
line[0] = '\0';
|
||||
fgets(line, 1024, stdin);
|
||||
if (feof(stdin)) {
|
||||
write(1, "\n", 1);
|
||||
break;
|
||||
}
|
||||
if (line[0]) line[strlen(line)-1] = '\0';
|
||||
line[1023] = '\0';
|
||||
} while(console_command(line));
|
||||
|
||||
return 0;
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#include "device.h"
|
||||
|
||||
static const char * devices[] = {
|
||||
[DEVICE_SU_18] = "SU-18",
|
||||
[DEVICE_RX_34] = "RX-34",
|
||||
[DEVICE_RX_44] = "RX-44",
|
||||
[DEVICE_RX_48] = "RX-48",
|
||||
[DEVICE_RX_51] = "RX-51",
|
||||
[DEVICE_RM_680] = "RM-680",
|
||||
[DEVICE_RM_696] = "RM-696",
|
||||
};
|
||||
|
||||
enum device device_from_string(const char * device) {
|
||||
|
||||
size_t i;
|
||||
|
||||
if ( ! device || ! device[0] )
|
||||
return DEVICE_ANY;
|
||||
|
||||
for ( i = 0; i < sizeof(devices)/sizeof(devices[0]); ++i )
|
||||
if ( devices[i] && strcmp(devices[i], device) == 0 )
|
||||
return i;
|
||||
|
||||
return DEVICE_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
const char * device_to_string(enum device device) {
|
||||
|
||||
if ( device >= sizeof(devices)/sizeof(devices[0]) )
|
||||
return NULL;
|
||||
|
||||
return devices[device];
|
||||
|
||||
}
|
||||
|
||||
static const char * long_devices[] = {
|
||||
[DEVICE_SU_18] = "Nokia 770",
|
||||
[DEVICE_RX_34] = "Nokia N800",
|
||||
[DEVICE_RX_44] = "Nokia N810",
|
||||
[DEVICE_RX_48] = "Nokia N810 Wimax",
|
||||
[DEVICE_RX_51] = "Nokia N900",
|
||||
[DEVICE_RM_680] = "Nokia N950",
|
||||
[DEVICE_RM_696] = "Nokia N9",
|
||||
};
|
||||
|
||||
const char * device_to_long_string(enum device device) {
|
||||
|
||||
if ( device >= sizeof(long_devices)/sizeof(long_devices[0]) )
|
||||
return NULL;
|
||||
|
||||
return long_devices[device];
|
||||
|
||||
}
|
||||
|
||||
int hwrev_is_valid(const int16_t * hwrevs, int16_t hwrev) {
|
||||
|
||||
int i;
|
||||
|
||||
/* hwrevs not specified, valid for any hwrev */
|
||||
if ( ! hwrevs )
|
||||
return 1;
|
||||
|
||||
for ( i = 0; hwrevs[i] != -1; ++i )
|
||||
if ( hwrev == hwrevs[i] )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int16_t * hwrevs_alloc_from_string(const char * str) {
|
||||
|
||||
const char * ptr = str;
|
||||
const char * oldptr = ptr;
|
||||
int count = 2;
|
||||
int16_t * ret;
|
||||
int16_t tmp;
|
||||
int i;
|
||||
char buf[5];
|
||||
|
||||
if ( ! str )
|
||||
return NULL;
|
||||
|
||||
while ( (ptr = strchr(ptr, ',')) ) {
|
||||
++count;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
ret = calloc(count, sizeof(int16_t));
|
||||
if ( ! ret )
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
|
||||
ptr = str;
|
||||
while ( (ptr = strchr(ptr, ',')) ) {
|
||||
strncpy(buf, oldptr, ptr-oldptr);
|
||||
buf[4] = 0;
|
||||
tmp = atoi(buf);
|
||||
if ( tmp >= 0 )
|
||||
ret[i++] = tmp;
|
||||
++ptr;
|
||||
oldptr = ptr;
|
||||
}
|
||||
|
||||
tmp = atoi(oldptr);
|
||||
if ( tmp >= 0 )
|
||||
ret[i++] = tmp;
|
||||
|
||||
ret[i++] = -1;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
char * hwrevs_alloc_to_string(const int16_t * hwrevs) {
|
||||
|
||||
char * ret;
|
||||
char * ptr;
|
||||
int i;
|
||||
int len = 0;
|
||||
|
||||
for ( i = 0; hwrevs[i] != -1; ++i )
|
||||
len += 7;
|
||||
|
||||
ret = calloc(1, len+1);
|
||||
if ( ! ret )
|
||||
return NULL;
|
||||
|
||||
ptr = ret;
|
||||
for ( i = 0; hwrevs[i] != -1; ++i )
|
||||
ptr += sprintf(ptr, "%d,", hwrevs[i]);
|
||||
|
||||
*(ptr-1) = 0;
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
#define MAX_HWREVS 29
|
||||
|
||||
char ** device_list_alloc_to_bufs(const struct device_list * device_list) {
|
||||
|
||||
int count = 0;
|
||||
int size = 0;
|
||||
const char * device;
|
||||
const struct device_list * device_first;
|
||||
char ** ret;
|
||||
char * last_ptr;
|
||||
int i, j, k;
|
||||
|
||||
device_first = device_list;
|
||||
|
||||
while ( device_first ) {
|
||||
|
||||
int local = 0;
|
||||
|
||||
if ( ! device_to_string(device_first->device) ) {
|
||||
device_first = device_first->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( device_first->hwrevs ) {
|
||||
for ( i = 0; device_first->hwrevs[i] != -1; ++i )
|
||||
if ( device_first->hwrevs[i] >= 0 && device_first->hwrevs[i] <= 9999 )
|
||||
++local;
|
||||
}
|
||||
|
||||
size += (1+16+(MAX_HWREVS+1)*8)*(local/MAX_HWREVS+1);
|
||||
count += local/MAX_HWREVS;
|
||||
if ( local%MAX_HWREVS != 0 || local == 0 )
|
||||
++count;
|
||||
|
||||
device_first = device_first->next;
|
||||
|
||||
}
|
||||
|
||||
ret = calloc(1, (count+1)*sizeof(char *) + size);
|
||||
if ( ! ret )
|
||||
return NULL;
|
||||
|
||||
j = 0;
|
||||
last_ptr = (char *)ret + (count+1)*sizeof(char *);
|
||||
device_first = device_list;
|
||||
|
||||
while ( device_first ) {
|
||||
|
||||
i = -1;
|
||||
|
||||
device = device_to_string(device_first->device);
|
||||
if ( ! device ) {
|
||||
device_first = device_first->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
uint8_t len = 0;
|
||||
ret[j] = ++last_ptr;
|
||||
|
||||
strncpy(ret[j]+1, device, 16);
|
||||
last_ptr += 16;
|
||||
len += 16;
|
||||
|
||||
k = 0;
|
||||
|
||||
for ( k = 0; k < MAX_HWREVS; ++k ) {
|
||||
|
||||
if ( ! device_first->hwrevs || device_first->hwrevs[i+1] == -1 )
|
||||
break;
|
||||
|
||||
++i;
|
||||
|
||||
if ( device_first->hwrevs[i] < 0 || device_first->hwrevs[i] > 9999 )
|
||||
continue;
|
||||
|
||||
snprintf(ret[j]+1+16+k*8, 8, "%d", device_first->hwrevs[i]);
|
||||
last_ptr += 8;
|
||||
len += 8;
|
||||
|
||||
}
|
||||
|
||||
((uint8_t*)ret[j])[0] = len;
|
||||
|
||||
++j;
|
||||
|
||||
} while ( device_first->hwrevs && device_first->hwrevs[i+1] != -1 );
|
||||
|
||||
device_first = device_first->next;
|
||||
|
||||
}
|
||||
|
||||
ret[j] = NULL;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
struct device_list * device_list_alloc_from_buf(const char * buf, size_t size) {
|
||||
|
||||
int i;
|
||||
int len;
|
||||
int count;
|
||||
char str[17];
|
||||
const char * ptr1;
|
||||
const char * ptr;
|
||||
struct device_list * ret;
|
||||
|
||||
ret = calloc(1, sizeof(struct device_list));
|
||||
if ( ! ret )
|
||||
return NULL;
|
||||
|
||||
len = strnlen(buf, size);
|
||||
if ( len > 16 )
|
||||
len = 16;
|
||||
|
||||
memset(str, 0, sizeof(str));
|
||||
memcpy(str, buf, len);
|
||||
ptr1 = buf + len;
|
||||
|
||||
ret->device = device_from_string(str);
|
||||
|
||||
ptr = ptr1;
|
||||
count = 1;
|
||||
while ( ptr < buf + size ) {
|
||||
|
||||
while ( ptr < buf + size && *ptr < 32 )
|
||||
++ptr;
|
||||
|
||||
if ( ptr >= buf + size )
|
||||
break;
|
||||
|
||||
len = strnlen(ptr, buf + size - ptr);
|
||||
if ( len > 8 )
|
||||
len = 8;
|
||||
|
||||
ptr += len + 1;
|
||||
++count;
|
||||
|
||||
}
|
||||
|
||||
ret->hwrevs = calloc(count, sizeof(int16_t));
|
||||
if ( ! ret->hwrevs )
|
||||
return ret;
|
||||
|
||||
ptr = ptr1;
|
||||
i = 0;
|
||||
while ( ptr < buf + size ) {
|
||||
|
||||
while ( ptr < buf + size && *ptr < 32 )
|
||||
++ptr;
|
||||
|
||||
if ( ptr >= buf + size )
|
||||
break;
|
||||
|
||||
len = strnlen(ptr, buf + size - ptr);
|
||||
if ( len > 8 )
|
||||
len = 8;
|
||||
|
||||
memset(str, 0, sizeof(str));
|
||||
memcpy(str, ptr, len);
|
||||
ptr += len + 1;
|
||||
ret->hwrevs[i++] = atoi(str);
|
||||
|
||||
}
|
||||
|
||||
ret->hwrevs[i] = -1;
|
||||
return ret;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum device {
|
||||
DEVICE_UNKNOWN = 0,
|
||||
DEVICE_ANY, /* Unspecified / Any device */
|
||||
DEVICE_SU_18, /* Nokia 770 */
|
||||
DEVICE_RX_34, /* Nokia N800 */
|
||||
DEVICE_RX_44, /* Nokia N810 */
|
||||
DEVICE_RX_48, /* Nokia N810 WiMax */
|
||||
DEVICE_RX_51, /* Nokia N900 */
|
||||
DEVICE_RM_680, /* Nokia N950 */
|
||||
DEVICE_RM_696, /* Nokia N9 */
|
||||
DEVICE_COUNT,
|
||||
};
|
||||
|
||||
/*
|
||||
hwrevs - array of int16_t
|
||||
- terminated by -1
|
||||
- valid numbers: 0-9999
|
||||
*/
|
||||
struct device_list {
|
||||
enum device device;
|
||||
int16_t * hwrevs;
|
||||
struct device_list * next;
|
||||
};
|
||||
|
||||
enum device device_from_string(const char * device);
|
||||
const char * device_to_string(enum device device);
|
||||
const char * device_to_long_string(enum device device);
|
||||
|
||||
int hwrev_is_valid(const int16_t * hwrevs, int16_t hwrev);
|
||||
|
||||
int16_t * hwrevs_alloc_from_string(const char * str);
|
||||
char * hwrevs_alloc_to_string(const int16_t * hwrevs);
|
||||
|
||||
char ** device_list_alloc_to_bufs(const struct device_list * device_list);
|
||||
struct device_list * device_list_alloc_from_buf(const char * buf, size_t size);
|
||||
|
||||
#endif
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* The internet tablet PC (and probably most of
|
||||
* Nokia devices have different USB-IDs depending
|
||||
* on the boot state.
|
||||
*
|
||||
* The following table shows this info:
|
||||
*
|
||||
* boot os
|
||||
* n770 0421:0105 0421:0431
|
||||
* n800 0421:0431
|
||||
*
|
||||
*/
|
||||
struct devices supported_devices[SUPPORTED_DEVICES] = {
|
||||
{ "FFFF", 0x000, 0x0000, 0x0000 }, // dummy
|
||||
{ "unkn", 0x421, 0x3f00, 0x0000 }, // probably a development board
|
||||
{ "n770", 0x421, 0x0105, 0x0001 }, // my n770
|
||||
{ "n800", 0x421, 0x04c3, 0x0001 }, // a n800
|
||||
{ 0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/** Returns 0 when no device was found and a positive
|
||||
* non-zero value when one was found.
|
||||
*
|
||||
* The return value is the index into the supported_devices
|
||||
* array which denotes the device which was found.
|
||||
*/
|
||||
int is_valid_device(struct usb_device_descriptor *udd)
|
||||
{
|
||||
int i;
|
||||
struct devices ptr = supported_devices[1];
|
||||
|
||||
for(i=1 ; ptr.vendor_id; ptr = supported_devices[++i])
|
||||
if ((udd->idVendor == ptr.vendor_id)
|
||||
&& (udd->idProduct == ptr.product_id)) {
|
||||
D printf("found %s\n", supported_devices[i].name);
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* List all supported device-ids and it's names
|
||||
*
|
||||
*/
|
||||
void list_valid_devices()
|
||||
{
|
||||
int i;
|
||||
struct devices ptr = supported_devices[1];
|
||||
|
||||
for(i=1; ptr.vendor_id; ptr = supported_devices[++i])
|
||||
printf("%04x:%04x %s\n", ptr.vendor_id, ptr.product_id, ptr.name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true (1) when a valid usb device is found and stores the udd and devices
|
||||
* structures for the specified device.
|
||||
* Otherwise returns false (0)
|
||||
*/
|
||||
|
||||
int usb_device_found(struct usb_device_descriptor *udd, struct devices *it_device)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
int dev_index = 0;
|
||||
|
||||
if (usb_find_busses() < 0) {
|
||||
fprintf(stderr, "\nerror: no usb busses found.\n");
|
||||
exit(1);
|
||||
} else {
|
||||
switch(usb_find_devices()) {
|
||||
case -1:
|
||||
fprintf(stderr, "\nerror: no devices found.\n");
|
||||
exit(1);
|
||||
default:
|
||||
for (bus = usb_busses; bus; bus = bus->next) {
|
||||
struct usb_device *dev = bus->devices;
|
||||
D printf("bus: \n");
|
||||
for (; dev; dev = dev->next) {
|
||||
*udd = dev->descriptor;
|
||||
D printf(" dev (%s) - ", dev->filename);
|
||||
D printf("vendor: %04x product: %04x\n", udd->idVendor, udd->idProduct);
|
||||
|
||||
if ((dev_index = is_valid_device(udd))) {
|
||||
device = dev;
|
||||
*it_device = supported_devices[dev_index];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+539
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "disk.h"
|
||||
#include "global.h"
|
||||
#include "image.h"
|
||||
#include "device.h"
|
||||
#include "usb-device.h"
|
||||
#include "printf-utils.h"
|
||||
|
||||
static char global_buf[1UL << 22]; /* 4MB */
|
||||
|
||||
int disk_open_dev(int maj, int min, int partition, int readonly) {
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
int fd;
|
||||
struct stat st;
|
||||
DIR * dir;
|
||||
struct dirent * dirent;
|
||||
int found;
|
||||
int old_errno;
|
||||
size_t len;
|
||||
char blkdev[1024];
|
||||
|
||||
dir = opendir("/dev/");
|
||||
if ( ! dir ) {
|
||||
ERROR_INFO("Cannot open '/dev/' directory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
|
||||
while ( ( dirent = readdir(dir) ) ) {
|
||||
|
||||
if ( strncmp(dirent->d_name, ".", sizeof(".")) == 0 || strncmp(dirent->d_name, "..", sizeof("..")) == 0 )
|
||||
continue;
|
||||
|
||||
if ( snprintf(blkdev, sizeof(blkdev), "/dev/%s", dirent->d_name) <= 0 )
|
||||
continue;
|
||||
|
||||
if ( stat(blkdev, &st) != 0 )
|
||||
continue;
|
||||
|
||||
if ( ! S_ISBLK(st.st_mode) )
|
||||
continue;
|
||||
|
||||
if ( makedev(maj, min) != st.st_rdev )
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if ( ! found ) {
|
||||
ERROR("Cannot find block device with id %d:%d", maj, min);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Found block device %s with id %d:%d\n", blkdev, maj, min);
|
||||
|
||||
if ( partition == -1 ) {
|
||||
|
||||
/* Check if block device does not have partitions */
|
||||
|
||||
len = strlen(blkdev);
|
||||
if ( sizeof(blkdev) <= len+2 ) {
|
||||
ERROR("Block device name is too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(blkdev+len, "p1", 3);
|
||||
if ( stat(blkdev, &st) == 0 ) {
|
||||
ERROR("Block device has partitions");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(blkdev+len, "1", 2);
|
||||
if ( stat(blkdev, &st) == 0 ) {
|
||||
ERROR("Block device has partitions");
|
||||
return -1;
|
||||
}
|
||||
|
||||
blkdev[len] = 0;
|
||||
|
||||
fd = open(blkdev, ((simulate || readonly) ? O_RDONLY : O_RDWR) | O_EXCL | O_NONBLOCK);
|
||||
if ( fd < 0 ) {
|
||||
ERROR_INFO("Cannot open block device %s", blkdev);
|
||||
return -1;
|
||||
} else {
|
||||
if ( fstat(fd, &st) != 0 || ! S_ISBLK(st.st_mode) || makedev(maj, min) != st.st_rdev ) {
|
||||
ERROR("Block device %s does not have id %d:%d\n", blkdev, maj, min);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if ( partition > 0 ) {
|
||||
|
||||
/* Select partition */
|
||||
|
||||
len = strlen(blkdev);
|
||||
if ( sizeof(blkdev) <= len+2 ) {
|
||||
ERROR("Block device name is too long");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( snprintf(blkdev+len, sizeof(blkdev)-len, "p%d", partition) >= (int)(sizeof(blkdev)-len) ) {
|
||||
ERROR("Block device name is too long");
|
||||
return -1;
|
||||
}
|
||||
fd = open(blkdev, ((simulate || readonly) ? O_RDONLY : O_RDWR) | O_EXCL);
|
||||
if ( fd < 0 && errno == ENOENT ) {
|
||||
if ( snprintf(blkdev+len, sizeof(blkdev)-len, "%d", partition) >= (int)(sizeof(blkdev)-len) ) {
|
||||
ERROR("Block device name is too long");
|
||||
return -1;
|
||||
}
|
||||
fd = open(blkdev, ((simulate || readonly) ? O_RDONLY : O_RDWR) | O_EXCL);
|
||||
}
|
||||
if ( fd < 0 && errno == ENOENT ) {
|
||||
blkdev[len] = 0;
|
||||
fd = open(blkdev, O_RDONLY | O_NONBLOCK);
|
||||
if ( fd < 0 ) {
|
||||
ERROR_INFO("Cannot open block device %s", blkdev);
|
||||
} else {
|
||||
close(fd);
|
||||
ERROR("Block device %s does not have partitions", blkdev);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if ( fd < 0 )
|
||||
old_errno = errno;
|
||||
|
||||
printf("Found block device %s for partition %d\n", blkdev, partition);
|
||||
|
||||
if ( fd < 0 ) {
|
||||
errno = old_errno;
|
||||
ERROR_INFO("Cannot open block device %s", blkdev);
|
||||
} else if ( fstat(fd, &st) != 0 || ! S_ISBLK(st.st_mode) ) {
|
||||
ERROR("Block device %s is not block device\n", blkdev);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ERROR("Invalid partition %d for block device %s", partition, blkdev);
|
||||
fd = -1;
|
||||
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
||||
#else
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)min;
|
||||
(void)maj;
|
||||
(void)partition;
|
||||
(void)readonly;
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int disk_dump_dev(int fd, const char * file) {
|
||||
|
||||
int fd2 = -1;
|
||||
int ret;
|
||||
char * path;
|
||||
uint64_t blksize;
|
||||
size_t need, sent;
|
||||
ssize_t size;
|
||||
struct statvfs buf;
|
||||
|
||||
printf("Dump block device to file %s...\n", file);
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 ) {
|
||||
ERROR_INFO("Cannot get size of block device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
blksize = lseek(fd, 0, SEEK_END);
|
||||
if ( (off_t)blksize == (off_t)-1 ) {
|
||||
ERROR_INFO("Cannot get size of block device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( lseek(fd, 0, SEEK_SET) == (off_t)-1 ) {
|
||||
ERROR_INFO("Cannot seek to begin of block device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( blksize == 0 ) {
|
||||
ERROR("Block device has zero size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
path = strdup(file);
|
||||
if ( ! path ) {
|
||||
ALLOC_ERROR();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = statvfs(dirname(path), &buf);
|
||||
|
||||
free(path);
|
||||
|
||||
if ( ret == 0 && buf.f_bsize * buf.f_bfree < blksize ) {
|
||||
ERROR("Not enough free space (have: %llu, need: %llu)", (unsigned long long int)(buf.f_bsize) * buf.f_bfree, (unsigned long long int)blksize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ! simulate ) {
|
||||
|
||||
fd2 = creat(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
if ( fd2 < 0 ) {
|
||||
ERROR_INFO("Cannot create file %s", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sent = 0;
|
||||
printf_progressbar(0, blksize);
|
||||
|
||||
while ( sent < blksize ) {
|
||||
need = blksize - sent;
|
||||
if ( need > sizeof(global_buf) )
|
||||
need = sizeof(global_buf);
|
||||
size = read(fd, global_buf, need);
|
||||
if ( size == 0 )
|
||||
break;
|
||||
if ( size < 0 ) {
|
||||
PRINTF_ERROR("Reading from block device failed");
|
||||
if ( ! simulate )
|
||||
close(fd2);
|
||||
return -1;
|
||||
}
|
||||
if ( ! simulate ) {
|
||||
if ( write(fd2, global_buf, size) != size ) {
|
||||
PRINTF_ERROR("Dumping image failed");
|
||||
close(fd2);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sent += size;
|
||||
printf_progressbar(sent, blksize);
|
||||
}
|
||||
|
||||
if ( ! simulate )
|
||||
close(fd2);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int disk_flash_dev(int fd, struct image * image) {
|
||||
|
||||
uint64_t blksize;
|
||||
size_t need, sent;
|
||||
ssize_t size;
|
||||
|
||||
if ( image->type != IMAGE_MMC )
|
||||
ERROR_RETURN("Only mmc images are supported", -1);
|
||||
|
||||
printf("Writing image to block device...\n");
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 ) {
|
||||
ERROR_INFO("Cannot get size of block device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
blksize = lseek(fd, 0, SEEK_END);
|
||||
if ( (off_t)blksize == (off_t)-1 ) {
|
||||
ERROR_INFO("Cannot get size of block device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( lseek(fd, 0, SEEK_SET) == (off_t)-1 ) {
|
||||
ERROR_INFO("Cannot seek to begin of block device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( blksize == 0 )
|
||||
ERROR_RETURN("Block device has zero size", -1);
|
||||
|
||||
if ( image->size > blksize )
|
||||
ERROR_RETURN("Image is too big", -1);
|
||||
|
||||
sent = 0;
|
||||
printf_progressbar(0, image->size);
|
||||
|
||||
while ( sent < image->size ) {
|
||||
need = image->size - sent;
|
||||
if ( need > sizeof(global_buf) )
|
||||
need = sizeof(global_buf);
|
||||
size = image_read(image, global_buf, need);
|
||||
if ( size == 0 ) {
|
||||
PRINTF_ERROR("Failed to read image");
|
||||
return -1;
|
||||
}
|
||||
if ( ! simulate ) {
|
||||
if ( write(fd, global_buf, size) != size ) {
|
||||
PRINTF_ERROR("Writing image failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sent += size;
|
||||
printf_progressbar(sent, image->size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int disk_init(struct usb_device_info * dev) {
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
int fd;
|
||||
int maj1;
|
||||
int maj2;
|
||||
int min1;
|
||||
int min2;
|
||||
int tmp;
|
||||
|
||||
maj1 = -1;
|
||||
maj2 = -1;
|
||||
min1 = -1;
|
||||
min2 = -1;
|
||||
|
||||
FILE * f;
|
||||
DIR * dir;
|
||||
struct dirent * dirent;
|
||||
char buf[1024];
|
||||
unsigned int devnum;
|
||||
unsigned int busnum;
|
||||
|
||||
libusb_device * device;
|
||||
|
||||
device = libusb_get_device(dev->udev);
|
||||
|
||||
dir = opendir("/sys/dev/block/");
|
||||
if ( ! dir ) {
|
||||
ERROR_INFO("Cannot open '/sys/dev/block/' directory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( ( dirent = readdir(dir) ) ) {
|
||||
|
||||
if ( strncmp(dirent->d_name, ".", sizeof(".")) == 0 || strncmp(dirent->d_name, "..", sizeof("..")) == 0 )
|
||||
continue;
|
||||
|
||||
if ( snprintf(buf, sizeof(buf), "/sys/dev/block/%s/device/../../../../busnum", dirent->d_name) <= 0 )
|
||||
continue;
|
||||
|
||||
f = fopen(buf, "r");
|
||||
if ( ! f )
|
||||
continue;
|
||||
|
||||
if ( fscanf(f, "%u", &busnum) != 1 ) {
|
||||
fclose(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if ( snprintf(buf, sizeof(buf), "/sys/dev/block/%s/device/../../../../devnum", dirent->d_name) <= 0 )
|
||||
continue;
|
||||
|
||||
f = fopen(buf, "r");
|
||||
if ( ! f )
|
||||
continue;
|
||||
|
||||
if ( fscanf(f, "%u", &devnum) != 1 ) {
|
||||
fclose(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if ( (unsigned int)libusb_get_device_address(device) != devnum )
|
||||
continue;
|
||||
|
||||
if ( (unsigned int)libusb_get_bus_number(device) != busnum )
|
||||
continue;
|
||||
|
||||
if ( sscanf(dirent->d_name, "%d:%d", &maj2, &min2) != 2 ) {
|
||||
maj2 = -1;
|
||||
min2 = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( maj1 != -1 && min1 != -1 && maj2 != -1 && min2 != -1 )
|
||||
break;
|
||||
|
||||
maj1 = maj2;
|
||||
min1 = min2;
|
||||
maj2 = -1;
|
||||
min2 = -1;
|
||||
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if ( maj1 == -1 || min1 == -1 ) {
|
||||
ERROR("Cannot find id for mmc block disk device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ensure that maj1:min1 is first device and maj2:min2 is second device */
|
||||
if ( min2 != -1 && min2 < min1 ) {
|
||||
tmp = min1;
|
||||
min1 = min2;
|
||||
min2 = tmp;
|
||||
tmp = maj1;
|
||||
maj1 = maj2;
|
||||
maj2 = tmp;
|
||||
}
|
||||
|
||||
/* RX-51, RM-680 and RM-696 export MyDocs in first usb device and just first partion, so host system see whole device without MBR table */
|
||||
if ( dev->device == DEVICE_RX_51 || dev->device == DEVICE_RM_680 || dev->device == DEVICE_RM_696 )
|
||||
fd = disk_open_dev(maj1, min1, -1, simulate ? 1 : 0);
|
||||
/* Other devices can export SD card as first partition and export whole mmc device, so host system will see MBR table */
|
||||
else if ( maj2 != -1 && min2 != -1 )
|
||||
fd = disk_open_dev(maj2, min2, 1, simulate ? 1 : 0);
|
||||
else
|
||||
fd = disk_open_dev(maj1, min1, 1, simulate ? 1 : 0);
|
||||
|
||||
if ( fd < 0 )
|
||||
return -1;
|
||||
|
||||
dev->data = fd;
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
return -1;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void disk_exit(struct usb_device_info * dev) {
|
||||
|
||||
if ( dev->data >= 0 )
|
||||
close(dev->data);
|
||||
|
||||
}
|
||||
|
||||
enum device disk_get_device(struct usb_device_info * dev) {
|
||||
|
||||
return dev->device;
|
||||
|
||||
}
|
||||
|
||||
int disk_flash_image(struct usb_device_info * dev, struct image * image) {
|
||||
|
||||
int ret;
|
||||
|
||||
printf("Flash image:\n");
|
||||
image_print_info(image);
|
||||
|
||||
ret = disk_flash_dev(dev->data, image);
|
||||
if ( ret == 0 )
|
||||
printf("Done\n");
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file) {
|
||||
|
||||
if ( image != IMAGE_MMC )
|
||||
ERROR_RETURN("Only mmc images are supported", -1);
|
||||
|
||||
return disk_dump_dev(dev->data, file);
|
||||
|
||||
}
|
||||
|
||||
int disk_check_badblocks(struct usb_device_info * dev, const char * device) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)device;
|
||||
return -1;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DISK_H
|
||||
#define DISK_H
|
||||
|
||||
#include "image.h"
|
||||
#include "device.h"
|
||||
#include "usb-device.h"
|
||||
|
||||
int disk_init(struct usb_device_info * dev);
|
||||
void disk_exit(struct usb_device_info * dev);
|
||||
|
||||
enum device disk_get_device(struct usb_device_info * dev);
|
||||
|
||||
int disk_open_dev(int maj, int min, int partition, int readonly);
|
||||
int disk_dump_dev(int fd, const char * file);
|
||||
int disk_flash_dev(int fd, struct image * image);
|
||||
|
||||
int disk_flash_image(struct usb_device_info * dev, struct image * image);
|
||||
int disk_dump_image(struct usb_device_info * dev, enum image_type image, const char * file);
|
||||
int disk_check_badblocks(struct usb_device_info * dev, const char * device);
|
||||
|
||||
#endif
|
||||
-581
@@ -1,581 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "hexdump.h"
|
||||
#include <usb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Extracts a piece from an mtd device
|
||||
* -----------------------------------
|
||||
* This function is known to be buggy, It does not takes care about
|
||||
* badblocks and oob data. It is replaced by nanddump(), but will
|
||||
* probably be fixed in the future or it will die.
|
||||
*/
|
||||
int rf_extract(char *dev, off_t from, off_t to, char *file)
|
||||
{
|
||||
off_t i, blk = 0xfffff;
|
||||
char buf[0xfffff];
|
||||
FILE *fs = fopen(dev, "rb");
|
||||
FILE *fd = fopen(file, "wb+");
|
||||
|
||||
if (from>to) {
|
||||
printf("Bad range %lld - %lld for %s\n", from, to, file);
|
||||
goto __rf_extract_exit;
|
||||
}
|
||||
if (fs == NULL) { perror(dev); goto __rf_extract_exit; }
|
||||
if (fd == NULL) { perror(file); goto __rf_extract_exit; }
|
||||
|
||||
printf("Extracting %s...\n", file);
|
||||
fseek(fs, from, SEEK_SET);
|
||||
|
||||
for(i=from;i<to;i+=blk) {
|
||||
int ret;
|
||||
if (i+blk>to) blk = to-i;
|
||||
ret = fread(buf, blk, 1, fs);
|
||||
progressbar(i, to);
|
||||
if (!ret || feof(fs)) break;
|
||||
fwrite(buf, blk, 1, fd);
|
||||
}
|
||||
|
||||
printf("\r%s: %lld bytes dumped from %s\n",
|
||||
file, to-from, dev);
|
||||
|
||||
__rf_extract_exit:
|
||||
if (fs) fclose(fs);
|
||||
if (fd) fclose(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function was covardly copied from nanddump.c @ mtd-utils-20060907
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <asm/types.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
|
||||
#define M_RDONLY 0x00000001
|
||||
#define M_RDRW 0x00000002
|
||||
#define M_OMITOOB 0x00000010
|
||||
#define M_OMITBAD 0x00000011
|
||||
#define M_OMITECC 0x00000012
|
||||
|
||||
int mtd_open(char *file, mtd_info_t *meminfo, int *oobinfochanged,
|
||||
struct nand_oobinfo *old_oobinfo, int *eccstats, int flags)
|
||||
{
|
||||
int fd;
|
||||
*oobinfochanged = 0 ;
|
||||
|
||||
fd = open(file, (flags&M_RDONLY)?O_RDONLY:O_RDWR);
|
||||
if (fd == -1) {
|
||||
perror("mtd_open");
|
||||
return -1;
|
||||
}
|
||||
/* Fill in MTD device capability structure */
|
||||
if (ioctl(fd, MEMGETINFO, meminfo) != 0) {
|
||||
perror("MEMGETINFO");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make sure device page sizes are valid */
|
||||
if (!(meminfo->oobsize == 64 && meminfo->writesize == 2048) &&
|
||||
!(meminfo->oobsize == 16 && meminfo->writesize == 512) &&
|
||||
!(meminfo->oobsize == 8 && meminfo->writesize == 256)) {
|
||||
fprintf(stderr, "Unknown flash (not normal NAND)\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int mtd_close(int fd, struct nand_oobinfo *old_oobinfo, int oobinfochanged)
|
||||
{
|
||||
if (fd == -1)
|
||||
return 1;
|
||||
|
||||
/* reset oobinfo */
|
||||
if (oobinfochanged == 1) {
|
||||
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
|
||||
perror ("MEMSETOOBSEL");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Close the output file and MTD device */
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
// configuration for nanddump //
|
||||
//int noecc = 0; // don't error correct
|
||||
int omitoob = 1; // omit oob data
|
||||
int omitbad = 1;
|
||||
// configuration for nanddump //
|
||||
|
||||
#define CONFIGURE_FLAGS(x) \
|
||||
omitoob = x & M_OMITOOB; \
|
||||
omitbad = x & M_OMITBAD;
|
||||
|
||||
int check_badblocks(char *mtddev)
|
||||
{
|
||||
int fd;
|
||||
int oobinfochanged = 0 ;
|
||||
int badblock = 0;
|
||||
int badblocks = 1;
|
||||
int eccstats = 0;
|
||||
unsigned long int i;
|
||||
unsigned long long blockstart = 1;
|
||||
unsigned char oobbuf[64];
|
||||
struct nand_oobinfo old_oobinfo;
|
||||
struct mtd_oob_buf oob = {0, 16, oobbuf};
|
||||
struct mtd_ecc_stats stat1, stat2;
|
||||
mtd_info_t meminfo;
|
||||
|
||||
fd = mtd_open(mtddev, &meminfo, &oobinfochanged, &old_oobinfo, &eccstats, M_RDONLY);
|
||||
|
||||
if (fd == -1) {
|
||||
printf("cannot open mtd\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
|
||||
meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
|
||||
fprintf(stderr, "Size %u, flags %u, type 0x%x\n",
|
||||
meminfo.size, meminfo.flags, (int)meminfo.type);
|
||||
|
||||
|
||||
oob.length = meminfo.oobsize;
|
||||
for(i = 0; i < meminfo.size; i+= meminfo.writesize) {
|
||||
|
||||
// new eraseblock , check for bad block
|
||||
if (blockstart != (i & (~meminfo.erasesize + 1))) {
|
||||
blockstart = i & (~meminfo.erasesize + 1);
|
||||
if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
|
||||
perror("ioctl(MEMGETBADBLOCK)");
|
||||
goto closeall;
|
||||
}
|
||||
}
|
||||
|
||||
if (badblock) {
|
||||
if (omitbad) {
|
||||
printf("Bad block found at 0x%lx\n", i);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
char readbuf[2048]; // XXX hardcoded like mtd-utils?? ugly!
|
||||
// dummy -- should be removed
|
||||
if (pread(fd, readbuf, meminfo.writesize, i) != meminfo.writesize) {
|
||||
perror("pread");
|
||||
goto closeall;
|
||||
}
|
||||
}
|
||||
|
||||
/* ECC stats available ? */
|
||||
if (eccstats) {
|
||||
if (ioctl(fd, ECCGETSTATS, &stat2)) {
|
||||
perror("ioctl(ECCGETSTATS)");
|
||||
goto closeall;
|
||||
}
|
||||
if (stat1.failed != stat2.failed)
|
||||
fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
|
||||
" at offset 0x%08lx\n",
|
||||
stat2.failed - stat1.failed, i);
|
||||
if (stat1.corrected != stat2.corrected)
|
||||
fprintf(stderr, "ECC: %d corrected bitflip(s) at"
|
||||
" offset 0x%08lx\n",
|
||||
stat2.corrected - stat1.corrected, i);
|
||||
stat1 = stat2;
|
||||
}
|
||||
|
||||
if (badblock) {
|
||||
printf("Oops badblock %d at 0x%lx !\n", badblocks++, i);
|
||||
} else {
|
||||
/* Read OOB data and exit on failure */
|
||||
oob.start = i;
|
||||
if (ioctl(fd, MEMREADOOB, &oob) != 0) {
|
||||
perror("ioctl(MEMREADOOB)");
|
||||
goto closeall;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write out OOB data */
|
||||
if (badblock)
|
||||
D dump_bytes(oobbuf, meminfo.oobsize);
|
||||
}
|
||||
|
||||
mtd_close(fd, &old_oobinfo, oobinfochanged);
|
||||
return 0;
|
||||
|
||||
closeall:
|
||||
mtd_close(fd, &old_oobinfo, oobinfochanged);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// XXX warning ioob is not used
|
||||
int nanddump(char *mtddev, unsigned long start_addr, unsigned long length, char *dumpfile, int isbl, int ioob)
|
||||
{
|
||||
unsigned char readbuf[2048];
|
||||
int oobinfochanged = 0 ;
|
||||
unsigned char oobbuf[64];
|
||||
unsigned long ofs, end_addr = 0;
|
||||
unsigned long long blockstart = 1;
|
||||
struct nand_oobinfo none_oobinfo = {
|
||||
.useecc = MTD_NANDECC_OFF,
|
||||
};
|
||||
int fd, ofd, bs, badblock = 0;
|
||||
struct mtd_oob_buf oob = {0, 16, oobbuf};
|
||||
mtd_info_t meminfo;
|
||||
int badblocks = 1;
|
||||
struct nand_oobinfo old_oobinfo;
|
||||
int eccstats = 0;
|
||||
struct mtd_ecc_stats stat1, stat2;
|
||||
int flags = M_RDONLY;
|
||||
|
||||
printf("\nExtracting %s from %s...\n", dumpfile, mtddev);
|
||||
|
||||
fd = mtd_open(mtddev, &meminfo, &oobinfochanged, &old_oobinfo, &eccstats, flags);
|
||||
|
||||
if (meminfo.writesize == 0) {
|
||||
printf("What the fuck.. this is not an MTD device!\n");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read the real oob length */
|
||||
oob.length = meminfo.oobsize;
|
||||
fprintf(stderr, "Block size %u, page size %u, OOB size %u\n",
|
||||
meminfo.erasesize, meminfo.writesize, meminfo.oobsize);
|
||||
fprintf(stderr, "Size %u, flags %u, type 0x%x\n",
|
||||
meminfo.size, meminfo.flags, (int)meminfo.type);
|
||||
|
||||
if (flags & M_OMITECC) { // (noecc)
|
||||
switch (ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW)) {
|
||||
case -ENOTTY:
|
||||
if (ioctl (fd, MEMGETOOBSEL, old_oobinfo) != 0) {
|
||||
perror ("MEMGETOOBSEL");
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
if (ioctl (fd, MEMSETOOBSEL, none_oobinfo) != 0) {
|
||||
perror ("MEMSETOOBSEL");
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
oobinfochanged = 1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
oobinfochanged = 2;
|
||||
break;
|
||||
default:
|
||||
perror ("MTDFILEMODE");
|
||||
close (fd);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* check if we can read ecc stats */
|
||||
if (!ioctl(fd, ECCGETSTATS, &stat1)) {
|
||||
eccstats = 1;
|
||||
fprintf(stderr, "ECC failed: %d\n", stat1.failed);
|
||||
fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
|
||||
fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
|
||||
fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
|
||||
} else
|
||||
perror("No ECC status information available");
|
||||
}
|
||||
|
||||
/* Open output file for writing. If file name is "-", write to standard
|
||||
* output. */
|
||||
if (!dumpfile) {
|
||||
ofd = STDOUT_FILENO;
|
||||
} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
|
||||
perror ("open outfile");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize start/end addresses and block size */
|
||||
if (length)
|
||||
end_addr = start_addr + length;
|
||||
if (!length || end_addr > meminfo.size)
|
||||
end_addr = meminfo.size;
|
||||
|
||||
bs = meminfo.writesize;
|
||||
|
||||
fprintf(stderr,
|
||||
"Dumping data starting at 0x%08x and ending at 0x%08x...\n",
|
||||
(unsigned int) start_addr, (unsigned int) end_addr);
|
||||
|
||||
/* Dump the flash contents */
|
||||
for (ofs = start_addr; ofs < end_addr ; ofs+=bs) {
|
||||
// new eraseblock , check for bad block
|
||||
if (blockstart != (ofs & (~meminfo.erasesize + 1))) {
|
||||
blockstart = ofs & (~meminfo.erasesize + 1);
|
||||
if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) {
|
||||
perror("ioctl(MEMGETBADBLOCK)");
|
||||
goto closeall;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isbl && badblock) {
|
||||
if (omitbad)
|
||||
continue;
|
||||
memset (readbuf, 0xff, bs);
|
||||
} else {
|
||||
/* Read page data and exit on failure */
|
||||
if (pread(fd, readbuf, bs, ofs) != bs) {
|
||||
perror("pread");
|
||||
goto closeall;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO exist on n800??? // remove code?
|
||||
/* ECC stats available ? */
|
||||
if (eccstats) {
|
||||
if (ioctl(fd, ECCGETSTATS, &stat2)) {
|
||||
perror("ioctl(ECCGETSTATS)");
|
||||
goto closeall;
|
||||
}
|
||||
if (stat1.failed != stat2.failed)
|
||||
fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
|
||||
" at offset 0x%08lx\n",
|
||||
stat2.failed - stat1.failed, ofs);
|
||||
if (stat1.corrected != stat2.corrected)
|
||||
fprintf(stderr, "ECC: %d corrected bitflip(s) at"
|
||||
" offset 0x%08lx\n",
|
||||
stat2.corrected - stat1.corrected, ofs);
|
||||
stat1 = stat2;
|
||||
}
|
||||
|
||||
/* Write out page data */
|
||||
//if (pretty_print) dump_bytes(readbuf, bs);
|
||||
progressbar(ofs, end_addr);
|
||||
|
||||
// OOB STUFF //
|
||||
if (omitoob)
|
||||
continue;
|
||||
|
||||
if (!isbl&&badblock) {
|
||||
printf("Oops badblock %d *ignored* at 0x%lx !\n", badblocks++, ofs);
|
||||
memset (readbuf, 0xff, meminfo.oobsize);
|
||||
} else {
|
||||
/* Read OOB data and exit on failure */
|
||||
oob.start = ofs;
|
||||
if (ioctl(fd, MEMREADOOB, &oob) != 0) {
|
||||
perror("ioctl(MEMREADOOB)");
|
||||
goto closeall;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write out OOB data */
|
||||
D dump_bytes(oobbuf, meminfo.oobsize);
|
||||
write(ofd, oobbuf, meminfo.oobsize);
|
||||
}
|
||||
|
||||
mtd_close(fd, &old_oobinfo, oobinfochanged);
|
||||
close(ofd);
|
||||
|
||||
return 0;
|
||||
|
||||
closeall:
|
||||
mtd_close(fd, &old_oobinfo, oobinfochanged);
|
||||
close(ofd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rf_strip(char *file)
|
||||
{
|
||||
FILE *fd = fopen(file, "rw");
|
||||
unsigned char buf[4096];
|
||||
int ret;
|
||||
off_t eof = 0;
|
||||
|
||||
if (!fd) {
|
||||
fprintf(stderr, "Weird! can't open %s???\n", file);
|
||||
exit(0);
|
||||
}
|
||||
printf("Stripping padding from %s... ", file);
|
||||
fflush(stdout);
|
||||
fseek(fd, 0, SEEK_END);
|
||||
if (ftell(fd)>4096) {
|
||||
do {
|
||||
fseek(fd, -4096, SEEK_CUR);
|
||||
ret = fread(buf, 1, 4096, fd);
|
||||
fseek(fd, -4096, SEEK_CUR);
|
||||
for(ret--;ret>0;ret--)
|
||||
if (buf[ret]!=0xff) {
|
||||
fseek(fd, ret+1, SEEK_CUR);
|
||||
eof = ftell(fd);
|
||||
goto __done;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
__done:
|
||||
fclose(fd);
|
||||
if (eof) truncate(file, eof);
|
||||
printf("done at %d\n", (int)eof);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int is_n800()
|
||||
{
|
||||
int n800 = 0;
|
||||
unsigned char buf[4];
|
||||
FILE *fd = fopen("/dev/mtd0", "rb");
|
||||
|
||||
if (!fd) {
|
||||
fprintf(stderr, "Cannot open /dev/mtd0.\n");
|
||||
exit(1);
|
||||
}
|
||||
fread(buf, 4, 1,fd);
|
||||
if (!memcmp("\xff\xff\xff\xff", buf, 4))
|
||||
n800 = 1;
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return n800;
|
||||
}
|
||||
|
||||
int dump_config()
|
||||
{
|
||||
mtd_info_t meminfo;
|
||||
int fd = open("/dev/mtd1", O_RDONLY);
|
||||
char buf[1024];
|
||||
int i=0,j;
|
||||
int ret;
|
||||
|
||||
|
||||
if (fd == -1) {
|
||||
perror("open /dev/mtd1");
|
||||
return 1;
|
||||
}
|
||||
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
|
||||
perror("MEMGETINFO");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(i<0x60000) {
|
||||
iniloop:
|
||||
ret = read(fd, buf, 4);
|
||||
if (ret == -1)
|
||||
break;
|
||||
if (!memcmp(buf,"ConF", 4)) {
|
||||
loop:
|
||||
read(fd, buf, 4);
|
||||
if (ret == -1) break;
|
||||
printf("\n0x%08x : ConF %02x %02x %02x %02x : ", i,
|
||||
buf[0], buf[1], buf[2], buf[3]);
|
||||
fflush(stdout);
|
||||
while(1) {
|
||||
ret = read(fd, buf, 4);
|
||||
if (ret <1) {
|
||||
printf("Unexpected eof\n");
|
||||
break;
|
||||
}
|
||||
if (buf[0]=='\0'||buf[1]=='\0'||buf[2]=='\0'||buf[3]=='\0') {
|
||||
printf("%s \t ", buf);
|
||||
fflush(stdout);
|
||||
while(1) {
|
||||
ret = read(fd, buf, 4);
|
||||
if (ret <1) {
|
||||
printf("Unexpected eof\n");
|
||||
break;
|
||||
}
|
||||
if (!memcmp(buf,"\xff\xff\xff\xff", 4))
|
||||
goto iniloop;
|
||||
if (!memcmp(buf,"ConF", 4))
|
||||
goto loop;
|
||||
printf ("%02x %02x %02x %02x ",
|
||||
buf[0], buf[1], buf[2], buf[3]);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
write(1, buf,4);
|
||||
}
|
||||
}
|
||||
}
|
||||
j = lseek(fd, 0, SEEK_CUR);
|
||||
if (j==i) break; i = j;
|
||||
}
|
||||
close(fd);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reverse_extract_pieces(char *dir)
|
||||
{
|
||||
char reply;
|
||||
chdir(dir);
|
||||
|
||||
// TODO: get values from /proc/mtd ???
|
||||
|
||||
//rf_extract("/dev/mtd0", is_n800()?0x200:0, 0x003600, "xloader.bin");
|
||||
nanddump("/dev/mtd0", is_n800()?0x200:0, 0x4000, "xloader.bin", 1,0); // 0x3600 size?
|
||||
//rf_extract("/dev/mtd0", 0x004000, 0x01ffff, "secondary.bin");
|
||||
nanddump("/dev/mtd0", 0x004000, 0, "secondary.bin", 1,0);
|
||||
nanddump("/dev/mtd1", 0, 0, "config.bin", 0,0);
|
||||
//rf_extract("/dev/mtd2", 0x000800, 0x200000, "zImage");
|
||||
nanddump("/dev/mtd2", 0x000800, 0, "zImage", 0,0);
|
||||
//rf_extract("/dev/mtd3", 0x000000, 0x1D00000, "initfs.jffs2");
|
||||
nanddump("/dev/mtd3", 0x000000, 0, "initfs.jffs2", 0,0);
|
||||
|
||||
printf("\n\nExtract rootfs? (y/N): "); fflush(stdout);
|
||||
read(0, &reply, 1);
|
||||
if (reply=='y'||reply=='Y') {
|
||||
//rf_extract("/dev/mtd4", 0x000000, 0x6000000, "rootfs.jffs2");
|
||||
nanddump("/dev/mtd4", 0x000000, 0, "rootfs.jffs2", 0,0);
|
||||
} else printf("*** Ignoring rootfs\n");
|
||||
|
||||
printf("\n\nStrip dumped files? (y/N): "); fflush(stdout);
|
||||
read(0, &reply, 1);
|
||||
if (reply=='y'||reply=='Y') {
|
||||
rf_strip("xloader.bin");
|
||||
rf_strip("secondary.bin");
|
||||
rf_strip("zImage");
|
||||
rf_strip("initfs.jffs2");
|
||||
} else printf("*** Ignoring strip\n");
|
||||
|
||||
printf("\nIdentifying extracted files...\n");
|
||||
printf("%s: xloader\n", fpid_file("xloader.bin"));
|
||||
printf("%s: secondary.bin\n", fpid_file("secondary.bin"));
|
||||
printf("%s: config.bin\n", fpid_file("config.bin"));
|
||||
printf("%s: zImage\n", fpid_file("zImage"));
|
||||
printf("%s: initfs.jffs2\n", fpid_file("initfs.jffs2"));
|
||||
printf("%s: rootfs.jffs2\n", fpid_file("rootfs.jffs2"));
|
||||
|
||||
return 1;
|
||||
}
|
||||
+756
-250
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2007-2011 pancake <pancake@youterm.com>
|
||||
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FIASCO_H
|
||||
#define FIASCO_H
|
||||
|
||||
#include "image.h"
|
||||
|
||||
struct fiasco {
|
||||
char name[257];
|
||||
char swver[257];
|
||||
int fd;
|
||||
char * orig_filename;
|
||||
struct image_list * first;
|
||||
};
|
||||
|
||||
struct fiasco * fiasco_alloc_empty(void);
|
||||
struct fiasco * fiasco_alloc_from_file(const char * file);
|
||||
void fiasco_free(struct fiasco * fiasco);
|
||||
void fiasco_add_image(struct fiasco * fiasco, struct image * image);
|
||||
int fiasco_write_to_file(struct fiasco * fiasco, const char * file);
|
||||
int fiasco_unpack(struct fiasco * fiasco, const char * dir);
|
||||
void fiasco_print_info(struct fiasco * fiasco);
|
||||
|
||||
#endif
|
||||
-197
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "hash.h"
|
||||
#include "hexdump.h"
|
||||
#include <usb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void check_nolo_order_failed()
|
||||
{
|
||||
fprintf(stderr, "\nERROR: Provide xloader before the secondary. NOLO disagrees anything else.\n");
|
||||
fprintf(stderr, "Use: -p xloader.bin -p secondary.bin\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void query_error_message()
|
||||
{
|
||||
/* query error message */
|
||||
int len = 0;
|
||||
char nolomsg[2048];
|
||||
memset(nolomsg, '\0', 2048);
|
||||
usb_control_msg(dev, 192, 5, 0, 0, nolomsg, 2048, 2000);
|
||||
nolomsg[2047] = '\0';
|
||||
printf("\nNOLO says:\n");
|
||||
if (nolomsg[0] == '\0') {
|
||||
printf(" (.. silence ..)\n");
|
||||
} else {
|
||||
dump_bytes((unsigned char *)nolomsg, 128);
|
||||
do {
|
||||
printf(" - %s\n", nolomsg+len);
|
||||
len+=strlen(nolomsg+len)+1;
|
||||
} while(nolomsg[len]!='\0');
|
||||
}
|
||||
}
|
||||
|
||||
void check_nolo_order()
|
||||
{
|
||||
int i, xlo = 0;
|
||||
|
||||
for(i=0;i<pcs_n;i++) {
|
||||
if (!strcmp(pcs[i].type, "xloader")) {
|
||||
if (!xlo && ++i<pcs_n) {
|
||||
printf("CHK%s\n", pcs[i].type);
|
||||
xlo++;
|
||||
if (!strcmp(pcs[i].type, "secondary")) {
|
||||
xlo = 0x11;
|
||||
break;
|
||||
} else check_nolo_order_failed();
|
||||
} check_nolo_order_failed();
|
||||
} else
|
||||
if (!strcmp(pcs[i].type, "secondary"))
|
||||
check_nolo_order_failed();
|
||||
}
|
||||
|
||||
if (xlo && xlo != 0x11)
|
||||
check_nolo_order_failed();
|
||||
}
|
||||
|
||||
void flash_image(char *filename, char *piece, char *version)
|
||||
{
|
||||
FILE *fd;
|
||||
int vlen = 0;
|
||||
int request;
|
||||
/*/ n800 flash queries have a variable size */
|
||||
unsigned char fquery[256]; /* flash query */
|
||||
unsigned long long size, off;
|
||||
unsigned char bsize[4], tmp;
|
||||
unsigned char nolofiller[128];
|
||||
ushort hash = do_hash_file(filename);
|
||||
|
||||
if (version)
|
||||
vlen = strlen(version)+1;
|
||||
|
||||
fd = fopen(filename, "rb");
|
||||
if (fd == NULL) {
|
||||
printf("Cannot open file\n");
|
||||
exit(1);
|
||||
}
|
||||
/* cook flash query */
|
||||
memset(fquery, '\x00', 27); // reset buffer
|
||||
memcpy(fquery, "\x2e\x19\x01\x01", 4); // header
|
||||
//memcpy(fquery+5, "\xbf\x6b", 2); // some magic (modified crc16???)
|
||||
memcpy(fquery+5, &hash, 2);
|
||||
tmp = fquery[5]; fquery[5] = fquery[6]; fquery[6] = tmp;
|
||||
memcpy(fquery+7, piece, strlen(piece)); // XXX ??!??
|
||||
|
||||
printf("| hash: 0x%hhx%hhx ", fquery[5], fquery[6]);
|
||||
size = get_file_size(filename);
|
||||
bsize[0] = (size & 0xff000000) >> 24;
|
||||
bsize[1] = (size & 0x00ff0000) >> 16;
|
||||
bsize[2] = (size & 0x0000ff00) >> 8;
|
||||
bsize[3] = (size & 0x000000ff);
|
||||
printf("size: %lld (%02x %02x %02x %02x)\n",
|
||||
size, bsize[0], bsize[1], bsize[2], bsize[3]);
|
||||
memcpy(fquery+0x13, &bsize, 4);
|
||||
if (vlen) memcpy(fquery+27, version, vlen);
|
||||
|
||||
if (!strcmp(piece, "rootfs"))
|
||||
request = 85;
|
||||
else request = 68;
|
||||
|
||||
//dump_bytes(fquery, 27+vlen);
|
||||
if (usb_control_msg(dev, CMD_WRITE, request, 0, 0, (char *)fquery, 27+vlen, 2000) <0) {
|
||||
query_error_message();
|
||||
perror("flash_image.header");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*/ cook and bulk nollo filler */
|
||||
memset(&nolofiller, '\xff', 128);
|
||||
memcpy(nolofiller+0x00, "NOLO filler", 11);
|
||||
memcpy(nolofiller+0x40, "NOLO filler", 11);
|
||||
usb_bulk_write(dev, 2, (char *)nolofiller, 128, 5000);
|
||||
usb_bulk_write(dev, 2, (char *)nolofiller, 0, 5000);
|
||||
|
||||
/*/ bulk write image here */
|
||||
printf("[=] Bulkwriting the %s piece...\n", piece);
|
||||
fflush(stdout);
|
||||
|
||||
for(off = 0; off<size; off += BSIZE) {
|
||||
char buf[BSIZE];
|
||||
int bread, bsize = size-off;
|
||||
if (bsize>BSIZE) bsize = BSIZE;
|
||||
bread = fread(buf, bsize, 1, fd);
|
||||
if (bread != 1)
|
||||
printf("WARNING: Oops wrong read %d vs %d \n", bread, bsize);
|
||||
bread = usb_bulk_write(dev, 2, buf, bsize, 5000);
|
||||
if (bread == 64) {
|
||||
query_error_message();
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
progressbar(off, size);
|
||||
if (bread<0) {
|
||||
printf("\n");
|
||||
perror(" -ee- ");
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
fclose(fd);
|
||||
/*/ EOF */
|
||||
usb_bulk_write(dev, 2, (char *)nolofiller, 0, 1000);
|
||||
progressbar(1, 1);
|
||||
printf("\n");
|
||||
|
||||
// index = 4????
|
||||
if (!strcmp(piece, "rootfs")) {
|
||||
if (usb_control_msg(dev, CMD_WRITE, 82, 0, 0, (char *)fquery, 0, 30000)<0) {
|
||||
fprintf(stderr, "Oops. Invalid checksum?\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
int t = 0;
|
||||
if (!strcmp(piece, "secondary"))
|
||||
t = 1;
|
||||
else
|
||||
if (!strcmp(piece, "kernel"))
|
||||
t = 3;
|
||||
else
|
||||
if (!strcmp(piece, "initfs"))
|
||||
t = 4;
|
||||
if (!strcmp(piece, "xloader"))
|
||||
printf("xloader flashed not commiting until secondary arrives...\n");
|
||||
else
|
||||
if (usb_control_msg(dev, CMD_WRITE, 80, 0, t, (char *)fquery, 0, 10000)<0) {
|
||||
fprintf(stderr, "Oops. Invalid checksum?\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// unknown query !! :""
|
||||
if (usb_control_msg(dev, CMD_WRITE, 67, 0, 0, (char *)fquery, 0, 2000)<0) {
|
||||
fprintf(stderr, "Oops, the flash was denied or so :/\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Flash done succesfully.\n");
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *fpid_file(const char *filename)
|
||||
{
|
||||
FILE *fd;
|
||||
char buf[512];
|
||||
unsigned char *b = (unsigned char *)&buf;
|
||||
char *piece = NULL;
|
||||
long size;
|
||||
|
||||
// 2nd : +0x34 = 2NDAPE
|
||||
// secondary: +0x04 = NOLOScnd
|
||||
// x-loader : +0x14 = X-LOADER
|
||||
// xloader8 : +0x0c = NOLOXldr
|
||||
// kernel : +0x00 = 0000 a0e1 0000 a0e1
|
||||
// initfs : <2M...be sure with 3M 0x300000
|
||||
|
||||
fd = fopen(filename, "r");
|
||||
if (fd == NULL) {
|
||||
printf("Cannot open file '%s'\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
fread(buf, 512, 1, fd);
|
||||
fseek(fd, 0, SEEK_END);
|
||||
size = ftell(fd);
|
||||
fclose(fd);
|
||||
|
||||
if (!memcmp(b+0x34, "2NDAPE", 6))
|
||||
return pieces[PIECE_2ND];
|
||||
else
|
||||
if (!memcmp(b+0x04, "NOLOScnd", 8))
|
||||
return pieces[PIECE_SECONDARY];
|
||||
else
|
||||
if (!memcmp(b+0x14, "X-LOADER", 8))
|
||||
return pieces[PIECE_XLOADER];
|
||||
else
|
||||
if (!memcmp(b+0x0c, "NOLOXldr", 8)) // TODO: this is xloader800, not valid on 770?
|
||||
return pieces[PIECE_XLOADER];
|
||||
else
|
||||
if (!memcmp(b+0x00, "\x00\x00\xa0\xe1\x00\x00\xa0\xe1", 8))
|
||||
return pieces[PIECE_KERNEL];
|
||||
else
|
||||
// JFFS2 MAGIC
|
||||
if (!memcmp(b+0x00, "\x85\x19", 2)) { //\x01\xe0", 4)) {
|
||||
/*/ is jffs2 */
|
||||
if (size < 0x300000)
|
||||
return pieces[PIECE_INITFS];
|
||||
return pieces[PIECE_ROOTFS];
|
||||
}
|
||||
|
||||
return piece;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
extern int simulate;
|
||||
extern int noverify;
|
||||
extern int verbose;
|
||||
|
||||
#define VERBOSE(...) do { if ( verbose ) { fprintf(stderr, __VA_ARGS__); } } while (0)
|
||||
#define WARNING(...) do { fprintf(stderr, "Warning: "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
|
||||
#define ERROR_INFO_STR(str, ...) do { if ( str[0] ) fprintf(stderr, "Error: %s: ", str); else fprintf(stderr, "Error: "); fprintf(stderr, __VA_ARGS__); if ( errno ) fprintf(stderr, ": %s\n", strerror(errno)); else fprintf(stderr, "\n"); } while (0)
|
||||
#define ERROR_STR(str, ...) do { errno = 0; ERROR_INFO_STR(str, __VA_ARGS__); } while (0)
|
||||
#define ERROR_INFO(...) do { ERROR_INFO_STR("", __VA_ARGS__); } while (0)
|
||||
#define ERROR(...) do { ERROR_STR("", __VA_ARGS__); } while (0)
|
||||
#define ERROR_RETURN(str, ...) do { ERROR("%s", str); return __VA_ARGS__; } while (0)
|
||||
|
||||
#define ALLOC_ERROR() do { ERROR("Cannot allocate memory"); } while (0)
|
||||
#define ALLOC_ERROR_RETURN(...) do { ALLOC_ERROR(); return __VA_ARGS__; } while (0)
|
||||
|
||||
#define MSLEEP(msec) do { nanosleep(&(struct timespec){ (msec / 1000), (1000L * 1000L * (msec % 1000)) }, NULL); } while (0)
|
||||
|
||||
static inline void * MEMMEM(void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
|
||||
for ( size_t i = 0; i < haystacklen; ++i ) {
|
||||
for ( size_t j = 0; j < needlelen; ++j ) {
|
||||
if ( ((char *)haystack)[i+j] != ((const char *)needle)[j] )
|
||||
break;
|
||||
if ( j != needlelen - 1 )
|
||||
continue;
|
||||
return (char *)haystack + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "hash.h"
|
||||
|
||||
usho do_hash(usho *b, int len)
|
||||
{
|
||||
usho result = 0;
|
||||
for(len>>=1;len--;b=b+1)
|
||||
result^=b[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
usho do_hash_file(const char *filename)
|
||||
{
|
||||
unsigned char buf[BSIZE];
|
||||
FILE *fd = fopen(filename, "r");
|
||||
usho hash = 0;
|
||||
int ret;
|
||||
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr, "ERROR: File '%s' not found.\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
do { ret = fread(&buf, 1, BSIZE, fd);
|
||||
if (ret == -1)
|
||||
return 0;
|
||||
hash ^= do_hash((usho *)&buf, ret);
|
||||
} while(ret);
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
#if 0
|
||||
main()
|
||||
{
|
||||
usho us = do_hash_file("zImage");
|
||||
unsigned char *h= (unsigned char *)&us;
|
||||
printf("%x %x\n",h[0],h[1]);
|
||||
}
|
||||
#endif
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
#ifndef _INCLUDE_HASH_H_
|
||||
#define _INCLUDE_HASH_H_
|
||||
|
||||
#define usho unsigned short
|
||||
#define BSIZE 0x20000
|
||||
|
||||
usho do_hash(usho *b, int len);
|
||||
usho do_hash_file(const char *filename);
|
||||
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* radare - advanced commandline hexadecimal editor
|
||||
* Copyright (C) 2006,2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "hexdump.h"
|
||||
|
||||
char getprintablechar(char a)
|
||||
{
|
||||
if (a>=' '&&a<='~')
|
||||
return a;
|
||||
return '.';
|
||||
}
|
||||
|
||||
int is_printable (int c)
|
||||
{
|
||||
if (c<' '||c>'~') return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function
|
||||
*/
|
||||
void dump_bytes(unsigned char *buf, int len)
|
||||
{
|
||||
int i,j,seek = 0;
|
||||
int inc = 16;
|
||||
|
||||
for(i=0; i<len; i+=inc) {
|
||||
fprintf(stderr, "0x%08x | ", seek+i);
|
||||
for(j=i;j<i+inc;j++) {
|
||||
if (j>=len) {
|
||||
fprintf(stderr, " ");
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "%02x ", buf[j]);
|
||||
}
|
||||
fprintf(stderr, " ");
|
||||
for(j=i; j<i+inc; j++) {
|
||||
if (j >= len)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
if ( is_printable(buf[j]) )
|
||||
fprintf(stderr, "%c", buf[j]);
|
||||
else fprintf(stderr, ".");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
char getprintablechar(char a);
|
||||
int is_printable (int c);
|
||||
void dump_bytes(unsigned char *buf, int len);
|
||||
+814
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "device.h"
|
||||
#include "image.h"
|
||||
|
||||
/* format: type-device:hwrevs_version */
|
||||
static void image_missing_values_from_name(struct image * image, const char * name) {
|
||||
|
||||
char * str;
|
||||
char * ptr;
|
||||
char * ptr2;
|
||||
char * type = NULL;
|
||||
char * device = NULL;
|
||||
char * hwrevs = NULL;
|
||||
char * version = NULL;
|
||||
enum device new_device;
|
||||
|
||||
str = strdup(name);
|
||||
if ( ! str )
|
||||
return;
|
||||
|
||||
ptr = strchr(str, '_');
|
||||
if ( ptr ) {
|
||||
*ptr = 0;
|
||||
++ptr;
|
||||
version = strdup(ptr);
|
||||
}
|
||||
|
||||
ptr = strchr(str, '-');
|
||||
if ( ptr ) {
|
||||
*ptr = 0;
|
||||
++ptr;
|
||||
type = strdup(str);
|
||||
ptr2 = strchr(ptr, ':');
|
||||
if ( ptr2 ) {
|
||||
*ptr2 = 0;
|
||||
++ptr2;
|
||||
hwrevs = strdup(ptr2);
|
||||
}
|
||||
device = strdup(ptr);
|
||||
} else {
|
||||
type = strdup(str);
|
||||
}
|
||||
|
||||
if ( ! image->type )
|
||||
image->type = image_type_from_string(type);
|
||||
free(type);
|
||||
|
||||
if ( ! image->devices || ! image->devices->device || image->devices->device == DEVICE_ANY ) {
|
||||
new_device = device_from_string(device);
|
||||
if ( new_device ) {
|
||||
if ( ! image->devices ) image->devices = calloc(1, sizeof(struct device_list));
|
||||
if ( image->devices )
|
||||
image->devices->device = new_device;
|
||||
}
|
||||
}
|
||||
free(device);
|
||||
|
||||
if ( image->devices && image->devices->device && ! image->devices->hwrevs )
|
||||
image->devices->hwrevs = hwrevs_alloc_from_string(hwrevs);
|
||||
|
||||
if ( ! image->version )
|
||||
image->version = version;
|
||||
else
|
||||
free(version);
|
||||
|
||||
free(hwrevs);
|
||||
free(str);
|
||||
|
||||
}
|
||||
|
||||
/* format: type-device:hwrevs_version */
|
||||
char * image_name_alloc_from_values(struct image * image, int part_num) {
|
||||
|
||||
char * name;
|
||||
char * ptr;
|
||||
char * hwrevs;
|
||||
size_t length;
|
||||
const char * type;
|
||||
const char * device;
|
||||
struct image_part * part;
|
||||
int i;
|
||||
|
||||
type = image_type_to_string(image->type);
|
||||
|
||||
if ( ! type )
|
||||
type = "unknown";
|
||||
|
||||
if ( image->devices )
|
||||
device = device_to_string(image->devices->device);
|
||||
else
|
||||
device = NULL;
|
||||
|
||||
if ( image->devices && image->devices->hwrevs )
|
||||
hwrevs = hwrevs_alloc_to_string(image->devices->hwrevs);
|
||||
else
|
||||
hwrevs = NULL;
|
||||
|
||||
part = image->parts;
|
||||
|
||||
if ( part && ( !part->next || part_num < 0 ) )
|
||||
part = NULL;
|
||||
|
||||
for ( i = 0; i < part_num && part; i++ )
|
||||
part = part->next;
|
||||
|
||||
length = 1 + strlen(type);
|
||||
|
||||
if ( device )
|
||||
length += 1 + strlen(device);
|
||||
if ( hwrevs )
|
||||
length += 1 + strlen(hwrevs);
|
||||
if ( image->version )
|
||||
length += 1 + strlen(image->version);
|
||||
if ( part )
|
||||
length += 4 + 3; /* 3 <= strlen(part_num) */
|
||||
if ( part && part->name )
|
||||
length += 1 + strlen(part->name);
|
||||
|
||||
name = calloc(1, length);
|
||||
if ( ! name ) {
|
||||
free(hwrevs);
|
||||
ALLOC_ERROR_RETURN(NULL);
|
||||
}
|
||||
|
||||
strcpy(name, type);
|
||||
ptr = name + strlen(name);
|
||||
|
||||
if ( device )
|
||||
ptr += sprintf(ptr, "-%s", device);
|
||||
if ( hwrevs )
|
||||
ptr += sprintf(ptr, ":%s", hwrevs);
|
||||
if ( image->version )
|
||||
ptr += sprintf(ptr, "_%s", image->version);
|
||||
|
||||
if ( part ) {
|
||||
ptr += sprintf(ptr, "_part%d", part_num+1);
|
||||
if ( part->name )
|
||||
ptr += sprintf(ptr, "_%s", part->name);
|
||||
}
|
||||
|
||||
free(hwrevs);
|
||||
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
static int image_append(struct image * image, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
|
||||
|
||||
enum image_type detected_type;
|
||||
|
||||
image->hash = image_hash_from_data(image);
|
||||
|
||||
image->devices = calloc(1, sizeof(struct device_list));
|
||||
if ( ! image->devices ) {
|
||||
image_free(image);
|
||||
ALLOC_ERROR_RETURN(-1);
|
||||
}
|
||||
|
||||
image->devices->device = DEVICE_ANY;
|
||||
|
||||
if ( device && device[0] ) {
|
||||
image->devices->device = device_from_string(device);
|
||||
if ( ! noverify && image->devices->device == DEVICE_UNKNOWN ) {
|
||||
ERROR("Specified Device %s is unknown", device);
|
||||
image_free(image);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
detected_type = image_type_from_data(image);
|
||||
image->type = detected_type;
|
||||
|
||||
if ( type && type[0] ) {
|
||||
image->type = image_type_from_string(type);
|
||||
if ( ! noverify && image->type == IMAGE_UNKNOWN ) {
|
||||
ERROR("Specified Image type %s is unknown", type);
|
||||
image_free(image);
|
||||
return -1;
|
||||
}
|
||||
if ( ! noverify && detected_type != image->type && detected_type != IMAGE_UNKNOWN ) {
|
||||
ERROR("Image type mishmash (detected %s, got %s)", image_type_to_string(detected_type), type);
|
||||
image_free(image);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hwrevs && hwrevs[0] )
|
||||
image->devices->hwrevs = hwrevs_alloc_from_string(hwrevs);
|
||||
else
|
||||
image->devices->hwrevs = NULL;
|
||||
|
||||
if ( version && version[0] )
|
||||
image->version = strdup(version);
|
||||
else
|
||||
image->version = NULL;
|
||||
|
||||
if ( layout && layout[0] )
|
||||
image->layout = strdup(layout);
|
||||
else
|
||||
image->layout = NULL;
|
||||
|
||||
image->parts = parts;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void image_align(struct image * image) {
|
||||
|
||||
struct image_fd * image_fd = image->fds;
|
||||
size_t align, aligned_size;
|
||||
uint32_t total_size;
|
||||
|
||||
if ( image->type == IMAGE_MMC )
|
||||
align = 8;
|
||||
else
|
||||
align = 7;
|
||||
|
||||
if ( image_fd && ! image_fd->next && image->size == image_fd->size && ( image->size & ( ( 1ULL << align ) - 1 ) ) == 0 )
|
||||
return;
|
||||
|
||||
total_size = 0;
|
||||
|
||||
while ( image_fd ) {
|
||||
|
||||
if ( ( image_fd->size & ( ( 1ULL << align ) - 1 ) ) != 0 ) {
|
||||
aligned_size = ((image_fd->size >> align) + 1) << align;
|
||||
image_fd->align = aligned_size - image_fd->size;
|
||||
image_fd->size = aligned_size;
|
||||
}
|
||||
|
||||
total_size += image_fd->size;
|
||||
image_fd = image_fd->next;
|
||||
|
||||
}
|
||||
|
||||
image->size = total_size;
|
||||
|
||||
image->hash = image_hash_from_data(image);
|
||||
|
||||
}
|
||||
|
||||
static struct image * image_alloc(void) {
|
||||
|
||||
struct image * image = calloc(1, sizeof(struct image));
|
||||
if ( ! image )
|
||||
ALLOC_ERROR_RETURN(NULL);
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
|
||||
|
||||
return image_alloc_from_files(&file, 1, type, device, hwrevs, version, layout, parts);
|
||||
|
||||
}
|
||||
|
||||
struct image * image_alloc_from_files(const char ** files, int count, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
|
||||
|
||||
struct image * image;
|
||||
int i;
|
||||
int * fds = calloc(count, sizeof(int));
|
||||
if ( ! fds )
|
||||
ALLOC_ERROR_RETURN(NULL);
|
||||
|
||||
for ( i = 0; i < count; ++i ) {
|
||||
fds[i] = open(files[i], O_RDONLY);
|
||||
if ( fds[i] < 0 ) {
|
||||
ERROR_INFO("Cannot open image file %s", files[i]);
|
||||
free(fds);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
image = image_alloc_from_fds(fds, files, count, type, device, hwrevs, version, layout, parts);
|
||||
free(fds);
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
|
||||
|
||||
return image_alloc_from_fds(&fd, &orig_filename, 1, type, device, hwrevs, version, layout, parts);
|
||||
|
||||
}
|
||||
|
||||
struct image * image_alloc_from_fds(int * fds, const char ** orig_filenames, int count, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
|
||||
|
||||
int i;
|
||||
struct image * image = image_alloc();
|
||||
if ( ! image ) {
|
||||
for ( i = 0; i < count; ++i )
|
||||
close(fds[i]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i = 0; i < count; ++i ) {
|
||||
|
||||
off_t offset;
|
||||
struct image_fd * image_fds = image->fds;
|
||||
struct image_fd * image_fd = calloc(1, sizeof(struct image_fd));
|
||||
if ( ! image_fd ) {
|
||||
image_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( ! image_fds ) {
|
||||
image->fds = image_fd;
|
||||
} else {
|
||||
while ( image_fds->next )
|
||||
image_fds = image_fds->next;
|
||||
image_fds->next = image_fd;
|
||||
}
|
||||
|
||||
image_fd->is_shared_fd = 0;
|
||||
image_fd->fd = fds[i];
|
||||
|
||||
offset = lseek(image_fd->fd, 0, SEEK_END);
|
||||
if ( offset == (off_t)-1 ) {
|
||||
ERROR_INFO("Cannot seek to end of file %s", orig_filenames[i]);
|
||||
image_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image_fd->size = offset;
|
||||
image_fd->offset = 0;
|
||||
image_fd->is_shared_fd = 0;
|
||||
image_fd->shared_cur = 0;
|
||||
image_fd->orig_filename = strdup(orig_filenames[i]);
|
||||
|
||||
image->size += image_fd->size;
|
||||
|
||||
if ( lseek(image_fd->fd, 0, SEEK_SET) == (off_t)-1 ) {
|
||||
ERROR_INFO("Cannot seek to begin of file %s", orig_filenames[i]);
|
||||
image_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
|
||||
return NULL;
|
||||
|
||||
if ( ( ! type || ! type[0] ) && ( ! device || ! device[0] ) && ( ! hwrevs || ! hwrevs[0] ) && ( ! version || ! version[0] ) )
|
||||
image_missing_values_from_name(image, count > 0 ? orig_filenames[0] : NULL);
|
||||
|
||||
image_align(image);
|
||||
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts) {
|
||||
|
||||
struct image * image = image_alloc();
|
||||
struct image_fd * image_fd = calloc(1, sizeof(struct image_fd));
|
||||
if ( ! image || ! image_fd ) {
|
||||
free(image);
|
||||
free(image_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image_fd->is_shared_fd = 1;
|
||||
image_fd->fd = fd;
|
||||
image_fd->size = size;
|
||||
image_fd->offset = offset;
|
||||
image_fd->shared_cur = 0;
|
||||
image->fds = image_fd;
|
||||
image->size = image_fd->size;
|
||||
|
||||
if ( image_append(image, type, device, hwrevs, version, layout, parts) < 0 )
|
||||
return NULL;
|
||||
|
||||
if ( ! noverify && image->hash != hash ) {
|
||||
ERROR("Image hash mishmash (counted %#04x, got %#04x)", image->hash, hash);
|
||||
image_free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image_align(image);
|
||||
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
void image_free(struct image * image) {
|
||||
|
||||
if ( ! image )
|
||||
return;
|
||||
|
||||
while ( image->fds ) {
|
||||
struct image_fd * next = image->fds->next;
|
||||
if ( ! image->fds->is_shared_fd )
|
||||
close(image->fds->fd);
|
||||
free(image->fds->orig_filename);
|
||||
free(image->fds);
|
||||
image->fds = next;
|
||||
}
|
||||
|
||||
while ( image->devices ) {
|
||||
struct device_list * next = image->devices->next;
|
||||
free(image->devices->hwrevs);
|
||||
free(image->devices);
|
||||
image->devices = next;
|
||||
}
|
||||
|
||||
while ( image->parts ) {
|
||||
struct image_part * next = image->parts->next;
|
||||
free(image->parts->name);
|
||||
free(image->parts);
|
||||
image->parts = next;
|
||||
}
|
||||
|
||||
free(image->version);
|
||||
free(image->layout);
|
||||
|
||||
free(image);
|
||||
|
||||
}
|
||||
|
||||
void image_seek(struct image * image, size_t whence) {
|
||||
|
||||
off_t offset;
|
||||
size_t start = 0;
|
||||
struct image_fd * image_fd = image->fds;
|
||||
|
||||
image->cur = whence;
|
||||
|
||||
if ( whence > image->size ) {
|
||||
ERROR("Seek in image failed: Position end of the image");
|
||||
return;
|
||||
}
|
||||
|
||||
while ( image_fd ) {
|
||||
if ( ( whence >= start && whence < start + image_fd->size ) || ! image_fd->next )
|
||||
break;
|
||||
start += image_fd->size;
|
||||
image_fd = image_fd->next;
|
||||
}
|
||||
|
||||
if ( whence - start >= image_fd->size - image_fd->align ) {
|
||||
offset = lseek(image_fd->fd, image_fd->size - image_fd->align, SEEK_SET);
|
||||
} else {
|
||||
offset = lseek(image_fd->fd, image_fd->offset + whence - start, SEEK_SET);
|
||||
}
|
||||
|
||||
if ( offset == (off_t)-1 )
|
||||
ERROR_INFO("Seek in file %s failed", (image_fd->orig_filename ? image_fd->orig_filename : "(unknown)"));
|
||||
else if ( image_fd->is_shared_fd )
|
||||
image_fd->shared_cur = offset;
|
||||
|
||||
}
|
||||
|
||||
size_t image_read(struct image * image, void * buf, size_t count) {
|
||||
|
||||
ssize_t ret;
|
||||
off_t offset;
|
||||
size_t new_count = 0;
|
||||
size_t ret_count = 0;
|
||||
size_t start = 0;
|
||||
struct image_fd * image_fd = image->fds;
|
||||
|
||||
while ( image_fd ) {
|
||||
if ( ( image->cur >= start && image->cur < start + image_fd->size ) || ! image_fd->next )
|
||||
break;
|
||||
start += image_fd->size;
|
||||
image_fd = image_fd->next;
|
||||
}
|
||||
|
||||
if ( image_fd->is_shared_fd ) {
|
||||
if ( lseek(image_fd->fd, image_fd->shared_cur, SEEK_SET) != image_fd->shared_cur ) {
|
||||
ERROR_INFO("Cannot restore offset of file %s", (image_fd->orig_filename ? image_fd->orig_filename : "(unknown)"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
while ( count > 0 ) {
|
||||
|
||||
if ( image->cur < start + image_fd->size - image_fd->align ) {
|
||||
|
||||
if ( image->cur + count > start + image_fd->size - image_fd->align )
|
||||
new_count = start + image_fd->size - image_fd->align - image->cur;
|
||||
else
|
||||
new_count = count;
|
||||
|
||||
ret = read(image_fd->fd, buf, new_count);
|
||||
if ( ret <= 0 )
|
||||
break;
|
||||
|
||||
count -= ret;
|
||||
buf = (unsigned char *)buf + ret;
|
||||
ret_count += ret;
|
||||
image->cur += ret;
|
||||
|
||||
if ( image_fd->is_shared_fd )
|
||||
image_fd->shared_cur += ret;
|
||||
|
||||
if ( (size_t)ret != new_count )
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if ( image_fd->align > 0 && count > 0 && image->cur < start + image_fd->size ) {
|
||||
|
||||
if ( count > image_fd->align )
|
||||
new_count = image_fd->align;
|
||||
else
|
||||
new_count = count;
|
||||
|
||||
if ( image->cur + new_count > start + image_fd->size )
|
||||
new_count = start + image_fd->size - image->cur;
|
||||
|
||||
memset(buf, 0xFF, new_count);
|
||||
ret = new_count;
|
||||
|
||||
count -= ret;
|
||||
buf = (unsigned char *)buf + ret;
|
||||
ret_count += ret;
|
||||
image->cur += ret;
|
||||
|
||||
}
|
||||
|
||||
if ( image->cur == start + image_fd->size ) {
|
||||
|
||||
start += image_fd->size;
|
||||
image_fd = image_fd->next;
|
||||
|
||||
if ( ! image_fd )
|
||||
break;
|
||||
|
||||
offset = lseek(image_fd->fd, image_fd->offset, SEEK_SET);
|
||||
if ( offset == (off_t)-1 ) {
|
||||
ERROR_INFO("Seek in file %s failed", (image_fd->orig_filename ? image_fd->orig_filename : "(unknown)"));
|
||||
break;
|
||||
} else if ( image_fd->is_shared_fd ) {
|
||||
image_fd->shared_cur = offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret_count;
|
||||
|
||||
}
|
||||
|
||||
void image_list_add(struct image_list ** list, struct image * image) {
|
||||
|
||||
struct image_list * last = calloc(1, sizeof(struct image_list));
|
||||
if ( ! last )
|
||||
ALLOC_ERROR_RETURN();
|
||||
|
||||
last->image = image;
|
||||
|
||||
if ( ! *list ) {
|
||||
*list = last;
|
||||
return;
|
||||
}
|
||||
|
||||
while ( (*list)->next )
|
||||
list = &((*list)->next);
|
||||
|
||||
last->prev = *list;
|
||||
(*list)->next = last;
|
||||
|
||||
}
|
||||
|
||||
void image_list_del(struct image_list * list) {
|
||||
|
||||
if ( ! list )
|
||||
return;
|
||||
|
||||
image_list_unlink(list);
|
||||
image_free(list->image);
|
||||
free(list);
|
||||
|
||||
}
|
||||
|
||||
void image_list_unlink(struct image_list * list) {
|
||||
|
||||
if ( ! list )
|
||||
return;
|
||||
|
||||
if ( list->prev )
|
||||
list->prev->next = list->next;
|
||||
|
||||
if ( list->next )
|
||||
list->next->prev = list->prev;
|
||||
|
||||
list->prev = NULL;
|
||||
list->next = NULL;
|
||||
|
||||
}
|
||||
|
||||
static uint16_t do_hash(uint16_t * b, size_t len) {
|
||||
|
||||
uint16_t result = 0;
|
||||
|
||||
for ( len >>= 1; len--; b = b+1 )
|
||||
result^=b[0];
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
uint16_t image_hash_from_data(struct image * image) {
|
||||
|
||||
unsigned char buf[0x20000];
|
||||
uint16_t hash = 0;
|
||||
size_t ret;
|
||||
|
||||
image_seek(image, 0);
|
||||
while ( ( ret = image_read(image, buf, sizeof(buf)) ) )
|
||||
hash ^= do_hash((uint16_t *)buf, ret);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static const char * image_types[] = {
|
||||
[IMAGE_XLOADER] = "xloader",
|
||||
[IMAGE_2ND] = "2nd",
|
||||
[IMAGE_SECONDARY] = "secondary",
|
||||
[IMAGE_KERNEL] = "kernel",
|
||||
[IMAGE_INITFS] = "initfs",
|
||||
[IMAGE_ROOTFS] = "rootfs",
|
||||
[IMAGE_MMC] = "mmc",
|
||||
[IMAGE_CMT_2ND] = "cmt-2nd",
|
||||
[IMAGE_CMT_ALGO] = "cmt-algo",
|
||||
[IMAGE_CMT_MCUSW] = "cmt-mcusw",
|
||||
[IMAGE_1ST] = "1st",
|
||||
[IMAGE_CERT_SW] = "cert-sw",
|
||||
[IMAGE_APE_ALGO] = "ape-algo",
|
||||
};
|
||||
|
||||
enum image_type image_type_from_data(struct image * image) {
|
||||
|
||||
unsigned char buf[512];
|
||||
size_t size;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
image_seek(image, 0);
|
||||
size = image_read(image, buf, sizeof(buf));
|
||||
|
||||
if ( size >= 58 && memcmp(buf+52, "2NDAPE", 6) == 0 )
|
||||
return IMAGE_2ND;
|
||||
else if ( size >= 23 && memcmp(buf+20, "2ND", 3) == 0 )
|
||||
return IMAGE_2ND;
|
||||
else if ( size >= 8 && memcmp(buf+4, "NOLOScnd", 8) == 0 )
|
||||
return IMAGE_SECONDARY;
|
||||
else if ( size >= 28 && memcmp(buf+20, "X-LOADER", 8) == 0 )
|
||||
return IMAGE_XLOADER;
|
||||
else if ( size >= 20 && memcmp(buf+12, "NOLOXldr", 8) == 0 )
|
||||
return IMAGE_XLOADER;
|
||||
else if ( size >= 12 && memcmp(buf+4, "NOLOXldr", 8) == 0 )
|
||||
return IMAGE_2ND;
|
||||
else if ( size >= 40 && memcmp(buf+36, "\x18\x28\x6f\x01", 4) == 0 ) /* ARM Linux kernel magic number */
|
||||
return IMAGE_KERNEL;
|
||||
else if ( size >= 4 && memcmp(buf+1, "\x00\x00\xea", 3) == 0 ) /* ARM U-Boot - instruction branch */
|
||||
return IMAGE_KERNEL;
|
||||
else if ( size >= 4 && memcmp(buf, "UBI#", 4) == 0 ) /* UBI EC header */
|
||||
return IMAGE_ROOTFS;
|
||||
else if ( size >= 512 && memcmp(buf+510, "\x55\xaa", 2) == 0 ) /* FAT boot sector signature */
|
||||
return IMAGE_MMC;
|
||||
else if ( size >= 8 && memcmp(buf, "\xb0\x00\x01\x03\x9d\x00\x00\x00", 8) == 0 )
|
||||
return IMAGE_CMT_2ND;
|
||||
else if ( size >= 8 && memcmp(buf, "\xb1\x00\x00\x00\x82\x00\x00\x00", 8) == 0 )
|
||||
return IMAGE_CMT_ALGO;
|
||||
else if ( size >= 8 && memcmp(buf, "\xb2\x00\x00\x01\x44\x00\x00\x00", 8) == 0 )
|
||||
return IMAGE_CMT_MCUSW;
|
||||
else if ( size >= 4 && memcmp(buf, "\x45\x3d\xcd\x28", 4) == 0 ) /* CRAMFS MAGIC */
|
||||
return IMAGE_INITFS;
|
||||
else if ( size >= 2 && memcmp(buf, "\x85\x19", 2) == 0 ) { /* JFFS2 MAGIC */
|
||||
if ( image->size < 0x1000000 )
|
||||
return IMAGE_INITFS;
|
||||
else
|
||||
return IMAGE_ROOTFS;
|
||||
}
|
||||
|
||||
return IMAGE_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
enum image_type image_type_from_string(const char * type) {
|
||||
|
||||
size_t i;
|
||||
|
||||
if ( ! type )
|
||||
return IMAGE_UNKNOWN;
|
||||
|
||||
for ( i = 0; i < sizeof(image_types)/sizeof(image_types[0]); ++i )
|
||||
if ( image_types[i] && strcmp(image_types[i], type) == 0 )
|
||||
return i;
|
||||
|
||||
return IMAGE_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
const char * image_type_to_string(enum image_type type) {
|
||||
|
||||
if ( type >= sizeof(image_types)/sizeof(image_types[0]) )
|
||||
return NULL;
|
||||
|
||||
return image_types[type];
|
||||
|
||||
}
|
||||
|
||||
int image_hwrev_is_valid(struct image * image, int16_t hwrev) {
|
||||
|
||||
struct device_list * device_ptr = image->devices;
|
||||
|
||||
while ( device_ptr ) {
|
||||
if ( hwrev_is_valid(device_ptr->hwrevs, hwrev) )
|
||||
return 1;
|
||||
device_ptr = device_ptr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void image_print_info(struct image * image) {
|
||||
|
||||
int i = 0;
|
||||
const char * str;
|
||||
struct image_fd * image_fd = image->fds;
|
||||
struct image_part * part = image->parts;
|
||||
struct device_list * device = image->devices;
|
||||
|
||||
if ( image->fds && image->fds->orig_filename ) {
|
||||
if ( image->fds->next )
|
||||
printf("Multifile image:\n");
|
||||
else
|
||||
printf("File: %s\n", image->fds->orig_filename);
|
||||
}
|
||||
|
||||
str = image_type_to_string(image->type);
|
||||
printf(" Image type: %s\n", str ? str : "unknown");
|
||||
printf(" Image size: %d bytes\n", image->size);
|
||||
|
||||
if ( image->version )
|
||||
printf(" Image version: %s\n", image->version);
|
||||
|
||||
if ( image->layout )
|
||||
printf(" Image layout: included\n");
|
||||
|
||||
while ( part ) {
|
||||
|
||||
if ( image->fds && image->fds->orig_filename && image->fds->next )
|
||||
printf("File: %s\n", (image_fd && image_fd->orig_filename) ? image_fd->orig_filename : "(unknown)");
|
||||
|
||||
printf(" Image part %d name: %s\n", i, part->name ? part->name : "(empty)");
|
||||
printf(" Image part %d size: %d bytes\n", i, part->size);
|
||||
|
||||
part = part->next;
|
||||
image_fd = image_fd ? image_fd->next : NULL;
|
||||
++i;
|
||||
|
||||
}
|
||||
|
||||
while ( device ) {
|
||||
|
||||
char * str2 = NULL;
|
||||
struct device_list * next = device->next;
|
||||
|
||||
if ( device->device == DEVICE_UNKNOWN )
|
||||
str = "unknown";
|
||||
else
|
||||
str = device_to_string(device->device);
|
||||
|
||||
if ( str )
|
||||
printf(" Valid for: device %s", str);
|
||||
|
||||
if ( str && device->hwrevs )
|
||||
str2 = hwrevs_alloc_to_string(device->hwrevs);
|
||||
|
||||
if ( str2 ) {
|
||||
printf(", HW revisions: %s\n", str2);
|
||||
free(str2);
|
||||
} else if ( str ) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
device = next;
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_H
|
||||
#define IMAGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "device.h"
|
||||
|
||||
enum image_type {
|
||||
IMAGE_UNKNOWN = 0,
|
||||
IMAGE_XLOADER,
|
||||
IMAGE_2ND,
|
||||
IMAGE_SECONDARY,
|
||||
IMAGE_KERNEL,
|
||||
IMAGE_INITFS,
|
||||
IMAGE_ROOTFS,
|
||||
IMAGE_MMC,
|
||||
IMAGE_CMT_2ND,
|
||||
IMAGE_CMT_ALGO,
|
||||
IMAGE_CMT_MCUSW,
|
||||
IMAGE_1ST,
|
||||
IMAGE_CERT_SW,
|
||||
IMAGE_APE_ALGO,
|
||||
IMAGE_COUNT,
|
||||
};
|
||||
|
||||
struct image_part {
|
||||
struct image_part * next;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
char * name;
|
||||
};
|
||||
|
||||
struct image_fd {
|
||||
struct image_fd * next;
|
||||
int fd;
|
||||
int is_shared_fd;
|
||||
off_t shared_cur;
|
||||
uint32_t size;
|
||||
uint32_t align;
|
||||
size_t offset;
|
||||
char * orig_filename;
|
||||
};
|
||||
|
||||
struct image {
|
||||
enum image_type type;
|
||||
struct device_list * devices;
|
||||
char * version;
|
||||
char * layout;
|
||||
uint16_t hash;
|
||||
uint32_t size;
|
||||
struct image_part * parts;
|
||||
struct image_fd * fds;
|
||||
size_t cur;
|
||||
};
|
||||
|
||||
struct image_list {
|
||||
struct image * image;
|
||||
struct image_list * prev;
|
||||
struct image_list * next;
|
||||
};
|
||||
|
||||
struct image * image_alloc_from_file(const char * file, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
|
||||
struct image * image_alloc_from_files(const char ** files, int count, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
|
||||
struct image * image_alloc_from_fd(int fd, const char * orig_filename, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
|
||||
struct image * image_alloc_from_fds(int * fds, const char ** orig_filenames, int count, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
|
||||
struct image * image_alloc_from_shared_fd(int fd, size_t size, size_t offset, uint16_t hash, const char * type, const char * device, const char * hwrevs, const char * version, const char * layout, struct image_part * parts);
|
||||
void image_free(struct image * image);
|
||||
void image_seek(struct image * image, size_t whence);
|
||||
size_t image_read(struct image * image, void * buf, size_t count);
|
||||
void image_print_info(struct image * image);
|
||||
void image_list_add(struct image_list ** list, struct image * image);
|
||||
void image_list_del(struct image_list * list);
|
||||
void image_list_unlink(struct image_list * list);
|
||||
|
||||
uint16_t image_hash_from_data(struct image * image);
|
||||
enum image_type image_type_from_data(struct image * image);
|
||||
char * image_name_alloc_from_values(struct image * image, int part_num);
|
||||
enum image_type image_type_from_string(const char * type);
|
||||
const char * image_type_to_string(enum image_type type);
|
||||
int image_hwrev_is_valid(struct image * image, int16_t hwrev);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
libusb-sniff.c - Library for usb sniffing nokia's flasher-3.5
|
||||
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
/* compile: gcc libusb-sniff.c -o libusb-sniff.so -W -Wall -O2 -fPIC -ldl -shared -m32 */
|
||||
/* usage: sudo USBSNIFF_WAIT=1 LD_PRELOAD=./libusb-sniff.so flasher-3.5 ... */
|
||||
/* usage: sudo USBSNIFF_SKIP_READ=1 USBSNIFF_SKIP_WRITE=1 LD_PRELOAD=./libusb-sniff.so flasher-3.5 ... */
|
||||
|
||||
/* Enable RTLD_NEXT for glibc */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
struct usb_dev_handle;
|
||||
struct libusb_device_handle;
|
||||
typedef struct usb_dev_handle usb_dev_handle;
|
||||
typedef struct libusb_device_handle libusb_device_handle;
|
||||
|
||||
static char to_ascii(char c) {
|
||||
|
||||
if ( c >= 32 && c <= 126 )
|
||||
return c;
|
||||
return '.';
|
||||
|
||||
}
|
||||
|
||||
static void dump_bytes(const char * buf, size_t size) {
|
||||
|
||||
size_t i, ascii_cnt = 0;
|
||||
char ascii[17] = { 0, };
|
||||
|
||||
for ( i = 0; i < size; i++ ) {
|
||||
if ( i % 16 == 0 ) {
|
||||
if ( i != 0 ) {
|
||||
printf(" |%s|\n", ascii);
|
||||
ascii[0] = 0;
|
||||
ascii_cnt = 0;
|
||||
}
|
||||
printf("%04X:", (unsigned int)i);
|
||||
}
|
||||
printf(" %02X", buf[i] & 0xFF);
|
||||
ascii[ascii_cnt] = to_ascii(buf[i]);
|
||||
ascii[ascii_cnt + 1] = 0;
|
||||
ascii_cnt++;
|
||||
}
|
||||
|
||||
if ( ascii[0] ) {
|
||||
if ( size % 16 )
|
||||
for ( i = 0; i < 16 - (size % 16); i++ )
|
||||
printf(" ");
|
||||
printf(" |%s|\n", ascii);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int usb_bulk_write(usb_dev_handle * dev, int ep, const char * bytes, int size, int timeout) {
|
||||
|
||||
static int (*real_usb_bulk_write)(usb_dev_handle * dev, int ep, const char * bytes, int size, int timeout) = NULL;
|
||||
|
||||
if ( ! real_usb_bulk_write )
|
||||
*(void **)(&real_usb_bulk_write) = dlsym(RTLD_NEXT, "usb_bulk_write");
|
||||
|
||||
if ( ! getenv("USBSNIFF_SKIP_WRITE") ) {
|
||||
|
||||
printf("\n==== usb_bulk_write (ep=%d size=%d timeout=%d) ====\n", ep, size, timeout);
|
||||
dump_bytes(bytes, size);
|
||||
printf("====\n");
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return real_usb_bulk_write(dev, ep, bytes, size, timeout);
|
||||
|
||||
}
|
||||
|
||||
int usb_bulk_read(usb_dev_handle * dev, int ep, char * bytes, int size, int timeout) {
|
||||
|
||||
static int (*real_usb_bulk_read)(usb_dev_handle * dev, int ep, char * bytes, int size, int timeout) = NULL;
|
||||
int ret;
|
||||
|
||||
if ( ! real_usb_bulk_read )
|
||||
*(void **)(&real_usb_bulk_read) = dlsym(RTLD_NEXT, "usb_bulk_read");
|
||||
|
||||
ret = real_usb_bulk_read(dev, ep, bytes, size, timeout);
|
||||
|
||||
if ( ! getenv("USBSNIFF_SKIP_READ") ) {
|
||||
|
||||
printf("\n==== usb_bulk_read (ep=%d size=%d timeout=%d) ret = %d ====\n", ep, size, timeout, ret);
|
||||
if ( ret > 0 ) {
|
||||
dump_bytes(bytes, ret);
|
||||
printf("====\n");
|
||||
}
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int libusb_bulk_transfer(libusb_device_handle *dev, unsigned char ep, unsigned char *bytes, int size, int *actual_length, unsigned int timeout) {
|
||||
|
||||
static int (*real_libusb_bulk_transfer)(libusb_device_handle *dev, unsigned char ep, unsigned char *bytes, int size, int *actual_length, unsigned int timeout) = NULL;
|
||||
int ret;
|
||||
|
||||
if ( ! real_libusb_bulk_transfer )
|
||||
*(void **)(&real_libusb_bulk_transfer) = dlsym(RTLD_NEXT, "libusb_bulk_transfer");
|
||||
|
||||
if ( ep == 0x81 ) {
|
||||
|
||||
ret = real_libusb_bulk_transfer(dev, ep, bytes, size, actual_length, timeout);
|
||||
|
||||
if ( ! getenv("USBSNIFF_SKIP_READ") ) {
|
||||
|
||||
printf("\n==== usb_bulk_read (ep=%d size=%d timeout=%d) ret = %d ====\n", ep, size, timeout, (ret < 0) ? ret : *actual_length);
|
||||
if ( ret == 0 ) {
|
||||
dump_bytes((char*) bytes, *actual_length);
|
||||
printf("====\n");
|
||||
}
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
} else {
|
||||
|
||||
if ( ! getenv("USBSNIFF_SKIP_WRITE") ) {
|
||||
|
||||
printf("\n==== usb_bulk_write (ep=%d size=%d timeout=%d) ====\n", ep, size, timeout);
|
||||
dump_bytes((char*) bytes, size);
|
||||
printf("====\n");
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return real_libusb_bulk_transfer(dev, ep, bytes, size, actual_length, timeout);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout) {
|
||||
|
||||
static int (*real_usb_control_msg)(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout) = NULL;
|
||||
int ret;
|
||||
|
||||
if ( ! real_usb_control_msg )
|
||||
*(void **)(&real_usb_control_msg) = dlsym(RTLD_NEXT, "usb_control_msg");
|
||||
|
||||
if ( requesttype == 64 && ! getenv("USBSNIFF_SKIP_CONTROL") ) {
|
||||
|
||||
printf("\n==== usb_control_msg(requesttype=%d, request=%d, value=%d, index=%d, size=%d, timeout=%d) ====\n", requesttype, request, value, index, size, timeout);
|
||||
dump_bytes(bytes, size);
|
||||
printf("====\n");
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = real_usb_control_msg(dev, requesttype, request, value, index, bytes, size, timeout);
|
||||
|
||||
if ( requesttype != 64 && ! getenv("USBSNIFF_SKIP_CONTROL") ) {
|
||||
|
||||
printf("\n==== usb_control_msg(requesttype=%d, request=%d, value=%d, index=%d, size=%d, timeout=%d) ret = %d ====\n", requesttype, request, value, index, size, timeout, ret);
|
||||
if ( ret > 0 ) {
|
||||
dump_bytes(bytes, ret);
|
||||
printf("====\n");
|
||||
}
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int libusb_control_transfer(libusb_device_handle *dev, uint8_t requesttype, uint8_t request, uint16_t value, uint16_t index, unsigned char *bytes, uint16_t size, unsigned int timeout) {
|
||||
|
||||
static int (*real_libusb_control_transfer)(libusb_device_handle *dev, uint8_t requesttype, uint8_t request, uint16_t value, uint16_t index, unsigned char *bytes, uint16_t size, unsigned int timeout) = NULL;
|
||||
int ret;
|
||||
|
||||
if ( ! real_libusb_control_transfer )
|
||||
*(void **)(&real_libusb_control_transfer) = dlsym(RTLD_NEXT, "libusb_control_transfer");
|
||||
|
||||
if ( requesttype == 64 && ! getenv("USBSNIFF_SKIP_CONTROL") ) {
|
||||
|
||||
printf("\n==== usb_control_msg(requesttype=%d, request=%d, value=%d, index=%d, size=%d, timeout=%d) ====\n", (int)requesttype, (int)request, (int)value, (int)index, (int)size, (int)timeout);
|
||||
dump_bytes((char*) bytes, size);
|
||||
printf("====\n");
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = real_libusb_control_transfer(dev, requesttype, request, value, index, bytes, size, timeout);
|
||||
|
||||
if ( requesttype != 64 && ! getenv("USBSNIFF_SKIP_CONTROL") ) {
|
||||
|
||||
printf("\n==== usb_control_msg(requesttype=%d, request=%d, value=%d, index=%d, size=%d, timeout=%d) ret = %d ====\n", (int)requesttype, (int)request, (int)value, (int)index, (int)size, (int)timeout, ret);
|
||||
if ( ret > 0 ) {
|
||||
dump_bytes((char*) bytes, ret);
|
||||
printf("====\n");
|
||||
}
|
||||
|
||||
if ( getenv("USBSNIFF_WAIT") ) {
|
||||
printf("Press ENTER"); fflush(stdout); getchar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int usb_set_configuration(usb_dev_handle *dev, int configuration) {
|
||||
|
||||
static int (*real_usb_set_configuration)(usb_dev_handle *dev, int configuration) = NULL;
|
||||
|
||||
if ( ! real_usb_set_configuration )
|
||||
*(void **)(&real_usb_set_configuration) = dlsym(RTLD_NEXT, "usb_set_configuration");
|
||||
|
||||
printf("\n==== usb_set_configuration (configuration=%d) ====\n", configuration);
|
||||
|
||||
return real_usb_set_configuration(dev, configuration);
|
||||
|
||||
}
|
||||
|
||||
int libusb_set_configuration(libusb_device_handle *dev, int configuration) {
|
||||
|
||||
static int (*real_usb_set_configuration)(libusb_device_handle *dev, int configuration) = NULL;
|
||||
|
||||
if ( ! real_usb_set_configuration )
|
||||
*(void **)(&real_usb_set_configuration) = dlsym(RTLD_NEXT, "libusb_set_configuration");
|
||||
|
||||
printf("\n==== usb_set_configuration (configuration=%d) ====\n", configuration);
|
||||
|
||||
return real_usb_set_configuration(dev, configuration);
|
||||
|
||||
}
|
||||
|
||||
int usb_claim_interface(usb_dev_handle *dev, int interface) {
|
||||
|
||||
static int (*real_usb_claim_interface)(usb_dev_handle *dev, int interface) = NULL;
|
||||
|
||||
if ( ! real_usb_claim_interface )
|
||||
*(void **)(&real_usb_claim_interface) = dlsym(RTLD_NEXT, "usb_claim_interface");
|
||||
|
||||
printf("\n==== usb_claim_interface (interface=%d) ====\n", interface);
|
||||
|
||||
return real_usb_claim_interface(dev, interface);
|
||||
|
||||
}
|
||||
|
||||
int libusb_claim_interface(libusb_device_handle *dev, int interface) {
|
||||
|
||||
static int (*real_usb_claim_interface)(libusb_device_handle *dev, int interface) = NULL;
|
||||
|
||||
if ( ! real_usb_claim_interface )
|
||||
*(void **)(&real_usb_claim_interface) = dlsym(RTLD_NEXT, "libusb_claim_interface");
|
||||
|
||||
printf("\n==== usb_claim_interface (interface=%d) ====\n", interface);
|
||||
|
||||
return real_usb_claim_interface(dev, interface);
|
||||
|
||||
}
|
||||
|
||||
int usb_set_altinterface(usb_dev_handle *dev, int alternate) {
|
||||
|
||||
static int (*real_usb_set_altinterface)(usb_dev_handle *dev, int alternate) = NULL;
|
||||
|
||||
if ( ! real_usb_set_altinterface )
|
||||
*(void **)(&real_usb_set_altinterface) = dlsym(RTLD_NEXT, "usb_set_altinterface");
|
||||
|
||||
printf("\n==== usb_set_altinterface (alternate=%d) ====\n", alternate);
|
||||
|
||||
return real_usb_set_altinterface(dev, alternate);
|
||||
|
||||
}
|
||||
|
||||
int libusb_set_interface_alt_setting(libusb_device_handle *dev, int interface, int alternate) {
|
||||
|
||||
static int (*real_usb_set_altinterface)(libusb_device_handle *dev, int interface, int alternate) = NULL;
|
||||
|
||||
if ( ! real_usb_set_altinterface )
|
||||
*(void **)(&real_usb_set_altinterface) = dlsym(RTLD_NEXT, "libusb_set_interface_alt_setting");
|
||||
|
||||
printf("\n==== usb_set_altinterface (alternate=%d) ====\n", alternate);
|
||||
|
||||
return real_usb_set_altinterface(dev, interface, alternate);
|
||||
|
||||
}
|
||||
+884
@@ -0,0 +1,884 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "local.h"
|
||||
#include "global.h"
|
||||
#include "device.h"
|
||||
#include "image.h"
|
||||
#include "cal.h"
|
||||
#include "disk.h"
|
||||
|
||||
static int failed;
|
||||
|
||||
static enum device device = DEVICE_UNKNOWN;
|
||||
static int16_t hwrev = -1;
|
||||
static char kernel_ver[256];
|
||||
static char initfs_ver[256];
|
||||
static char nolo_ver[256];
|
||||
static char sw_ver[256];
|
||||
static char content_ver[256];
|
||||
static char rd_mode[256];
|
||||
static int usb_host_mode = -1;
|
||||
static int root_device = -1;
|
||||
|
||||
#define min(a, b) (a < b ? a : b)
|
||||
#define local_cal_copy(dest, from, len) strncpy(dest, from, min(len, sizeof(dest)-1))
|
||||
#define local_cal_read(cal, str, ptr, len) ( cal_read_block(cal, str, &ptr, &len, 0) == 0 && ptr )
|
||||
#define local_cal_readcopy(cal, str, dest) do { void * ptr; unsigned long int len; if ( local_cal_read(cal, str, ptr, len) ) { local_cal_copy(dest, ptr, len); free(ptr); } } while ( 0 )
|
||||
|
||||
#if defined(__linux__) && defined(__arm__)
|
||||
|
||||
static void local_cal_parse(void) {
|
||||
|
||||
struct cal * cal = NULL;
|
||||
char buf[128];
|
||||
|
||||
printf("Reading CAL...\n");
|
||||
|
||||
if ( cal_init(&cal) < 0 || ! cal )
|
||||
return;
|
||||
|
||||
local_cal_readcopy(cal, "kernel-ver", kernel_ver);
|
||||
local_cal_readcopy(cal, "initfs-ver", kernel_ver);
|
||||
local_cal_readcopy(cal, "nolo-ver", nolo_ver);
|
||||
local_cal_readcopy(cal, "sw-release-ver", sw_ver);
|
||||
local_cal_readcopy(cal, "content-ver", content_ver);
|
||||
local_cal_readcopy(cal, "r&d_mode", rd_mode);
|
||||
|
||||
/* overwritten hw revision */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
local_cal_readcopy(cal, "hw-ver", buf);
|
||||
|
||||
if ( buf[0] && sscanf(buf, "%hd", &hwrev) != 1 )
|
||||
hwrev = -1;
|
||||
|
||||
if ( hwrev == -1 ) {
|
||||
|
||||
/* original hw revision */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
local_cal_readcopy(cal, "phone-info", buf);
|
||||
buf[4] = 0;
|
||||
|
||||
if ( buf[0] && sscanf(buf, "%hd", &hwrev) != 1 )
|
||||
hwrev = -1;
|
||||
|
||||
}
|
||||
|
||||
buf[0] = 0;
|
||||
local_cal_readcopy(cal, "usb_host_mode", buf);
|
||||
usb_host_mode = buf[0];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
local_cal_readcopy(cal, "root_device", buf);
|
||||
|
||||
if ( strcmp(buf, "mmc") == 0 )
|
||||
root_device = 1;
|
||||
else if ( strcmp(buf, "usb") == 0 )
|
||||
root_device = 2;
|
||||
else
|
||||
root_device = 0;
|
||||
|
||||
cal_finish(cal);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int local_init(void) {
|
||||
|
||||
#if defined(__linux__) && defined(__arm__)
|
||||
char buf[1024];
|
||||
char * ptr;
|
||||
char * ptr2;
|
||||
FILE * file;
|
||||
#endif
|
||||
|
||||
if ( failed )
|
||||
return -1;
|
||||
|
||||
#if defined(__linux__) && defined(__arm__)
|
||||
|
||||
file = fopen("/proc/cpuinfo", "r");
|
||||
if ( ! file ) {
|
||||
failed = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( fgets(buf, sizeof(buf), file) ) {
|
||||
|
||||
if ( strncmp(buf, "Hardware", sizeof("Hardware")-1) == 0 ) {
|
||||
|
||||
ptr = buf + sizeof("Hardware")-1;
|
||||
|
||||
while ( ptr < buf + sizeof(buf) && *ptr > 0 && *ptr <= 32 )
|
||||
++ptr;
|
||||
|
||||
if ( *ptr != ':' )
|
||||
continue;
|
||||
|
||||
++ptr;
|
||||
|
||||
while ( ptr < buf + sizeof(buf) && *ptr > 0 && *ptr <= 32 )
|
||||
++ptr;
|
||||
|
||||
if ( ! *ptr )
|
||||
continue;
|
||||
|
||||
ptr2 = buf + strlen(buf);
|
||||
|
||||
while ( *ptr2 <= 32 ) {
|
||||
*ptr2 = 0;
|
||||
--ptr2;
|
||||
}
|
||||
|
||||
if ( strcmp(ptr, "Nokia 770") == 0 )
|
||||
device = DEVICE_SU_18;
|
||||
else if ( strcmp(ptr, "Nokia N800") == 0 )
|
||||
device = DEVICE_RX_34;
|
||||
else if ( strcmp(ptr, "Nokia N810") == 0 )
|
||||
device = DEVICE_RX_44;
|
||||
else if ( strcmp(ptr, "Nokia N810 WiMAX") == 0 )
|
||||
device = DEVICE_RX_48;
|
||||
else if ( strcmp(ptr, "Nokia RX-51 board") == 0 )
|
||||
device = DEVICE_RX_51;
|
||||
|
||||
if ( device ) {
|
||||
printf("Found local device: %s\n", device_to_long_string(device));
|
||||
fclose(file);
|
||||
local_cal_parse();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
#endif
|
||||
|
||||
failed = 1;
|
||||
printf("Not a local device\n");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
enum device local_get_device(void) {
|
||||
|
||||
return device;
|
||||
|
||||
}
|
||||
|
||||
static int local_nanddump(const char * file, int mtd, int offset, int length) {
|
||||
|
||||
struct statvfs buf;
|
||||
char * command;
|
||||
char * path;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
path = strdup(file);
|
||||
if ( ! path )
|
||||
return 1;
|
||||
|
||||
ret = statvfs(dirname(path), &buf);
|
||||
|
||||
free(path);
|
||||
|
||||
if ( ret == 0 && buf.f_bsize * buf.f_bfree < (long unsigned int)length ) {
|
||||
ERROR("Not enough free space (have: %ju, need: %d)", (intmax_t)(buf.f_bsize * buf.f_bfree), length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size = snprintf(NULL, 0, "nanddump --omitoob -s %d -l %d -f %s /dev/mtd%d", offset, length, file, mtd);
|
||||
|
||||
command = malloc(size+1);
|
||||
if ( ! command )
|
||||
return 1;
|
||||
|
||||
snprintf(command, size+1, "nanddump --omitoob -s %d -l %d -f %s /dev/mtd%d", offset, length, file, mtd);
|
||||
|
||||
if ( ! simulate )
|
||||
ret = system(command);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
free(command);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static FILE * local_nandwrite(int mtd, int offset) {
|
||||
|
||||
char * command;
|
||||
FILE * stream;
|
||||
size_t size;
|
||||
|
||||
size = snprintf(NULL, 0, "nandwrite -a -s %d -p /dev/mtd%d -", offset, mtd);
|
||||
|
||||
command = malloc(size+1);
|
||||
if ( ! command )
|
||||
return NULL;
|
||||
|
||||
snprintf(command, size+1, "nandwrite -a -s %d -p /dev/mtd%d -", offset, mtd);
|
||||
|
||||
if ( ! simulate )
|
||||
stream = popen(command, "w");
|
||||
else
|
||||
stream = NULL;
|
||||
|
||||
free(command);
|
||||
|
||||
return stream;
|
||||
|
||||
}
|
||||
|
||||
struct nandpart_args {
|
||||
unsigned int mtd;
|
||||
unsigned int offset;
|
||||
unsigned int length;
|
||||
unsigned int header;
|
||||
};
|
||||
|
||||
static struct nandpart_args nandpart_rx51[] = {
|
||||
[IMAGE_XLOADER] = { 0, 0x00000000, 0x00004000, 0x00000000 },
|
||||
[IMAGE_SECONDARY] = { 0, 0x00004000, 0x0001C000, 0x00000000 },
|
||||
[IMAGE_KERNEL] = { 3, 0x00000000, 0x00200000, 0x00000800 },
|
||||
[IMAGE_INITFS] = { 4, 0x00000000, 0x00200000, 0x00000000 },
|
||||
[IMAGE_ROOTFS] = { 5, 0x00000000, 0x0fb40000, 0x00000000 },
|
||||
};
|
||||
|
||||
/* FIXME: Is this table correct? */
|
||||
static struct nandpart_args nandpart_rx4x[] = {
|
||||
[IMAGE_XLOADER] = { 0, 0x00000200, 0x00003E00, 0x00000000 },
|
||||
[IMAGE_SECONDARY] = { 0, 0x00004000, 0x0001C000, 0x00000000 },
|
||||
[IMAGE_KERNEL] = { 2, 0x00000000, 0x00220000, 0x00000800 },
|
||||
[IMAGE_INITFS] = { 3, 0x00000000, 0x00400000, 0x00000000 },
|
||||
[IMAGE_ROOTFS] = { 4, 0x00000000, 0x0f960000, 0x00000000 },
|
||||
};
|
||||
|
||||
/* FIXME: Is this table correct? */
|
||||
static struct nandpart_args nandpart_old[] = {
|
||||
[IMAGE_XLOADER] = { 0, 0x00000200, 0x00003E00, 0x00000000 },
|
||||
[IMAGE_SECONDARY] = { 0, 0x00004000, 0x0001C000, 0x00000000 },
|
||||
[IMAGE_KERNEL] = { 2, 0x00000000, 0x00200000, 0x00000800 },
|
||||
[IMAGE_INITFS] = { 3, 0x00000000, 0x00200000, 0x00000000 },
|
||||
[IMAGE_ROOTFS] = { 4, 0x00000000, 0x0fb80000, 0x00000000 },
|
||||
};
|
||||
|
||||
struct nand_device {
|
||||
size_t count;
|
||||
struct nandpart_args * args;
|
||||
};
|
||||
|
||||
#define NAND_DEVICE(device, array) [device] = { .count = sizeof(array)/sizeof(array[0]), .args = array }
|
||||
|
||||
static struct nand_device nand_device[] = {
|
||||
NAND_DEVICE(DEVICE_SU_18, nandpart_old),
|
||||
NAND_DEVICE(DEVICE_RX_34, nandpart_old),
|
||||
NAND_DEVICE(DEVICE_RX_44, nandpart_rx4x),
|
||||
NAND_DEVICE(DEVICE_RX_48, nandpart_rx4x),
|
||||
NAND_DEVICE(DEVICE_RX_51, nandpart_rx51),
|
||||
};
|
||||
|
||||
#undef NANDDUMP
|
||||
|
||||
static void local_find_internal_mydocs(int * maj, int * min) {
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
int fd;
|
||||
DIR * dir;
|
||||
DIR * dir2;
|
||||
FILE * f;
|
||||
struct dirent * dirent;
|
||||
struct dirent * dirent2;
|
||||
char buf[1024];
|
||||
|
||||
/* Find min & maj id for block device MyDocs (mmc device, partition 1) */
|
||||
|
||||
dir = opendir("/sys/class/mmc_host/");
|
||||
if ( ! dir ) {
|
||||
ERROR("Cannot find MyDocs mmc device: Opening '/sys/class/mmc_host/' failed");
|
||||
return;
|
||||
}
|
||||
|
||||
while ( ( dirent = readdir(dir) ) ) {
|
||||
|
||||
if ( strncmp(dirent->d_name, ".", sizeof(".")) == 0 || strncmp(dirent->d_name, "..", sizeof("..")) == 0 )
|
||||
continue;
|
||||
|
||||
if ( snprintf(buf, sizeof(buf), "/sys/class/mmc_host/%s/slot_name", dirent->d_name) <= 0 )
|
||||
continue;
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if ( fd < 0 )
|
||||
continue;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if ( read(fd, buf, sizeof(buf)-1) < 0 )
|
||||
buf[0] = 0;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
|
||||
if ( strncmp(buf, "internal", sizeof("internal")-1) != 0 )
|
||||
continue;
|
||||
|
||||
if ( snprintf(buf, sizeof(buf), "/sys/class/mmc_host/%s/%s:0001/", dirent->d_name, dirent->d_name) <= 0 )
|
||||
continue;
|
||||
|
||||
dir2 = opendir(buf);
|
||||
if ( ! dir2 )
|
||||
continue;
|
||||
|
||||
while ( ( dirent2 = readdir(dir2) ) ) {
|
||||
|
||||
if ( strncmp(dirent2->d_name, "block:mmcblk", sizeof("block:mmcblk")-1) != 0 )
|
||||
continue;
|
||||
|
||||
if ( snprintf(buf, sizeof(buf), "/sys/class/mmc_host/%s/%s:0001/%s/dev", dirent->d_name, dirent->d_name, dirent2->d_name) <= 0 )
|
||||
continue;
|
||||
|
||||
f = fopen(buf, "r");
|
||||
if ( ! f )
|
||||
continue;
|
||||
|
||||
if ( fscanf(f, "%d:%d", maj, min) != 2 ) {
|
||||
*maj = -1;
|
||||
*min = -1;
|
||||
fclose(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
closedir(dir2);
|
||||
|
||||
if ( *maj != -1 && *min != -1 )
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int local_dump_image(enum image_type image, const char * file) {
|
||||
|
||||
unsigned char buf[20];
|
||||
int ret = -1;
|
||||
int fd = -1;
|
||||
int header = 0;
|
||||
unsigned char * addr = NULL;
|
||||
off_t nlen = (off_t)-1;
|
||||
off_t len;
|
||||
int align;
|
||||
int maj, min;
|
||||
|
||||
printf("Dump %s image to file %s...\n", image_type_to_string(image), file);
|
||||
|
||||
if ( image == IMAGE_MMC ) {
|
||||
|
||||
maj = -1;
|
||||
min = -1;
|
||||
|
||||
local_find_internal_mydocs(&maj, &min);
|
||||
if ( maj == -1 || min == -1 ) {
|
||||
ERROR("Cannot find MyDocs mmc device: Slot 'internal' was not found");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
VERBOSE("Detected internal MyDocs mmc device: major=%d minor=%d\n", maj, min);
|
||||
|
||||
fd = disk_open_dev(maj, min, 1, 1);
|
||||
if ( fd < 0 ) {
|
||||
ERROR("Cannot open MyDocs mmc device in /dev/");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = disk_dump_dev(fd, file);
|
||||
|
||||
close(fd);
|
||||
fd = -1;
|
||||
|
||||
} else {
|
||||
|
||||
if ( device >= sizeof(nand_device)/sizeof(nand_device[0]) ) {
|
||||
ERROR("Unsupported device");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if ( image >= nand_device[device].count ) {
|
||||
ERROR("Unsupported image type: %s", image_type_to_string(image));
|
||||
goto clean;
|
||||
}
|
||||
|
||||
header = nand_device[device].args[image].header;
|
||||
|
||||
if ( header > 0 ) {
|
||||
|
||||
ret = local_nanddump(file, nand_device[device].args[image].mtd, nand_device[device].args[image].offset, header);
|
||||
if ( ret != 0 ) {
|
||||
if ( ! simulate )
|
||||
unlink(file);
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if ( ! simulate ) {
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if ( fd >= 0 ) {
|
||||
if ( read(fd, buf, 20) == 20 ) {
|
||||
if ( memcmp(buf, "NOLO!img\x02\x00\x00\x00\x00\x00\x00\x00", 16) == 0 )
|
||||
nlen = ((unsigned int)buf[16] << 0) | ((unsigned int)buf[17] << 8) | ((unsigned int)buf[18] << 16) | ((unsigned int)buf[19] << 24);
|
||||
else if ( memcmp(buf, "NOLO img", 8) == 0 )
|
||||
nlen = ((unsigned int)buf[8] << 0) | ((unsigned int)buf[9] << 8) | ((unsigned int)buf[10] << 16) | ((unsigned int)buf[11] << 24);
|
||||
}
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
unlink(file);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = local_nanddump(file, nand_device[device].args[image].mtd, nand_device[device].args[image].offset + header, nand_device[device].args[image].length - header);
|
||||
|
||||
}
|
||||
|
||||
if ( ret != 0 ) {
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if ( simulate )
|
||||
goto clean;
|
||||
|
||||
fd = open(file, O_RDWR);
|
||||
if ( fd < 0 )
|
||||
goto clean;
|
||||
|
||||
len = lseek(fd, 0, SEEK_END);
|
||||
if ( len == (off_t)-1 || len == 0 )
|
||||
goto clean;
|
||||
|
||||
if ( header <= 0 || nlen == (off_t)-1 ) {
|
||||
|
||||
addr = (unsigned char *)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
if ( addr == MAP_FAILED )
|
||||
addr = NULL;
|
||||
|
||||
if ( ! addr )
|
||||
goto clean;
|
||||
|
||||
for ( nlen = len; nlen > 0; --nlen )
|
||||
if ( addr[nlen-1] != 0xFF )
|
||||
break;
|
||||
|
||||
for ( ; nlen > 0; --nlen )
|
||||
if ( addr[nlen-1] != 0x00 )
|
||||
break;
|
||||
|
||||
if ( image == IMAGE_MMC )
|
||||
align = 8;
|
||||
else
|
||||
align = 7;
|
||||
|
||||
if ( ( nlen & ( ( 1ULL << align ) - 1 ) ) != 0 )
|
||||
nlen = ((nlen >> align) + 1) << align;
|
||||
|
||||
}
|
||||
|
||||
if ( header <= 0 && nlen == 0 ) {
|
||||
printf("File %s is empty, removing it...\n", file);
|
||||
unlink(file);
|
||||
} else if ( nlen != len ) {
|
||||
printf("Truncating file %s to %d bytes...\n", file, (int)nlen);
|
||||
if ( ftruncate(fd, nlen) < 0 )
|
||||
ERROR_INFO("Cannot truncate file %s", file);
|
||||
}
|
||||
|
||||
clean:
|
||||
if ( addr )
|
||||
munmap((void *)addr, len);
|
||||
|
||||
if ( fd >= 0 )
|
||||
close(fd);
|
||||
|
||||
printf("\n");
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int local_flash_image(struct image * image) {
|
||||
|
||||
unsigned char buf[0x20000];
|
||||
unsigned int remaining, size;
|
||||
void (*sighandler)(int);
|
||||
int min, maj, fd;
|
||||
FILE * stream;
|
||||
int ret;
|
||||
|
||||
printf("Flash image:\n");
|
||||
image_print_info(image);
|
||||
|
||||
if ( image->type == IMAGE_MMC ) {
|
||||
|
||||
maj = -1;
|
||||
min = -1;
|
||||
|
||||
local_find_internal_mydocs(&maj, &min);
|
||||
if ( maj == -1 || min == -1 )
|
||||
ERROR_RETURN("Cannot find MyDocs mmc device: Slot 'internal' was not found", -1);
|
||||
|
||||
VERBOSE("Detected internal MyDocs mmc device: major=%d minor=%d\n", maj, min);
|
||||
|
||||
fd = disk_open_dev(maj, min, 1, simulate ? 1 : 0);
|
||||
if ( fd < 0 )
|
||||
ERROR_RETURN("Cannot open MyDocs mmc device in /dev/", -1);
|
||||
|
||||
ret = disk_flash_dev(fd, image);
|
||||
|
||||
close(fd);
|
||||
|
||||
} else {
|
||||
|
||||
if ( device >= sizeof(nand_device)/sizeof(nand_device[0]) )
|
||||
ERROR_RETURN("Unsupported device", -1);
|
||||
|
||||
if ( image->type >= nand_device[device].count ) {
|
||||
ERROR("Unsupported image type: %s", image_type_to_string(image->type));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( image->size > nand_device[device].args[image->type].length - nand_device[device].args[image->type].header )
|
||||
ERROR_RETURN("Image is too big", -1);
|
||||
|
||||
printf("Using nandwrite for flashing %s image...\n", image_type_to_string(image->type));
|
||||
|
||||
stream = local_nandwrite(nand_device[device].args[image->type].mtd, nand_device[device].args[image->type].offset);
|
||||
if ( ! simulate && ! stream )
|
||||
ERROR_RETURN("Cannot start nandwrite process", -1);
|
||||
|
||||
ret = 0;
|
||||
sighandler = signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Write NOLO!img or NOLO img header with size */
|
||||
if ( nand_device[device].args[image->type].header > 0 ) {
|
||||
if ( device == DEVICE_RX_51 ) {
|
||||
memcpy(buf, "NOLO!img\x02\x00\x00\x00\x00\x00\x00\x00", 16);
|
||||
buf[16] = (image->size >> 0) & 0xFF;
|
||||
buf[17] = (image->size >> 8) & 0xFF;
|
||||
buf[18] = (image->size >> 16) & 0xFF;
|
||||
buf[19] = (image->size >> 24) & 0xFF;
|
||||
size = 20;
|
||||
} else {
|
||||
memcpy(buf, "NOLO img", 8);
|
||||
buf[ 8] = (image->size >> 0) & 0xFF;
|
||||
buf[ 9] = (image->size >> 8) & 0xFF;
|
||||
buf[10] = (image->size >> 16) & 0xFF;
|
||||
buf[11] = (image->size >> 24) & 0xFF;
|
||||
size = 12;
|
||||
}
|
||||
|
||||
if ( ! simulate ) {
|
||||
if ( fwrite(buf, size, 1, stream) != 1 ) {
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
remaining = nand_device[device].args[image->type].header - size;
|
||||
while ( remaining > 0 ) {
|
||||
size = remaining < sizeof(buf) ? remaining : sizeof(buf);
|
||||
if ( ! simulate ) {
|
||||
if ( fwrite(buf, size, 1, stream) != 1 ) {
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
remaining -= size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write image data */
|
||||
image_seek(image, 0);
|
||||
remaining = image->size;
|
||||
while ( remaining > 0 ) {
|
||||
size = remaining < sizeof(buf) ? remaining : sizeof(buf);
|
||||
size = image_read(image, buf, size);
|
||||
if ( size == 0 ) {
|
||||
ERROR("Failed to read image");
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
if ( ! simulate ) {
|
||||
if ( fwrite(buf, size, 1, stream) != 1 ) {
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
remaining -= size;
|
||||
}
|
||||
|
||||
/* Write filler zeros to clear previous data */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
remaining = nand_device[device].args[image->type].length - (image->size + nand_device[device].args[image->type].header);
|
||||
while ( remaining > 0 ) {
|
||||
size = remaining < sizeof(buf) ? remaining : sizeof(buf);
|
||||
if ( ! simulate ) {
|
||||
if ( fwrite(buf, size, 1, stream) != 1 ) {
|
||||
ret = -1;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
remaining -= size;
|
||||
}
|
||||
|
||||
clean:
|
||||
if ( ! simulate ) {
|
||||
if ( ret == 0 )
|
||||
ret = pclose(stream);
|
||||
else
|
||||
pclose(stream);
|
||||
}
|
||||
|
||||
signal(SIGPIPE, sighandler);
|
||||
|
||||
if ( ret != 0 )
|
||||
ERROR("Flashing failed");
|
||||
}
|
||||
|
||||
if ( ret == 0 )
|
||||
printf("Done\n");
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int local_check_badblocks(const char * device) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)device;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_reboot_device(void) {
|
||||
|
||||
if ( system("dsmetool -b") == 0 )
|
||||
return 0;
|
||||
return system("reboot");
|
||||
|
||||
}
|
||||
|
||||
int local_get_root_device(void) {
|
||||
|
||||
return root_device;
|
||||
|
||||
}
|
||||
|
||||
int local_set_root_device(int device) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)device;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_usb_host_mode(void) {
|
||||
|
||||
return usb_host_mode;
|
||||
|
||||
}
|
||||
|
||||
int local_set_usb_host_mode(int enable) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)enable;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_rd_mode(void) {
|
||||
|
||||
if ( strncmp(rd_mode, "master", sizeof("master")-1) == 0 )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_rd_mode(int enable) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)enable;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_rd_flags(char * flags, size_t size) {
|
||||
|
||||
const char * ptr;
|
||||
|
||||
if ( strncmp(rd_mode, "master", sizeof("master")-1) == 0 )
|
||||
ptr = rd_mode + sizeof("master")-1;
|
||||
else
|
||||
ptr = rd_mode;
|
||||
|
||||
if ( *ptr == ',' )
|
||||
++ptr;
|
||||
|
||||
if ( ! *ptr ) {
|
||||
flags[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
strncpy(flags, ptr, size);
|
||||
flags[size-1] = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_rd_flags(const char * flags) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)flags;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int16_t local_get_hwrev(void) {
|
||||
|
||||
return hwrev;
|
||||
|
||||
}
|
||||
|
||||
int local_set_hwrev(int16_t hwrev) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)hwrev;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_kernel_ver(char * ver, size_t size) {
|
||||
|
||||
strncpy(ver, kernel_ver, size);
|
||||
ver[size-1] = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_kernel_ver(const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_initfs_ver(char * ver, size_t size) {
|
||||
|
||||
strncpy(ver, initfs_ver, size);
|
||||
ver[size-1] = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_initfs_ver(const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_nolo_ver(char * ver, size_t size) {
|
||||
|
||||
strncpy(ver, nolo_ver, size);
|
||||
ver[size-1] = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_nolo_ver(const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_sw_ver(char * ver, size_t size) {
|
||||
|
||||
strncpy(ver, sw_ver, size);
|
||||
ver[size-1] = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_sw_ver(const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int local_get_content_ver(char * ver, size_t size) {
|
||||
|
||||
strncpy(ver, content_ver, size);
|
||||
ver[size-1] = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int local_set_content_ver(const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LOCAL_H
|
||||
#define LOCAL_H
|
||||
|
||||
#include "image.h"
|
||||
#include "device.h"
|
||||
|
||||
int local_init(void);
|
||||
|
||||
enum device local_get_device(void);
|
||||
|
||||
int local_flash_image(struct image * image);
|
||||
int local_dump_image(enum image_type image, const char * file);
|
||||
int local_check_badblocks(const char * device);
|
||||
|
||||
int local_reboot_device(void);
|
||||
|
||||
int local_get_root_device(void);
|
||||
int local_set_root_device(int device);
|
||||
|
||||
int local_get_usb_host_mode(void);
|
||||
int local_set_usb_host_mode(int enable);
|
||||
|
||||
int local_get_rd_mode(void);
|
||||
int local_set_rd_mode(int enable);
|
||||
|
||||
int local_get_rd_flags(char * flags, size_t size);
|
||||
int local_set_rd_flags(const char * flags);
|
||||
|
||||
int16_t local_get_hwrev(void);
|
||||
int local_set_hwrev(int16_t hwrev);
|
||||
|
||||
int local_get_kernel_ver(char * ver, size_t size);
|
||||
int local_set_kernel_ver(const char * ver);
|
||||
|
||||
int local_get_initfs_ver(char * ver, size_t size);
|
||||
int local_set_initfs_ver(const char * ver);
|
||||
|
||||
int local_get_nolo_ver(char * ver, size_t size);
|
||||
int local_set_nolo_ver(const char * ver);
|
||||
|
||||
int local_get_sw_ver(char * ver, size_t size);
|
||||
int local_set_sw_ver(const char * ver);
|
||||
|
||||
int local_get_content_ver(char * ver, size_t size);
|
||||
int local_set_content_ver(const char * ver);
|
||||
|
||||
#endif
|
||||
+1503
-319
File diff suppressed because it is too large.
Load diff
-109
@@ -1,109 +0,0 @@
|
||||
|
||||
#ifndef _INCLUDE_MAIN_H_
|
||||
#define _INCLUDE_MAIN_H_
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _GNU_SOURCE
|
||||
|
||||
// Forward declaration for use in function arguments.
|
||||
struct devices;
|
||||
|
||||
int reverse_extract_pieces(char *dir);
|
||||
void flash_image(char *filename, char *piece, char *version);
|
||||
int fiasco_read_image(char *file);
|
||||
void check_nolo_order();
|
||||
extern struct usb_dev_handle *dev;
|
||||
unsigned long get_file_size(char *file);
|
||||
void progressbar(unsigned long long part, unsigned long long total);
|
||||
const char *fpid_file(const char *filename);
|
||||
int add_piece(char *piece);
|
||||
void eprintf(const char *format, ...);
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
#include <usb.h>
|
||||
|
||||
extern struct usb_device *device;
|
||||
extern struct usb_dev_handle *dev;
|
||||
int is_valid_device(struct usb_device_descriptor *udd);
|
||||
void list_valid_devices();
|
||||
int usb_device_found(struct usb_device_descriptor *udd, struct devices *it_device);
|
||||
int console(const char *device);
|
||||
int connect_via_usb();
|
||||
int console_prompt();
|
||||
|
||||
//
|
||||
void cmd_info(char *line);
|
||||
int check_badblocks(char *mtddev);
|
||||
int dump_config();
|
||||
|
||||
extern int verbose;
|
||||
#define D if (verbose)
|
||||
|
||||
#define CMD_WRITE 64
|
||||
#define CMD_QUERY 192
|
||||
|
||||
#define NOLO_GET_STATUS 1
|
||||
#define NOLO_GET_BOARD_ID 2
|
||||
#define NOLO_GET_VERSION 3
|
||||
|
||||
struct piece_t {
|
||||
char *name;
|
||||
char *type;
|
||||
char *vers;
|
||||
};
|
||||
|
||||
struct devices {
|
||||
char *name;
|
||||
unsigned short vendor_id;
|
||||
unsigned short product_id;
|
||||
unsigned short flags;
|
||||
};
|
||||
|
||||
#define SUPPORTED_DEVICES 6
|
||||
extern struct devices supported_devices[SUPPORTED_DEVICES];
|
||||
|
||||
extern int pcs_n;
|
||||
extern struct piece_t pcs[10];
|
||||
|
||||
enum {
|
||||
PIECE_XLOADER = 0,
|
||||
PIECE_2ND,
|
||||
PIECE_SECONDARY,
|
||||
PIECE_KERNEL,
|
||||
PIECE_INITFS,
|
||||
PIECE_ROOTFS,
|
||||
PIECE_OMAPNAND,
|
||||
PIECE_LAST
|
||||
};
|
||||
|
||||
struct header_t {
|
||||
int fd;
|
||||
char fwname[128];
|
||||
char name[128];
|
||||
char version[128];
|
||||
unsigned short hash;
|
||||
unsigned int size;
|
||||
unsigned char *data;
|
||||
};
|
||||
|
||||
extern char *pieces[];
|
||||
extern char *modes[];
|
||||
extern char *root_devices[];
|
||||
|
||||
// fiasco
|
||||
int openfiasco(char *name);
|
||||
int fiasco_new(const char *filename, const char *name);
|
||||
void fiasco_data_read(struct header_t *header);
|
||||
int fiasco_add_eof(int fd);
|
||||
extern void (*fiasco_callback)(struct header_t *header);
|
||||
int fiasco_add(int fd, const char *name, const char *file, const char *version);
|
||||
int fiasco_pack(int optind, char *argv[]);
|
||||
int nanddump(char *mtddev, unsigned long start_addr, unsigned long length, char *dumpfile, int isbl, int ioob);
|
||||
|
||||
|
||||
#endif
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NAME "0xFFFF"
|
||||
#define INFO NAME " \\- Open Free Fiasco Firmware Flasher, version " VERSION
|
||||
#define DESCRIPTION "0xFFFF is Open Free Fiasco Firmware Flasher for Maemo devices. It support generating and unpacking FIASCO images on local computer. Useful for editing Maemo firmware package for future flash. It support via USB flashing any image type to Maemo device and also \"cold\" flashing which means flashing dead device with erased bootloader. There is support for booting kernel via USB without flashing to NAND and also changing configuration of Maemo device (enable/disable R&D mode, changing HW revision strings, ...).\n\n0xFFFF is alternative tool to proprietary Nokia flasher-3.5 and fiasco-gen. 0xFFFF generate compatible FIASCO images and also accept FIASCO images generated by Nokia fiasco-gen."
|
||||
|
||||
#ifndef BUILD_DATE
|
||||
#define BUILD_DATE __DATE__
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
|
||||
FILE * pipe;
|
||||
char buf[1024];
|
||||
|
||||
pipe = popen("./0xFFFF -h", "r");
|
||||
if ( ! pipe )
|
||||
return 1;
|
||||
|
||||
puts(".TH " NAME " 1 \"" BUILD_DATE "\" \"" NAME " " VERSION "\"");
|
||||
puts("");
|
||||
|
||||
puts(".SH NAME");
|
||||
puts(INFO);
|
||||
puts("");
|
||||
|
||||
puts(".SH SYNOPSIS");
|
||||
puts(".B " NAME);
|
||||
puts(".I [options]");
|
||||
puts("");
|
||||
|
||||
puts(".SH DESCRIPTION");
|
||||
puts(DESCRIPTION);
|
||||
|
||||
while ( fgets(buf, sizeof(buf), pipe) ) {
|
||||
|
||||
if ( ! buf[0] )
|
||||
continue;
|
||||
|
||||
if ( buf[0] == ' ' && buf[2] == ' ' ) {
|
||||
|
||||
char * ptr = buf;
|
||||
|
||||
while ( *ptr && *ptr == ' ' )
|
||||
++ptr;
|
||||
|
||||
if ( ! *ptr )
|
||||
continue;
|
||||
|
||||
printf(".br\n%s", ptr);
|
||||
|
||||
} else if ( buf[0] == ' ' ) {
|
||||
|
||||
char * ptr = buf;
|
||||
char * ptr2;
|
||||
|
||||
while ( *ptr && *ptr == ' ' )
|
||||
++ptr;
|
||||
|
||||
if ( ! *ptr )
|
||||
continue;
|
||||
|
||||
ptr2 = ptr;
|
||||
|
||||
while ( *ptr2 && ( *ptr2 != ' ' || *(ptr2-1) != ' ' ) )
|
||||
++ptr2;
|
||||
|
||||
*(ptr2-1) = 0;
|
||||
|
||||
while ( *ptr2 && *ptr2 == ' ' )
|
||||
++ptr2;
|
||||
|
||||
if ( *ptr2 )
|
||||
printf(".TP\n.B %s\n%s", ptr, ptr2);
|
||||
else
|
||||
printf(".br\n%s\n", ptr);
|
||||
|
||||
} else if ( buf[strlen(buf)-2] == ':' ) {
|
||||
|
||||
printf("\n.SH %s\n", buf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pclose(pipe);
|
||||
return 0;
|
||||
|
||||
}
|
||||
+583
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "mkii.h"
|
||||
#include "global.h"
|
||||
#include "image.h"
|
||||
#include "device.h"
|
||||
#include "usb-device.h"
|
||||
|
||||
#define MKII_OUT 0x8810001B
|
||||
#define MKII_IN 0x8800101B
|
||||
|
||||
#define MKII_PING 0x00
|
||||
#define MKII_GET 0x01
|
||||
#define MKII_TELL 0x02
|
||||
#define MKII_REBOOT 0x0C
|
||||
#define MKII_RESPONCE 0x20
|
||||
|
||||
struct mkii_message {
|
||||
uint32_t header;
|
||||
uint16_t size;
|
||||
uint16_t zero;
|
||||
uint8_t num;
|
||||
uint8_t type;
|
||||
char data[];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
static int mkii_send_receive(libusb_device_handle * udev, uint8_t type, struct mkii_message * in_msg, size_t data_size, struct mkii_message * out_msg, size_t out_size) {
|
||||
|
||||
int ret;
|
||||
static uint8_t number = 0;
|
||||
|
||||
in_msg->header = MKII_OUT;
|
||||
in_msg->size = htons(data_size + 4);
|
||||
in_msg->zero = 0;
|
||||
in_msg->num = number++;
|
||||
in_msg->type = type;
|
||||
|
||||
ret = usb_bulk_send(udev, USB_WRITE_EP, in_msg, data_size + sizeof(*in_msg), 5000);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
if ( (size_t)ret != data_size + sizeof(*in_msg) )
|
||||
return -1;
|
||||
|
||||
ret = usb_bulk_recv(udev, USB_READ_EP, out_msg, out_size, 5000);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
if ( out_msg->header != MKII_IN )
|
||||
return -1;
|
||||
|
||||
if ( out_msg->type != (type | MKII_RESPONCE) )
|
||||
return -1;
|
||||
|
||||
if ( (size_t)ret < sizeof(*out_msg) )
|
||||
return -1;
|
||||
|
||||
if ( ntohs(out_msg->size) != ret - sizeof(*out_msg) + 4 )
|
||||
return -1;
|
||||
|
||||
return ret - sizeof(*out_msg);
|
||||
|
||||
}
|
||||
|
||||
int mkii_init(struct usb_device_info * dev) {
|
||||
|
||||
char buf[2048];
|
||||
struct mkii_message * msg;
|
||||
struct libusb_config_descriptor * config;
|
||||
enum device device;
|
||||
int ret;
|
||||
char * newptr;
|
||||
char * ptr;
|
||||
enum image_type type;
|
||||
|
||||
printf("Initializing Mk II protocol...\n");
|
||||
|
||||
msg = (struct mkii_message *)buf;
|
||||
|
||||
ret = mkii_send_receive(dev->udev, MKII_PING, msg, 0, msg, sizeof(buf));
|
||||
if ( ret != 0 )
|
||||
ERROR_RETURN("Cannot ping device", -1);
|
||||
|
||||
memcpy(msg->data, "/update/protocol_version", sizeof("/update/protocol_version")-1);
|
||||
ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/update/protocol_version")-1, msg, sizeof(buf));
|
||||
if ( ret < 2 || msg->data[0] != 0 )
|
||||
ERROR_RETURN("Cannot get Mk II protocol version", -1);
|
||||
|
||||
msg->data[ret] = 0;
|
||||
|
||||
if ( ret == 2 && msg->data[1] == 0x32 )
|
||||
dev->data |= MKII_SUPPORT_SW_RELEASE;
|
||||
|
||||
printf("Detected Mk II protocol version: %s\n", msg->data);
|
||||
|
||||
memcpy(msg->data, "/update/host_protocol_version\x00\x32", sizeof("/update/host_protocol_version\x00\x32")-1);
|
||||
ret = mkii_send_receive(dev->udev, MKII_TELL, msg, sizeof("/update/host_protocol_version\x00\x32")-1, msg, sizeof(buf));
|
||||
if ( ret != 1 || msg->data[0] != 0 )
|
||||
ERROR_RETURN("Cannot send our protocol version", -1);
|
||||
|
||||
device = mkii_get_device(dev);
|
||||
|
||||
if ( ! dev->device )
|
||||
dev->device = device;
|
||||
|
||||
if ( dev->device && device && dev->device != device ) {
|
||||
ERROR("Device mishmash, expected %s, got %s", device_to_string(dev->device), device_to_string(device));
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->hwrev = mkii_get_hwrev(dev);
|
||||
|
||||
memcpy(msg->data, "/update/supported_images", sizeof("/update/supported_images")-1);
|
||||
ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/update/supported_images")-1, msg, sizeof(buf));
|
||||
if ( ret < 2 || msg->data[0] != 0 )
|
||||
ERROR_RETURN("Cannot get supported image types", -1);
|
||||
|
||||
msg->data[ret] = 0;
|
||||
ptr = msg->data + 1;
|
||||
|
||||
printf("Supported images by current device configuration:");
|
||||
|
||||
while ( ptr && *ptr ) {
|
||||
newptr = strchr(ptr, ',');
|
||||
if ( newptr ) {
|
||||
*newptr = 0;
|
||||
++newptr;
|
||||
}
|
||||
type = image_type_from_string(ptr);
|
||||
if ( type != IMAGE_UNKNOWN ) {
|
||||
dev->data |= (1UL << type);
|
||||
printf(" %s", ptr);
|
||||
}
|
||||
ptr = newptr;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if ( libusb_get_config_descriptor(libusb_get_device(dev->udev), 0, &config) == 0 ) {
|
||||
libusb_get_string_descriptor_ascii(dev->udev, config->iConfiguration, (unsigned char *)buf, sizeof(buf));
|
||||
libusb_free_config_descriptor(config);
|
||||
}
|
||||
if ( strncmp(buf, "Firmware Upgrade Configuration", sizeof("Firmware Upgrade Configuration")) == 0 )
|
||||
dev->data |= MKII_UPDATE_MODE;
|
||||
|
||||
printf("Mode: %s\n", (dev->data & MKII_UPDATE_MODE) ? "Update" : "PC Suite");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
enum device mkii_get_device(struct usb_device_info * dev) {
|
||||
|
||||
char buf[2048];
|
||||
struct mkii_message * msg;
|
||||
int ret;
|
||||
|
||||
msg = (struct mkii_message *)buf;
|
||||
|
||||
memcpy(msg->data, "/device/product_code", sizeof("/device/product_code")-1);
|
||||
ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/device/product_code")-1, msg, sizeof(buf));
|
||||
if ( ret < 2 || msg->data[0] != 0 || msg->data[1] == 0 )
|
||||
return DEVICE_UNKNOWN;
|
||||
|
||||
msg->data[ret] = 0;
|
||||
return device_from_string((char *)msg->data+1);
|
||||
|
||||
}
|
||||
|
||||
int mkii_flash_image(struct usb_device_info * dev, struct image * image) {
|
||||
|
||||
char buf1[512];
|
||||
char buf[2048];
|
||||
struct mkii_message * msg1;
|
||||
struct mkii_message * msg;
|
||||
char * ptr;
|
||||
const char * type;
|
||||
uint8_t len;
|
||||
uint16_t hash;
|
||||
uint32_t size;
|
||||
int ret;
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
return -1;
|
||||
|
||||
if ( ! ( dev->data & (1UL << image->type) ) ) {
|
||||
ERROR("Flashing image %s is not supported in current device configuration", image_type_to_string(image->type));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg = (struct mkii_message *)buf;
|
||||
msg1 = (struct mkii_message *)buf1;
|
||||
ptr = msg->data;
|
||||
|
||||
/* File data header */
|
||||
memcpy(ptr, "\x2E", 1);
|
||||
ptr += 1;
|
||||
|
||||
/* Length of file data */
|
||||
memcpy(ptr, "\x19", 1);
|
||||
ptr += 1;
|
||||
|
||||
/* File data (ignored): asic index: APE (0x01), device type: NAND (0x01), device index: 0 */
|
||||
memcpy(ptr, "\x01\x01\x00", 3);
|
||||
ptr += 3;
|
||||
|
||||
/* Hash */
|
||||
hash = htons(image->hash);
|
||||
memcpy(ptr, &hash, 2);
|
||||
ptr += 2;
|
||||
|
||||
/* Type */
|
||||
type = image_type_to_string(image->type);
|
||||
if ( ! type )
|
||||
ERROR_RETURN("Unknown image type", -1);
|
||||
memset(ptr, 0, 12);
|
||||
strncpy(ptr, type, 12);
|
||||
ptr += 12;
|
||||
|
||||
/* Size */
|
||||
size = htonl(image->size);
|
||||
memcpy(ptr, &size, 4);
|
||||
ptr += 4;
|
||||
|
||||
/* Load address (ignored) */
|
||||
memcpy(ptr, "\x00\x00\x00\x00", 4);
|
||||
ptr += 4;
|
||||
|
||||
/* Device & hwrev */
|
||||
if ( image->devices ) {
|
||||
|
||||
int i;
|
||||
uint8_t len;
|
||||
char buf[9];
|
||||
char ** bufs = NULL;
|
||||
struct device_list * device = image->devices;
|
||||
|
||||
while ( device ) {
|
||||
if ( device->device == dev->device && hwrev_is_valid(device->hwrevs, dev->hwrev) )
|
||||
break;
|
||||
device = device->next;
|
||||
}
|
||||
|
||||
if ( device )
|
||||
bufs = device_list_alloc_to_bufs(device);
|
||||
|
||||
if ( bufs ) {
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
snprintf(buf, 8+1, "%d", dev->hwrev);
|
||||
|
||||
for ( i = 0; bufs[i]; ++i ) {
|
||||
len = ((uint8_t*)bufs[i])[0];
|
||||
if ( MEMMEM(bufs[i]+1, len, buf, strlen(buf)) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( bufs[i] ) {
|
||||
/* Device & hwrev string header */
|
||||
memcpy(ptr, "\x32", 1);
|
||||
ptr += 1;
|
||||
/* Device & hwrev string size */
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
/* Device & hwrev string */
|
||||
memcpy(ptr, bufs[i]+1, len);
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
free(bufs);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Version */
|
||||
if ( image->version ) {
|
||||
len = strnlen(image->version, 255) + 1;
|
||||
/* Version string header */
|
||||
memcpy(ptr, "\x31", 1);
|
||||
ptr += 1;
|
||||
/* Version string size */
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
/* Version string */
|
||||
memcpy(ptr, image->version, len);
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
/* append layout subsection */
|
||||
if ( image->layout ) {
|
||||
len = strlen(image->layout);
|
||||
/* Layout header */
|
||||
memcpy(ptr, "\x33", 1);
|
||||
ptr += 1;
|
||||
/* Layout size */
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
/* Layout string */
|
||||
memcpy(ptr, image->layout, len);
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
/* end */
|
||||
memcpy(ptr, "\x00", 1);
|
||||
ptr += 1;
|
||||
|
||||
ret = mkii_send_receive(dev->udev, 0x03, msg1, 0, msg1, sizeof(buf1));
|
||||
if ( ret != 1 || msg1->data[0] != 0 )
|
||||
return -1;
|
||||
|
||||
ret = mkii_send_receive(dev->udev, 0x04, msg, ptr - msg->data, msg, sizeof(buf));
|
||||
if ( ret != 9 )
|
||||
return -1;
|
||||
|
||||
/* TODO: send image itself */
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int mkii_reboot_device(struct usb_device_info * dev, int update) {
|
||||
|
||||
char buf[2048];
|
||||
struct mkii_message * msg;
|
||||
const char * str;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
msg = (struct mkii_message *)buf;
|
||||
|
||||
if ( update ) {
|
||||
printf("Rebooting device to Update mode...\n");
|
||||
len = sizeof("reboot=update");
|
||||
str = "reboot=update";
|
||||
} else {
|
||||
printf("Rebooting device...\n");
|
||||
len = sizeof("reboot");
|
||||
str = "reboot";
|
||||
}
|
||||
|
||||
memcpy(msg->data, str, len);
|
||||
ret = mkii_send_receive(dev->udev, MKII_REBOOT, msg, len, msg, sizeof(buf));
|
||||
if ( ret != 1 || msg->data[0] != 0 )
|
||||
ERROR_RETURN("Cannot send reboot command", -1);
|
||||
|
||||
if (dev->data & MKII_UPDATE_MODE)
|
||||
MSLEEP(100);
|
||||
else
|
||||
MSLEEP(3000);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_root_device(struct usb_device_info * dev) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_root_device(struct usb_device_info * dev, int device) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)device;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_usb_host_mode(struct usb_device_info * dev) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_usb_host_mode(struct usb_device_info * dev, int enable) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)enable;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_rd_mode(struct usb_device_info * dev) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_rd_mode(struct usb_device_info * dev, int enable) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)enable;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)flags;
|
||||
(void)size;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_rd_flags(struct usb_device_info * dev, const char * flags) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)flags;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int16_t mkii_get_hwrev(struct usb_device_info * dev) {
|
||||
|
||||
char buf[2048];
|
||||
struct mkii_message * msg;
|
||||
int ret;
|
||||
|
||||
msg = (struct mkii_message *)buf;
|
||||
|
||||
memcpy(msg->data, "/device/hw_build", sizeof("/device/hw_build")-1);
|
||||
ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/device/hw_build")-1, msg, sizeof(buf));
|
||||
if ( ret < 2 || msg->data[0] != 0 || msg->data[1] == 0 )
|
||||
ERROR_RETURN("Cannot get hw revision", -1);
|
||||
|
||||
msg->data[ret] = 0;
|
||||
return atoi(msg->data+1);
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_hwrev(struct usb_device_info * dev, int16_t hwrev) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)hwrev;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
(void)size;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_kernel_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
(void)size;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_initfs_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
(void)size;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_nolo_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
char buf[2048];
|
||||
struct mkii_message * msg;
|
||||
int ret;
|
||||
|
||||
if ( ! ( dev->data & MKII_SUPPORT_SW_RELEASE ) )
|
||||
return -1;
|
||||
|
||||
msg = (struct mkii_message *)buf;
|
||||
|
||||
memcpy(msg->data, "/version/sw_release", sizeof("/version/sw_release")-1);
|
||||
ret = mkii_send_receive(dev->udev, MKII_GET, msg, sizeof("/version/sw_release")-1, msg, sizeof(buf));
|
||||
if ( ret < 2 || msg->data[0] != 0 || msg->data[1] == 0 )
|
||||
ERROR_RETURN("Cannot get sw release", -1);
|
||||
|
||||
msg->data[ret] = 0;
|
||||
strncpy(ver, msg->data+1, size);
|
||||
ver[size-1] = 0;
|
||||
return strlen(ver);
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_sw_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_get_content_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
(void)size;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int mkii_set_content_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
ERROR("Not implemented yet");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MKII_H
|
||||
#define MKII_H
|
||||
|
||||
#include "image.h"
|
||||
#include "device.h"
|
||||
#include "usb-device.h"
|
||||
|
||||
#define MKII_SUPPORT_SW_RELEASE (1UL << 30)
|
||||
#define MKII_UPDATE_MODE (1UL << 31)
|
||||
|
||||
int mkii_init(struct usb_device_info * dev);
|
||||
|
||||
enum device mkii_get_device(struct usb_device_info * dev);
|
||||
|
||||
int mkii_flash_image(struct usb_device_info * dev, struct image * image);
|
||||
int mkii_reboot_device(struct usb_device_info * dev, int update);
|
||||
|
||||
int mkii_get_root_device(struct usb_device_info * dev);
|
||||
int mkii_set_root_device(struct usb_device_info * dev, int device);
|
||||
|
||||
int mkii_get_usb_host_mode(struct usb_device_info * dev);
|
||||
int mkii_set_usb_host_mode(struct usb_device_info * dev, int enable);
|
||||
|
||||
int mkii_get_rd_mode(struct usb_device_info * dev);
|
||||
int mkii_set_rd_mode(struct usb_device_info * dev, int enable);
|
||||
|
||||
int mkii_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size);
|
||||
int mkii_set_rd_flags(struct usb_device_info * dev, const char * flags);
|
||||
|
||||
int16_t mkii_get_hwrev(struct usb_device_info * dev);
|
||||
int mkii_set_hwrev(struct usb_device_info * dev, int16_t hwrev);
|
||||
|
||||
int mkii_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int mkii_set_kernel_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int mkii_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int mkii_set_initfs_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int mkii_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int mkii_set_nolo_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int mkii_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int mkii_set_sw_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int mkii_get_content_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int mkii_set_content_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
#endif
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $
|
||||
*
|
||||
* Derived from (and probably identical to):
|
||||
* ftl.h 1.7 1999/10/25 20:23:17
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License
|
||||
* at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The initial developer of the original code is David A. Hinds
|
||||
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
|
||||
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use
|
||||
* your version of this file under the MPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_FTL_USER_H__
|
||||
#define __MTD_FTL_USER_H__
|
||||
|
||||
typedef struct erase_unit_header_t {
|
||||
u_int8_t LinkTargetTuple[5];
|
||||
u_int8_t DataOrgTuple[10];
|
||||
u_int8_t NumTransferUnits;
|
||||
u_int32_t EraseCount;
|
||||
u_int16_t LogicalEUN;
|
||||
u_int8_t BlockSize;
|
||||
u_int8_t EraseUnitSize;
|
||||
u_int16_t FirstPhysicalEUN;
|
||||
u_int16_t NumEraseUnits;
|
||||
u_int32_t FormattedSize;
|
||||
u_int32_t FirstVMAddress;
|
||||
u_int16_t NumVMPages;
|
||||
u_int8_t Flags;
|
||||
u_int8_t Code;
|
||||
u_int32_t SerialNumber;
|
||||
u_int32_t AltEUHOffset;
|
||||
u_int32_t BAMOffset;
|
||||
u_int8_t Reserved[12];
|
||||
u_int8_t EndTuple[2];
|
||||
} erase_unit_header_t;
|
||||
|
||||
/* Flags in erase_unit_header_t */
|
||||
#define HIDDEN_AREA 0x01
|
||||
#define REVERSE_POLARITY 0x02
|
||||
#define DOUBLE_BAI 0x04
|
||||
|
||||
/* Definitions for block allocation information */
|
||||
|
||||
#define BLOCK_FREE(b) ((b) == 0xffffffff)
|
||||
#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
|
||||
|
||||
#define BLOCK_TYPE(b) ((b) & 0x7f)
|
||||
#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
|
||||
#define BLOCK_NUMBER(b) ((b) >> 9)
|
||||
#define BLOCK_CONTROL 0x30
|
||||
#define BLOCK_DATA 0x40
|
||||
#define BLOCK_REPLACEMENT 0x60
|
||||
#define BLOCK_BAD 0x70
|
||||
|
||||
#endif /* __MTD_FTL_USER_H__ */
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
|
||||
*
|
||||
* Parts of INFTL headers shared with userspace
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_INFTL_USER_H__
|
||||
#define __MTD_INFTL_USER_H__
|
||||
|
||||
#define OSAK_VERSION 0x5120
|
||||
#define PERCENTUSED 98
|
||||
|
||||
#define SECTORSIZE 512
|
||||
|
||||
/* Block Control Information */
|
||||
|
||||
struct inftl_bci {
|
||||
uint8_t ECCsig[6];
|
||||
uint8_t Status;
|
||||
uint8_t Status1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct inftl_unithead1 {
|
||||
uint16_t virtualUnitNo;
|
||||
uint16_t prevUnitNo;
|
||||
uint8_t ANAC;
|
||||
uint8_t NACs;
|
||||
uint8_t parityPerField;
|
||||
uint8_t discarded;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct inftl_unithead2 {
|
||||
uint8_t parityPerField;
|
||||
uint8_t ANAC;
|
||||
uint16_t prevUnitNo;
|
||||
uint16_t virtualUnitNo;
|
||||
uint8_t NACs;
|
||||
uint8_t discarded;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct inftl_unittail {
|
||||
uint8_t Reserved[4];
|
||||
uint16_t EraseMark;
|
||||
uint16_t EraseMark1;
|
||||
} __attribute__((packed));
|
||||
|
||||
union inftl_uci {
|
||||
struct inftl_unithead1 a;
|
||||
struct inftl_unithead2 b;
|
||||
struct inftl_unittail c;
|
||||
};
|
||||
|
||||
struct inftl_oob {
|
||||
struct inftl_bci b;
|
||||
union inftl_uci u;
|
||||
};
|
||||
|
||||
|
||||
/* INFTL Media Header */
|
||||
|
||||
struct INFTLPartition {
|
||||
__u32 virtualUnits;
|
||||
__u32 firstUnit;
|
||||
__u32 lastUnit;
|
||||
__u32 flags;
|
||||
__u32 spareUnits;
|
||||
__u32 Reserved0;
|
||||
__u32 Reserved1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct INFTLMediaHeader {
|
||||
char bootRecordID[8];
|
||||
__u32 NoOfBootImageBlocks;
|
||||
__u32 NoOfBinaryPartitions;
|
||||
__u32 NoOfBDTLPartitions;
|
||||
__u32 BlockMultiplierBits;
|
||||
__u32 FormatFlags;
|
||||
__u32 OsakVersion;
|
||||
__u32 PercentUsed;
|
||||
struct INFTLPartition Partitions[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Partition flag types */
|
||||
#define INFTL_BINARY 0x20000000
|
||||
#define INFTL_BDTL 0x40000000
|
||||
#define INFTL_LAST 0x80000000
|
||||
|
||||
#endif /* __MTD_INFTL_USER_H__ */
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
|
||||
*
|
||||
* JFFS2 definitions for use in user space only
|
||||
*/
|
||||
|
||||
#ifndef __JFFS2_USER_H__
|
||||
#define __JFFS2_USER_H__
|
||||
|
||||
/* This file is blessed for inclusion by userspace */
|
||||
#include <linux/jffs2.h>
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
#undef cpu_to_je16
|
||||
#undef cpu_to_je32
|
||||
#undef cpu_to_jemode
|
||||
#undef je16_to_cpu
|
||||
#undef je32_to_cpu
|
||||
#undef jemode_to_cpu
|
||||
|
||||
extern int target_endian;
|
||||
|
||||
#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
|
||||
#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
|
||||
|
||||
#define cpu_to_je16(x) ((jint16_t){t16(x)})
|
||||
#define cpu_to_je32(x) ((jint32_t){t32(x)})
|
||||
#define cpu_to_jemode(x) ((jmode_t){t32(x)})
|
||||
|
||||
#define je16_to_cpu(x) (t16((x).v16))
|
||||
#define je32_to_cpu(x) (t32((x).v32))
|
||||
#define jemode_to_cpu(x) (t32((x).m))
|
||||
|
||||
#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
|
||||
#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
|
||||
#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
|
||||
#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
|
||||
|
||||
/* XATTR/POSIX-ACL related definition */
|
||||
/* Namespaces copied from xattr.h and posix_acl_xattr.h */
|
||||
#define XATTR_USER_PREFIX "user."
|
||||
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
|
||||
#define XATTR_SECURITY_PREFIX "security."
|
||||
#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
|
||||
#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
|
||||
#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
|
||||
#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
|
||||
#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
|
||||
#define XATTR_TRUSTED_PREFIX "trusted."
|
||||
#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
|
||||
|
||||
struct jffs2_acl_entry {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
jint32_t e_id;
|
||||
};
|
||||
|
||||
struct jffs2_acl_entry_short {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
};
|
||||
|
||||
struct jffs2_acl_header {
|
||||
jint32_t a_version;
|
||||
};
|
||||
|
||||
/* copied from include/linux/posix_acl_xattr.h */
|
||||
#define POSIX_ACL_XATTR_VERSION 0x0002
|
||||
|
||||
struct posix_acl_xattr_entry {
|
||||
uint16_t e_tag;
|
||||
uint16_t e_perm;
|
||||
uint32_t e_id;
|
||||
};
|
||||
|
||||
struct posix_acl_xattr_header {
|
||||
uint32_t a_version;
|
||||
struct posix_acl_xattr_entry a_entries[0];
|
||||
};
|
||||
|
||||
#endif /* __JFFS2_USER_H__ */
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
|
||||
*
|
||||
* Portions of MTD ABI definition which are shared by kernel and user space
|
||||
*/
|
||||
|
||||
#ifndef __MTD_ABI_H__
|
||||
#define __MTD_ABI_H__
|
||||
|
||||
#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
|
||||
separate files was to avoid #ifdef __KERNEL__ */
|
||||
#define __user
|
||||
#endif
|
||||
|
||||
struct erase_info_user {
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct mtd_oob_buf {
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
unsigned char __user *ptr;
|
||||
};
|
||||
|
||||
#define MTD_ABSENT 0
|
||||
#define MTD_NORFLASH 3
|
||||
#define MTD_NANDFLASH 4
|
||||
#define MTD_DATAFLASH 6
|
||||
#define MTD_GENERIC_TYPE 7
|
||||
|
||||
#define MTD_WRITEABLE 0x400 /* Device is writeable */
|
||||
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
|
||||
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
|
||||
|
||||
// Some common devices / combinations of capabilities
|
||||
#define MTD_CAP_ROM 0
|
||||
#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
|
||||
#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
|
||||
#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
|
||||
|
||||
|
||||
// Types of automatic ECC/Checksum available
|
||||
#define MTD_ECC_NONE 0 // No automatic ECC available
|
||||
#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip
|
||||
#define MTD_ECC_SW 2 // SW ECC for Toshiba & Samsung devices
|
||||
|
||||
/* ECC byte placement */
|
||||
#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
|
||||
#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
|
||||
#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
|
||||
#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
|
||||
#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
|
||||
|
||||
/* OTP mode selection */
|
||||
#define MTD_OTP_OFF 0
|
||||
#define MTD_OTP_FACTORY 1
|
||||
#define MTD_OTP_USER 2
|
||||
|
||||
struct mtd_info_user {
|
||||
uint8_t type;
|
||||
uint32_t flags;
|
||||
uint32_t size; // Total size of the MTD
|
||||
uint32_t erasesize;
|
||||
uint32_t writesize;
|
||||
uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
|
||||
uint32_t ecctype;
|
||||
uint32_t eccsize;
|
||||
};
|
||||
|
||||
struct region_info_user {
|
||||
uint32_t offset; /* At which this region starts,
|
||||
* from the beginning of the MTD */
|
||||
uint32_t erasesize; /* For this region */
|
||||
uint32_t numblocks; /* Number of blocks in this region */
|
||||
uint32_t regionindex;
|
||||
};
|
||||
|
||||
struct otp_info {
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
uint32_t locked;
|
||||
};
|
||||
|
||||
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
|
||||
#define MEMERASE _IOW('M', 2, struct erase_info_user)
|
||||
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
|
||||
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
|
||||
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
|
||||
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
|
||||
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
|
||||
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
|
||||
#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
|
||||
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
|
||||
#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
|
||||
#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
|
||||
#define OTPSELECT _IOR('M', 13, int)
|
||||
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
|
||||
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
|
||||
#define OTPLOCK _IOR('M', 16, struct otp_info)
|
||||
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
|
||||
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
|
||||
#define MTDFILEMODE _IO('M', 19)
|
||||
|
||||
/*
|
||||
* Obsolete legacy interface. Keep it in order not to break userspace
|
||||
* interfaces
|
||||
*/
|
||||
struct nand_oobinfo {
|
||||
uint32_t useecc;
|
||||
uint32_t eccbytes;
|
||||
uint32_t oobfree[8][2];
|
||||
uint32_t eccpos[32];
|
||||
};
|
||||
|
||||
struct nand_oobfree {
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
#define MTD_MAX_OOBFREE_ENTRIES 8
|
||||
/*
|
||||
* ECC layout control structure. Exported to userspace for
|
||||
* diagnosis and to allow creation of raw images
|
||||
*/
|
||||
struct nand_ecclayout {
|
||||
uint32_t eccbytes;
|
||||
uint32_t eccpos[64];
|
||||
uint32_t oobavail;
|
||||
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtd_ecc_stats - error correction status
|
||||
*
|
||||
* @corrected: number of corrected bits
|
||||
* @failed: number of uncorrectable errors
|
||||
* @badblocks: number of bad blocks in this partition
|
||||
* @bbtblocks: number of blocks reserved for bad block tables
|
||||
*/
|
||||
struct mtd_ecc_stats {
|
||||
uint32_t corrected;
|
||||
uint32_t failed;
|
||||
uint32_t badblocks;
|
||||
uint32_t bbtblocks;
|
||||
};
|
||||
|
||||
/*
|
||||
* Read/write file modes for access to MTD
|
||||
*/
|
||||
enum mtd_file_modes {
|
||||
MTD_MODE_NORMAL = MTD_OTP_OFF,
|
||||
MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
|
||||
MTD_MODE_OTP_USER = MTD_OTP_USER,
|
||||
MTD_MODE_RAW,
|
||||
};
|
||||
|
||||
#endif /* __MTD_ABI_H__ */
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* $Id: mtd-user.h,v 1.2 2004/05/05 14:44:57 dwmw2 Exp $
|
||||
*
|
||||
* MTD ABI header for use by user space only.
|
||||
*/
|
||||
|
||||
#ifndef __MTD_USER_H__
|
||||
#define __MTD_USER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* This file is blessed for inclusion by userspace */
|
||||
#include <mtd/mtd-abi.h>
|
||||
|
||||
typedef struct mtd_info_user mtd_info_t;
|
||||
typedef struct erase_info_user erase_info_t;
|
||||
typedef struct region_info_user region_info_t;
|
||||
typedef struct nand_oobinfo nand_oobinfo_t;
|
||||
typedef struct nand_ecclayout nand_ecclayout_t;
|
||||
|
||||
#endif /* __MTD_USER_H__ */
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
|
||||
*
|
||||
* Parts of NFTL headers shared with userspace
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MTD_NFTL_USER_H__
|
||||
#define __MTD_NFTL_USER_H__
|
||||
|
||||
/* Block Control Information */
|
||||
|
||||
struct nftl_bci {
|
||||
unsigned char ECCSig[6];
|
||||
uint8_t Status;
|
||||
uint8_t Status1;
|
||||
}__attribute__((packed));
|
||||
|
||||
/* Unit Control Information */
|
||||
|
||||
struct nftl_uci0 {
|
||||
uint16_t VirtUnitNum;
|
||||
uint16_t ReplUnitNum;
|
||||
uint16_t SpareVirtUnitNum;
|
||||
uint16_t SpareReplUnitNum;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nftl_uci1 {
|
||||
uint32_t WearInfo;
|
||||
uint16_t EraseMark;
|
||||
uint16_t EraseMark1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nftl_uci2 {
|
||||
uint16_t FoldMark;
|
||||
uint16_t FoldMark1;
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
|
||||
union nftl_uci {
|
||||
struct nftl_uci0 a;
|
||||
struct nftl_uci1 b;
|
||||
struct nftl_uci2 c;
|
||||
};
|
||||
|
||||
struct nftl_oob {
|
||||
struct nftl_bci b;
|
||||
union nftl_uci u;
|
||||
};
|
||||
|
||||
/* NFTL Media Header */
|
||||
|
||||
struct NFTLMediaHeader {
|
||||
char DataOrgID[6];
|
||||
uint16_t NumEraseUnits;
|
||||
uint16_t FirstPhysicalEUN;
|
||||
uint32_t FormattedSize;
|
||||
unsigned char UnitSizeFactor;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MAX_ERASE_ZONES (8192 - 512)
|
||||
|
||||
#define ERASE_MARK 0x3c69
|
||||
#define SECTOR_FREE 0xff
|
||||
#define SECTOR_USED 0x55
|
||||
#define SECTOR_IGNORE 0x11
|
||||
#define SECTOR_DELETED 0x00
|
||||
|
||||
#define FOLD_MARK_IN_PROGRESS 0x5555
|
||||
|
||||
#define ZONE_GOOD 0xff
|
||||
#define ZONE_BAD_ORIGINAL 0
|
||||
#define ZONE_BAD_MARKED 7
|
||||
|
||||
|
||||
#endif /* __MTD_NFTL_USER_H__ */
|
||||
+909
@@ -0,0 +1,909 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007-2009 pancake <pancake@youterm.com>
|
||||
* Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nolo.h"
|
||||
#include "image.h"
|
||||
#include "global.h"
|
||||
#include "printf-utils.h"
|
||||
|
||||
/* Request type */
|
||||
#define NOLO_WRITE 64
|
||||
#define NOLO_QUERY 192
|
||||
|
||||
/* Request */
|
||||
#define NOLO_STATUS 1
|
||||
#define NOLO_GET_NOLO_VERSION 3
|
||||
#define NOLO_IDENTIFY 4
|
||||
#define NOLO_ERROR_LOG 5
|
||||
#define NOLO_SET 16
|
||||
#define NOLO_GET 17
|
||||
#define NOLO_STRING 18
|
||||
#define NOLO_SET_STRING 19
|
||||
#define NOLO_GET_STRING 20
|
||||
#define NOLO_SEND_IMAGE 66
|
||||
#define NOLO_SET_SW_RELEASE 67
|
||||
#define NOLO_FLASH_IMAGE 80
|
||||
#define NOLO_SEND_FLASH_FINISH 82
|
||||
#define NOLO_SEND_FLASH_IMAGE 84
|
||||
#define NOLO_BOOT 130
|
||||
#define NOLO_REBOOT 131
|
||||
|
||||
/* Indexes - Flash image */
|
||||
#define NOLO_IMAGE_BOOTLOADER 1
|
||||
#define NOLO_IMAGE_KERNEL 3
|
||||
#define NOLO_IMAGE_INITFS 4
|
||||
#define NOLO_IMAGE_CMT 66
|
||||
|
||||
/* Indexes - Set & Get */
|
||||
#define NOLO_RD_MODE 0
|
||||
#define NOLO_ROOT_DEVICE 1
|
||||
#define NOLO_USB_HOST_MODE 2
|
||||
#define NOLO_ADD_RD_FLAGS 3
|
||||
#define NOLO_DEL_RD_FLAGS 4
|
||||
|
||||
/* Values - R&D flags */
|
||||
#define NOLO_RD_FLAG_NO_OMAP_WD 0x002
|
||||
#define NOLO_RD_FLAG_NO_EXT_WD 0x004
|
||||
#define NOLO_RD_FLAG_NO_LIFEGUARD 0x008
|
||||
#define NOLO_RD_FLAG_SERIAL_CONSOLE 0x010
|
||||
#define NOLO_RD_FLAG_NO_USB_TIMEOUT 0x020
|
||||
#define NOLO_RD_FLAG_STI_CONSOLE 0x040
|
||||
#define NOLO_RD_FLAG_NO_CHARGING 0x080
|
||||
#define NOLO_RD_FLAG_FORCE_POWER_KEY 0x100
|
||||
|
||||
/* Values - Boot mode */
|
||||
#define NOLO_BOOT_MODE_NORMAL 0
|
||||
#define NOLO_BOOT_MODE_UPDATE 1
|
||||
|
||||
#define NOLO_ERROR_RETURN(str, ...) do { nolo_error_log(dev, str == NULL); ERROR_RETURN(str, __VA_ARGS__); } while (0)
|
||||
|
||||
static void nolo_error_log(struct usb_device_info * dev, int only_clear) {
|
||||
|
||||
char buf[2048];
|
||||
size_t i, count;
|
||||
int ret;
|
||||
|
||||
for ( count = 0; count < 20; ++count ) {
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
ret = libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_ERROR_LOG, 0, 0, (unsigned char *)buf, sizeof(buf), 2000);
|
||||
if ( ret < 0 )
|
||||
break;
|
||||
|
||||
if ( ! only_clear ) {
|
||||
|
||||
for ( i = 0; i < sizeof(buf)-2; ++i )
|
||||
if ( buf[i] == 0 && buf[i+1] != 0 )
|
||||
buf[i] = '\n';
|
||||
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
puts(buf);
|
||||
|
||||
}
|
||||
|
||||
if ( (size_t)ret < sizeof(buf) )
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int nolo_identify_string(struct usb_device_info * dev, const char * str, char * out, size_t size) {
|
||||
|
||||
char buf[512];
|
||||
char * ptr;
|
||||
int ret;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
ret = libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_IDENTIFY, 0, 0, (unsigned char *)buf, sizeof(buf), 2000);
|
||||
if ( ret < 0 )
|
||||
NOLO_ERROR_RETURN("NOLO_IDENTIFY failed", -1);
|
||||
|
||||
if ( (size_t)ret > sizeof(buf) )
|
||||
ret = sizeof(buf);
|
||||
|
||||
ptr = MEMMEM(buf, ret, str, strlen(str));
|
||||
if ( ! ptr )
|
||||
ERROR_RETURN("Substring was not found", -1);
|
||||
|
||||
ptr += strlen(str) + 1;
|
||||
|
||||
while ( ptr-buf < ret && *ptr < 32 )
|
||||
++ptr;
|
||||
|
||||
if ( ! *ptr )
|
||||
return -1;
|
||||
|
||||
strncpy(out, ptr, size-1);
|
||||
out[size-1] = 0;
|
||||
return strlen(out);
|
||||
|
||||
}
|
||||
|
||||
static int nolo_set_string(struct usb_device_info * dev, char * str, char * arg) {
|
||||
|
||||
if ( simulate )
|
||||
return 0;
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, (unsigned char *)str, strlen(str), 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("NOLO_STRING failed", -1);
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET_STRING, 0, 0, (unsigned char *)arg, strlen(arg), 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("NOLO_SET_STRING failed", -1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int nolo_get_string(struct usb_device_info * dev, char * str, char * out, size_t size) {
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_STRING, 0, 0, (unsigned char *)str, strlen(str), 2000) < 0 )
|
||||
return -1;
|
||||
|
||||
if ( ( ret = libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET_STRING, 0, 0, (unsigned char *)out, size-1, 2000) ) < 0 )
|
||||
return -1;
|
||||
|
||||
if ( (size_t)ret > size-1 )
|
||||
ret = size-1;
|
||||
|
||||
out[size-1] = 0;
|
||||
out[ret] = 0;
|
||||
return strlen(out);
|
||||
|
||||
}
|
||||
|
||||
static int nolo_get_version_string(struct usb_device_info * dev, const char * str, char * out, size_t size) {
|
||||
|
||||
int ret;
|
||||
char buf[512];
|
||||
|
||||
if ( strlen(str) > 500 )
|
||||
return -1;
|
||||
|
||||
if ( sprintf(buf, "version:%s", str) <= 0 )
|
||||
return -1;
|
||||
|
||||
ret = nolo_get_string(dev, buf, out, size);
|
||||
if ( ret < 0 ) {
|
||||
nolo_error_log(dev, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ( ! out[0] )
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int nolo_init(struct usb_device_info * dev) {
|
||||
|
||||
uint32_t val = 1;
|
||||
enum device device;
|
||||
|
||||
printf("Initializing NOLO...\n");
|
||||
|
||||
while ( val != 0 )
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_STATUS, 0, 0, (unsigned char *)&val, 4, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("NOLO_STATUS failed", -1);
|
||||
|
||||
/* clear error log */
|
||||
nolo_error_log(dev, 1);
|
||||
|
||||
device = nolo_get_device(dev);
|
||||
|
||||
if ( ! dev->device )
|
||||
dev->device = device;
|
||||
|
||||
if ( dev->device && device && dev->device != device ) {
|
||||
ERROR("Device mishmash, expected %s, got %s", device_to_string(dev->device), device_to_string(device));
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->hwrev = nolo_get_hwrev(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum device nolo_get_device(struct usb_device_info * dev) {
|
||||
|
||||
char buf[20];
|
||||
if ( nolo_identify_string(dev, "prod_code", buf, sizeof(buf)) < 0 )
|
||||
return DEVICE_UNKNOWN;
|
||||
else if ( buf[0] )
|
||||
return device_from_string(buf);
|
||||
else
|
||||
return DEVICE_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
static int nolo_send_image(struct usb_device_info * dev, struct image * image, int flash) {
|
||||
|
||||
char buf[0x20000];
|
||||
char * ptr;
|
||||
const char * type;
|
||||
uint8_t len;
|
||||
uint16_t hash;
|
||||
uint32_t size;
|
||||
uint32_t need;
|
||||
uint32_t sent;
|
||||
int request;
|
||||
int ret;
|
||||
|
||||
if ( flash )
|
||||
printf("Send and flash image:\n");
|
||||
else
|
||||
printf("Load image:\n");
|
||||
image_print_info(image);
|
||||
|
||||
if ( image->type == IMAGE_2ND || image->type == IMAGE_MMC )
|
||||
ERROR_RETURN("Sending 2nd and mmc images are not supported", -1);
|
||||
|
||||
if ( ! flash && image->type == IMAGE_ROOTFS )
|
||||
ERROR_RETURN("Rootfs image must be sent in flash mode", -1);
|
||||
|
||||
ptr = buf;
|
||||
|
||||
/* File data header */
|
||||
memcpy(ptr, "\x2E", 1);
|
||||
ptr += 1;
|
||||
|
||||
/* Length of file data */
|
||||
memcpy(ptr, "\x19", 1);
|
||||
ptr += 1;
|
||||
|
||||
/* File data (ignored by NOLO): asic index: APE (0x01), device type: NAND (0x01), device index: 0 */
|
||||
memcpy(ptr, "\x01\x01\x00", 3);
|
||||
ptr += 3;
|
||||
|
||||
/* Hash */
|
||||
hash = htons(image->hash);
|
||||
memcpy(ptr, &hash, 2);
|
||||
ptr += 2;
|
||||
|
||||
/* Type */
|
||||
type = image_type_to_string(image->type);
|
||||
if ( ! type )
|
||||
ERROR_RETURN("Unknown image type", -1);
|
||||
memset(ptr, 0, 12);
|
||||
strncpy(ptr, type, 12);
|
||||
ptr += 12;
|
||||
|
||||
/* Size */
|
||||
size = htonl(image->size);
|
||||
memcpy(ptr, &size, 4);
|
||||
ptr += 4;
|
||||
|
||||
/* Load address (ignored by NOLO) */
|
||||
memcpy(ptr, "\x00\x00\x00\x00", 4);
|
||||
ptr += 4;
|
||||
|
||||
/* Device & hwrev */
|
||||
if ( image->devices ) {
|
||||
|
||||
int i;
|
||||
uint8_t len;
|
||||
char buf[9];
|
||||
char ** bufs = NULL;
|
||||
struct device_list * device = image->devices;
|
||||
|
||||
while ( device ) {
|
||||
if ( device->device == dev->device && hwrev_is_valid(device->hwrevs, dev->hwrev) )
|
||||
break;
|
||||
device = device->next;
|
||||
}
|
||||
|
||||
if ( device )
|
||||
bufs = device_list_alloc_to_bufs(device);
|
||||
|
||||
if ( bufs ) {
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
snprintf(buf, 8+1, "%d", dev->hwrev);
|
||||
|
||||
for ( i = 0; bufs[i]; ++i ) {
|
||||
len = ((uint8_t*)bufs[i])[0];
|
||||
if ( MEMMEM(bufs[i]+1, len, buf, strlen(buf)) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( bufs[i] ) {
|
||||
/* Device & hwrev string header */
|
||||
memcpy(ptr, "\x32", 1);
|
||||
ptr += 1;
|
||||
/* Device & hwrev string size */
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
/* Device & hwrev string */
|
||||
memcpy(ptr, bufs[i]+1, len);
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
free(bufs);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Version */
|
||||
if ( image->version ) {
|
||||
len = strnlen(image->version, 255) + 1;
|
||||
/* Version string header */
|
||||
memcpy(ptr, "\x31", 1);
|
||||
ptr += 1;
|
||||
/* Version string size */
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
/* Version string */
|
||||
memcpy(ptr, image->version, len);
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
if ( flash )
|
||||
request = NOLO_SEND_FLASH_IMAGE;
|
||||
else
|
||||
request = NOLO_SEND_IMAGE;
|
||||
|
||||
printf("Sending image header...\n");
|
||||
|
||||
if ( ! simulate ) {
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, request, 0, 0, (unsigned char *)buf, ptr-buf, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Sending image header failed", -1);
|
||||
}
|
||||
|
||||
if ( flash )
|
||||
printf("Sending and flashing image...\n");
|
||||
else
|
||||
printf("Sending image...\n");
|
||||
printf_progressbar(0, image->size);
|
||||
image_seek(image, 0);
|
||||
sent = 0;
|
||||
while ( sent < image->size ) {
|
||||
need = image->size - sent;
|
||||
if ( need > sizeof(buf) )
|
||||
need = sizeof(buf);
|
||||
ret = image_read(image, buf, need);
|
||||
if ( ret == 0 )
|
||||
break;
|
||||
if ( ! simulate ) {
|
||||
if ( usb_bulk_send(dev->udev, USB_WRITE_DATA_EP, buf, ret, 5000) != ret ) {
|
||||
PRINTF_END();
|
||||
NOLO_ERROR_RETURN("Sending image failed", -1);
|
||||
}
|
||||
}
|
||||
sent += ret;
|
||||
printf_progressbar(sent, image->size);
|
||||
}
|
||||
|
||||
if ( flash ) {
|
||||
printf("Finishing flashing...\n");
|
||||
if ( ! simulate ) {
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SEND_FLASH_FINISH, 0, 0, NULL, 0, 30000) < 0 )
|
||||
NOLO_ERROR_RETURN("Finishing failed", -1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_load_image(struct usb_device_info * dev, struct image * image) {
|
||||
|
||||
if ( image->type != IMAGE_KERNEL && image->type != IMAGE_INITFS )
|
||||
ERROR_RETURN("Only kernel or initfs image can be loaded", -1);
|
||||
|
||||
return nolo_send_image(dev, image, 0);
|
||||
|
||||
}
|
||||
|
||||
int nolo_flash_image(struct usb_device_info * dev, struct image * image) {
|
||||
|
||||
int ret;
|
||||
int flash;
|
||||
int index;
|
||||
unsigned long long int part;
|
||||
unsigned long long int total;
|
||||
unsigned long long int last_total;
|
||||
char buf[128];
|
||||
char * ptr;
|
||||
|
||||
if ( image->type == IMAGE_ROOTFS )
|
||||
flash = 1;
|
||||
else
|
||||
flash = 0;
|
||||
|
||||
ret = nolo_send_image(dev, image, flash);
|
||||
if ( ret < 0 )
|
||||
return ret;
|
||||
|
||||
if ( image->type == IMAGE_SECONDARY )
|
||||
index = NOLO_IMAGE_BOOTLOADER;
|
||||
else if ( image->type == IMAGE_KERNEL )
|
||||
index = NOLO_IMAGE_KERNEL;
|
||||
else if ( image->type == IMAGE_CMT_MCUSW )
|
||||
index = NOLO_IMAGE_CMT;
|
||||
else
|
||||
index = -1;
|
||||
|
||||
if ( image->type == IMAGE_CMT_MCUSW )
|
||||
nolo_set_string(dev, "cmt:verify", "1");
|
||||
|
||||
if ( ! flash && index >= 0 ) {
|
||||
|
||||
printf("Flashing image...\n");
|
||||
|
||||
if ( ! simulate ) {
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_FLASH_IMAGE, 0, index, NULL, 0, 10000) )
|
||||
NOLO_ERROR_RETURN("Flashing failed", -1);
|
||||
}
|
||||
|
||||
printf("Done\n");
|
||||
|
||||
}
|
||||
|
||||
if ( image->type == IMAGE_CMT_MCUSW ) {
|
||||
|
||||
int state = 0;
|
||||
last_total = 0;
|
||||
|
||||
if ( nolo_get_string(dev, "cmt:status", buf, sizeof(buf)) < 0 )
|
||||
NOLO_ERROR_RETURN("cmt:status failed", -1);
|
||||
|
||||
if ( strncmp(buf, "idle", sizeof("idle")-1) == 0 )
|
||||
state = 4;
|
||||
else
|
||||
printf("Erasing CMT...\n");
|
||||
|
||||
while ( state != 4 ) {
|
||||
|
||||
if ( nolo_get_string(dev, "cmt:status", buf, sizeof(buf)) < 0 ) {
|
||||
PRINTF_END();
|
||||
NOLO_ERROR_RETURN("cmt:status failed", -1);
|
||||
}
|
||||
|
||||
if ( strncmp(buf, "finished", sizeof("finished")-1) == 0 ) {
|
||||
|
||||
if ( state <= 0 ) {
|
||||
printf_progressbar(last_total, last_total);
|
||||
printf("Done\n");
|
||||
}
|
||||
if ( state <= 1 )
|
||||
printf("Programming CMT...\n");
|
||||
if ( state <= 2 ) {
|
||||
printf_progressbar(last_total, last_total);
|
||||
printf("Done\n");
|
||||
}
|
||||
|
||||
state = 4;
|
||||
|
||||
} else if ( strncmp(buf, "error", sizeof("error")-1) == 0 ) {
|
||||
|
||||
PRINTF_ERROR_RETURN("cmt:status error", -1);
|
||||
|
||||
} else {
|
||||
|
||||
ptr = strchr(buf, ':');
|
||||
if ( ! ptr )
|
||||
PRINTF_ERROR_RETURN("cmt:status unknown", -1);
|
||||
|
||||
*ptr = 0;
|
||||
ptr++;
|
||||
|
||||
if ( sscanf(ptr, "%llu/%llu", &part, &total) != 2 )
|
||||
PRINTF_ERROR_RETURN("cmt:status unknown", -1);
|
||||
|
||||
if ( strcmp(buf, "program") == 0 && state <= 0 ) {
|
||||
printf_progressbar(last_total, last_total);
|
||||
printf("Done\n");
|
||||
state = 1;
|
||||
}
|
||||
|
||||
if ( strcmp(buf, "program") == 0 && state <= 1 ) {
|
||||
printf("Programming CMT...\n");
|
||||
state = 2;
|
||||
}
|
||||
|
||||
printf_progressbar(part, total);
|
||||
last_total = total;
|
||||
|
||||
if ( strcmp(buf, "erase") == 0 && state <= 0 && part == total ) {
|
||||
printf("Done\n");
|
||||
state = 1;
|
||||
}
|
||||
|
||||
if ( strcmp(buf, "program") == 0 && state <= 2 && part == total ) {
|
||||
printf("Done\n");
|
||||
state = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MSLEEP(50);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_boot_device(struct usb_device_info * dev, const char * cmdline) {
|
||||
|
||||
int size = 0;
|
||||
int mode = NOLO_BOOT_MODE_NORMAL;
|
||||
|
||||
if ( cmdline && strncmp(cmdline, "update", sizeof("update")-1) == 0 && cmdline[sizeof("update")-1] <= 32 ) {
|
||||
mode = NOLO_BOOT_MODE_UPDATE;
|
||||
cmdline += sizeof("update")-1;
|
||||
if ( *cmdline ) ++cmdline;
|
||||
while ( *cmdline && *cmdline <= 32 )
|
||||
++cmdline;
|
||||
if ( *cmdline ) {
|
||||
printf("Booting kernel to update mode with cmdline: %s...\n", cmdline);
|
||||
size = strlen(cmdline);
|
||||
} else {
|
||||
printf("Booting kernel to update mode with default cmdline...\n");
|
||||
cmdline = NULL;
|
||||
}
|
||||
} else if ( cmdline && cmdline[0] ) {
|
||||
printf("Booting kernel with cmdline: '%s'...\n", cmdline);
|
||||
size = strlen(cmdline)+1;
|
||||
} else {
|
||||
printf("Booting kernel with default cmdline...\n");
|
||||
cmdline = NULL;
|
||||
}
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_BOOT, mode, 0, (unsigned char *)cmdline, size, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Booting failed", -1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_reboot_device(struct usb_device_info * dev) {
|
||||
|
||||
printf("Rebooting device...\n");
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_REBOOT, 0, 0, NULL, 0, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("NOLO_REBOOT failed", -1);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_root_device(struct usb_device_info * dev) {
|
||||
|
||||
uint8_t device = 0;
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ROOT_DEVICE, (unsigned char *)&device, 1, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot get root device", -1);
|
||||
return device;
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_root_device(struct usb_device_info * dev, int device) {
|
||||
|
||||
printf("Setting root device to %d...\n", device);
|
||||
if ( simulate )
|
||||
return 0;
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, device, NOLO_ROOT_DEVICE, NULL, 0, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot set root device", -1);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_usb_host_mode(struct usb_device_info * dev) {
|
||||
|
||||
uint32_t enabled = 0;
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_USB_HOST_MODE, (unsigned char *)&enabled, 4, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot get USB host mode status", -1);
|
||||
return enabled ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_usb_host_mode(struct usb_device_info * dev, int enable) {
|
||||
|
||||
printf("%s USB host mode...\n", enable ? "Enabling" : "Disabling");
|
||||
if ( simulate )
|
||||
return 0;
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_USB_HOST_MODE, NULL, 0, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot change USB host mode status", -1);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_rd_mode(struct usb_device_info * dev) {
|
||||
|
||||
uint8_t enabled = 0;
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_RD_MODE, (unsigned char *)&enabled, 1, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot get R&D mode status", -1);
|
||||
return enabled ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_rd_mode(struct usb_device_info * dev, int enable) {
|
||||
|
||||
printf("%s R&D mode...\n", enable ? "Enabling" : "Disabling");
|
||||
if ( simulate )
|
||||
return 0;
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, enable, NOLO_RD_MODE, NULL, 0, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot change R&D mode status", -1);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#define APPEND_STRING(ptr, buf, size, string) do { if ( (int)size > ptr-buf ) ptr += snprintf(ptr, size-(ptr-buf), "%s,", string); } while (0)
|
||||
|
||||
int nolo_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size) {
|
||||
|
||||
uint16_t add_flags = 0;
|
||||
char * ptr = flags;
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET, 0, NOLO_ADD_RD_FLAGS, (unsigned char *)&add_flags, 2, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot get R&D flags", -1);
|
||||
|
||||
if ( add_flags & NOLO_RD_FLAG_NO_OMAP_WD )
|
||||
APPEND_STRING(ptr, flags, size, "no-omap-wd");
|
||||
if ( add_flags & NOLO_RD_FLAG_NO_EXT_WD )
|
||||
APPEND_STRING(ptr, flags, size, "no-ext-wd");
|
||||
if ( add_flags & NOLO_RD_FLAG_NO_LIFEGUARD )
|
||||
APPEND_STRING(ptr, flags, size, "no-lifeguard-reset");
|
||||
if ( add_flags & NOLO_RD_FLAG_SERIAL_CONSOLE )
|
||||
APPEND_STRING(ptr, flags, size, "serial-console");
|
||||
if ( add_flags & NOLO_RD_FLAG_NO_USB_TIMEOUT )
|
||||
APPEND_STRING(ptr, flags, size, "no-usb-timeout");
|
||||
if ( add_flags & NOLO_RD_FLAG_STI_CONSOLE )
|
||||
APPEND_STRING(ptr, flags, size, "sti-console");
|
||||
if ( add_flags & NOLO_RD_FLAG_NO_CHARGING )
|
||||
APPEND_STRING(ptr, flags, size, "no-charging");
|
||||
if ( add_flags & NOLO_RD_FLAG_FORCE_POWER_KEY )
|
||||
APPEND_STRING(ptr, flags, size, "force-power-key");
|
||||
|
||||
if ( ptr != flags && *(ptr-1) == ',' )
|
||||
*(--ptr) = 0;
|
||||
|
||||
return ptr-flags;
|
||||
|
||||
}
|
||||
|
||||
#undef APPEND_STRING
|
||||
|
||||
int nolo_set_rd_flags(struct usb_device_info * dev, const char * flags) {
|
||||
|
||||
const char * ptr = flags;
|
||||
const char * endptr = ptr;
|
||||
|
||||
int add_flags = 0;
|
||||
int del_flags = 0;
|
||||
|
||||
if ( flags && flags[0] )
|
||||
printf("Setting R&D flags to: %s...\n", flags);
|
||||
else
|
||||
printf("Clearing all R&D flags...\n");
|
||||
|
||||
while ( ptr && *ptr ) {
|
||||
|
||||
while ( *ptr <= 32 )
|
||||
++ptr;
|
||||
|
||||
if ( ! *ptr )
|
||||
break;
|
||||
|
||||
endptr = strchr(ptr, ',');
|
||||
if ( endptr )
|
||||
endptr -= 1;
|
||||
else
|
||||
endptr = ptr+strlen(ptr);
|
||||
|
||||
if ( strncmp("no-omap-wd", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_NO_OMAP_WD;
|
||||
if ( strncmp("no-ext-wd", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_NO_EXT_WD;
|
||||
if ( strncmp("no-lifeguard-reset", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_NO_LIFEGUARD;
|
||||
if ( strncmp("serial-console", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_SERIAL_CONSOLE;
|
||||
if ( strncmp("no-usb-timeout", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_NO_USB_TIMEOUT;
|
||||
if ( strncmp("sti-console", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_STI_CONSOLE;
|
||||
if ( strncmp("no-charging", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_NO_CHARGING;
|
||||
if ( strncmp("force-power-key", ptr, endptr-ptr) == 0 )
|
||||
add_flags |= NOLO_RD_FLAG_FORCE_POWER_KEY;
|
||||
|
||||
if ( *(endptr+1) )
|
||||
ptr = endptr+2;
|
||||
else
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_NO_OMAP_WD ) )
|
||||
del_flags |= NOLO_RD_FLAG_NO_OMAP_WD;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_NO_EXT_WD ) )
|
||||
del_flags |= NOLO_RD_FLAG_NO_EXT_WD;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_NO_LIFEGUARD ) )
|
||||
del_flags |= NOLO_RD_FLAG_NO_LIFEGUARD;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_SERIAL_CONSOLE ) )
|
||||
del_flags |= NOLO_RD_FLAG_SERIAL_CONSOLE;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_NO_USB_TIMEOUT ) )
|
||||
del_flags |= NOLO_RD_FLAG_NO_USB_TIMEOUT;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_STI_CONSOLE ) )
|
||||
del_flags |= NOLO_RD_FLAG_STI_CONSOLE;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_NO_CHARGING ) )
|
||||
del_flags |= NOLO_RD_FLAG_NO_CHARGING;
|
||||
if ( ! ( add_flags & NOLO_RD_FLAG_FORCE_POWER_KEY ) )
|
||||
del_flags |= NOLO_RD_FLAG_FORCE_POWER_KEY;
|
||||
|
||||
if ( simulate )
|
||||
return 0;
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, add_flags, NOLO_ADD_RD_FLAGS, NULL, 0, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot add R&D flags", -1);
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET, del_flags, NOLO_DEL_RD_FLAGS, NULL, 0, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot del R&D flags", -1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int16_t nolo_get_hwrev(struct usb_device_info * dev) {
|
||||
|
||||
char buf[10];
|
||||
if ( nolo_identify_string(dev, "hw_rev", buf, sizeof(buf)) <= 0 )
|
||||
return -1;
|
||||
return atoi(buf);
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_hwrev(struct usb_device_info * dev, int16_t hwrev) {
|
||||
|
||||
char buf[9];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
snprintf(buf, sizeof(buf), "%d", hwrev);
|
||||
printf("Setting HW revision to: %s\n", buf);
|
||||
return nolo_set_string(dev, "hw_rev", buf);
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
return nolo_get_version_string(dev, "kernel", ver, size);
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_kernel_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
printf("nolo_set_kernel_ver is not implemented yet\n");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
return nolo_get_version_string(dev, "initfs", ver, size);
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_initfs_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
printf("nolo_set_initfs_ver is not implemented yet\n");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
uint32_t version = 0;
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_QUERY, NOLO_GET_NOLO_VERSION, 0, 0, (unsigned char *)&version, 4, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("Cannot get NOLO version", -1);
|
||||
|
||||
if ( (version & 255) > 1 )
|
||||
NOLO_ERROR_RETURN("Invalid NOLO version", -1);
|
||||
|
||||
return snprintf(ver, size, "%d.%d.%d", version >> 20 & 15, version >> 16 & 15, version >> 8 & 255);
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_nolo_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
printf("nolo_set_nolo_ver is not implemented yet\n");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
return nolo_get_version_string(dev, "sw-release", ver, size);
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_sw_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
char buf[512];
|
||||
char * ptr;
|
||||
uint8_t len;
|
||||
const char * str = "OSSO UART+USB";
|
||||
|
||||
printf("Setting Software release string to: %s\n", ver);
|
||||
|
||||
if ( strlen(ver) > UINT8_MAX )
|
||||
NOLO_ERROR_RETURN("Software release string is too long", -1);
|
||||
|
||||
ptr = buf;
|
||||
|
||||
memcpy(ptr, "\xe8", 1);
|
||||
ptr += 1;
|
||||
|
||||
len = strlen(str)+1;
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
|
||||
memcpy(ptr, str, len);
|
||||
ptr += len;
|
||||
|
||||
memcpy(ptr, "\x31", 1);
|
||||
ptr += 1;
|
||||
|
||||
len = strlen(ver)+1;
|
||||
memcpy(ptr, &len, 1);
|
||||
ptr += 1;
|
||||
|
||||
memcpy(ptr, ver, len);
|
||||
ptr += len;
|
||||
|
||||
if ( libusb_control_transfer(dev->udev, NOLO_WRITE, NOLO_SET_SW_RELEASE, 0, 0, (unsigned char *)buf, ptr-buf, 2000) < 0 )
|
||||
NOLO_ERROR_RETURN("NOLO_SET_SW_RELEASE failed", -1);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int nolo_get_content_ver(struct usb_device_info * dev, char * ver, size_t size) {
|
||||
|
||||
return nolo_get_version_string(dev, "content", ver, size);
|
||||
|
||||
}
|
||||
|
||||
int nolo_set_content_ver(struct usb_device_info * dev, const char * ver) {
|
||||
|
||||
printf("nolo_set_content_ver is not implemented yet\n");
|
||||
(void)dev;
|
||||
(void)ver;
|
||||
return -1;
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
* Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NOLO_H
|
||||
#define NOLO_H
|
||||
|
||||
#include "image.h"
|
||||
#include "usb-device.h"
|
||||
|
||||
int nolo_init(struct usb_device_info * dev);
|
||||
|
||||
enum device nolo_get_device(struct usb_device_info * dev);
|
||||
|
||||
int nolo_load_image(struct usb_device_info * dev, struct image * image);
|
||||
int nolo_flash_image(struct usb_device_info * dev, struct image * image);
|
||||
int nolo_boot_device(struct usb_device_info * dev, const char * cmdline);
|
||||
int nolo_reboot_device(struct usb_device_info * dev);
|
||||
|
||||
int nolo_get_root_device(struct usb_device_info * dev);
|
||||
int nolo_set_root_device(struct usb_device_info * dev, int device);
|
||||
|
||||
int nolo_get_usb_host_mode(struct usb_device_info * dev);
|
||||
int nolo_set_usb_host_mode(struct usb_device_info * dev, int enable);
|
||||
|
||||
int nolo_get_rd_mode(struct usb_device_info * dev);
|
||||
int nolo_set_rd_mode(struct usb_device_info * dev, int enable);
|
||||
|
||||
int nolo_get_rd_flags(struct usb_device_info * dev, char * flags, size_t size);
|
||||
int nolo_set_rd_flags(struct usb_device_info * dev, const char * flags);
|
||||
|
||||
int16_t nolo_get_hwrev(struct usb_device_info * dev);
|
||||
int nolo_set_hwrev(struct usb_device_info * dev, int16_t hwrev);
|
||||
|
||||
int nolo_get_kernel_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int nolo_set_kernel_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int nolo_get_initfs_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int nolo_set_initfs_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int nolo_get_nolo_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int nolo_set_nolo_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int nolo_get_sw_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int nolo_set_sw_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
int nolo_get_content_ver(struct usb_device_info * dev, char * ver, size_t size);
|
||||
int nolo_set_content_ver(struct usb_device_info * dev, const char * ver);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,679 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "device.h"
|
||||
#include "usb-device.h"
|
||||
#include "cold-flash.h"
|
||||
#include "nolo.h"
|
||||
#include "mkii.h"
|
||||
#include "disk.h"
|
||||
#include "local.h"
|
||||
|
||||
#include "operations.h"
|
||||
|
||||
struct device_info * dev_detect(void) {
|
||||
|
||||
int ret = 0;
|
||||
struct device_info * dev = NULL;
|
||||
struct usb_device_info * usb = NULL;
|
||||
|
||||
dev = calloc(1, sizeof(struct device_info));
|
||||
if ( ! dev )
|
||||
goto clean;
|
||||
|
||||
/* LOCAL */
|
||||
if ( local_init() == 0 ) {
|
||||
dev->method = METHOD_LOCAL;
|
||||
dev->detected_device = local_get_device();
|
||||
dev->detected_hwrev = local_get_hwrev();
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* USB */
|
||||
usb = usb_open_and_wait_for_device();
|
||||
if ( usb ) {
|
||||
dev->method = METHOD_USB;
|
||||
dev->usb = usb;
|
||||
|
||||
if ( dev->usb->flash_device->protocol == FLASH_NOLO )
|
||||
ret = nolo_init(dev->usb);
|
||||
else if ( dev->usb->flash_device->protocol == FLASH_COLD )
|
||||
ret = init_cold_flash(dev->usb);
|
||||
else if ( dev->usb->flash_device->protocol == FLASH_MKII )
|
||||
ret = mkii_init(dev->usb);
|
||||
else if ( dev->usb->flash_device->protocol == FLASH_DISK )
|
||||
ret = disk_init(dev->usb);
|
||||
else {
|
||||
ERROR("Unknown USB mode");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if ( ret < 0 )
|
||||
goto clean;
|
||||
|
||||
dev->detected_device = dev_get_device(dev);
|
||||
dev->detected_hwrev = dev_get_hwrev(dev);
|
||||
|
||||
if ( dev->detected_device && dev->usb->device && dev->detected_device != dev->usb->device ) {
|
||||
ERROR("Bad device, expected %s, got %s", device_to_string(dev->usb->device), device_to_string(dev->detected_device));
|
||||
goto clean;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
clean:
|
||||
if ( usb )
|
||||
usb_close_device(usb);
|
||||
free(dev);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
void dev_free(struct device_info * dev) {
|
||||
|
||||
if ( dev->usb ) {
|
||||
if ( dev->usb->flash_device->protocol == FLASH_DISK )
|
||||
disk_exit(dev->usb);
|
||||
usb_close_device(dev->usb);
|
||||
}
|
||||
free(dev);
|
||||
|
||||
}
|
||||
|
||||
enum device dev_get_device(struct device_info * dev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_device();
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_COLD )
|
||||
return DEVICE_UNKNOWN;
|
||||
else if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_device(dev->usb);
|
||||
else if ( protocol == FLASH_MKII )
|
||||
return mkii_get_device(dev->usb);
|
||||
else if ( protocol == FLASH_DISK )
|
||||
return disk_get_device(dev->usb);
|
||||
|
||||
}
|
||||
|
||||
return DEVICE_UNKNOWN;
|
||||
|
||||
}
|
||||
|
||||
int dev_load_image(struct device_info * dev, struct image * image) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL ) {
|
||||
ERROR("Loading image on local device is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_load_image(dev->usb, image);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_cold_flash_images(struct device_info * dev, struct image * x2nd, struct image * secondary) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL ) {
|
||||
ERROR("Cold Flashing on local device is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_COLD )
|
||||
return cold_flash(dev->usb, x2nd, secondary);
|
||||
|
||||
usb_switch_to_cold(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_flash_image(struct device_info * dev, struct image * image) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_flash_image(image);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO ) {
|
||||
if ( image->type != IMAGE_MMC )
|
||||
return nolo_flash_image(dev->usb, image);
|
||||
usb_switch_to_update(dev->usb);
|
||||
return -EAGAIN;
|
||||
} else if ( protocol == FLASH_MKII ) {
|
||||
if ( dev->usb->data & (1UL << image->type) )
|
||||
return mkii_flash_image(dev->usb, image);
|
||||
}
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_dump_image(struct device_info * dev, enum image_type image, const char * file) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_dump_image(image, file);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_DISK )
|
||||
return disk_dump_image(dev->usb, image, file);
|
||||
|
||||
ERROR("Dump image via USB not in Mass Storage Mode is not supported");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_check_badblocks(struct device_info * dev, const char * device) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_check_badblocks(device);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
ERROR("Check for badblocks via USB is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_boot_device(struct device_info * dev, const char * cmdline) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL ) {
|
||||
ERROR("Booting device on local device does not make sense");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_boot_device(dev->usb, cmdline);
|
||||
else if ( protocol == FLASH_MKII && cmdline && strcmp(cmdline, "update") == 0 )
|
||||
return mkii_reboot_device(dev->usb, 1);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_reboot_device(struct device_info * dev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_reboot_device();
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_COLD )
|
||||
return leave_cold_flash(dev->usb);
|
||||
else if ( protocol == FLASH_NOLO )
|
||||
return nolo_reboot_device(dev->usb);
|
||||
else if ( protocol == FLASH_MKII )
|
||||
return mkii_reboot_device(dev->usb, 0);
|
||||
else {
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_root_device(struct device_info * dev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_root_device();
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_root_device(dev->usb);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_root_device(struct device_info * dev, int device) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_root_device(device);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_root_device(dev->usb, device);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_usb_host_mode(struct device_info * dev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_usb_host_mode();
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_usb_host_mode(dev->usb);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_usb_host_mode(struct device_info * dev, int enable) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_usb_host_mode(enable);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_usb_host_mode(dev->usb, enable);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_rd_mode(struct device_info * dev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_rd_mode();
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_rd_mode(dev->usb);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_rd_mode(struct device_info * dev, int enable) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_rd_mode(enable);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_rd_mode(dev->usb, enable);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_rd_flags(struct device_info * dev, char * flags, size_t size) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_rd_flags(flags, size);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_rd_flags(dev->usb, flags, size);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_rd_flags(struct device_info * dev, const char * flags) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_rd_flags(flags);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_rd_flags(dev->usb, flags);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int16_t dev_get_hwrev(struct device_info * dev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_hwrev();
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_hwrev(dev->usb);
|
||||
else if ( protocol == FLASH_MKII )
|
||||
return mkii_get_hwrev(dev->usb);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_hwrev(struct device_info * dev, int16_t hwrev) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_hwrev(hwrev);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_hwrev(dev->usb, hwrev);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_kernel_ver(struct device_info * dev, char * ver, size_t size) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_kernel_ver(ver, size);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_kernel_ver(dev->usb, ver, size);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_kernel_ver(struct device_info * dev, const char * ver) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_kernel_ver(ver);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_kernel_ver(dev->usb, ver);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_initfs_ver(struct device_info * dev, char * ver, size_t size) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_initfs_ver(ver, size);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_initfs_ver(dev->usb, ver, size);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_initfs_ver(struct device_info * dev, const char * ver) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_initfs_ver(ver);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_initfs_ver(dev->usb, ver);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_nolo_ver(struct device_info * dev, char * ver, size_t size) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_nolo_ver(ver, size);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_nolo_ver(dev->usb, ver, size);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_nolo_ver(struct device_info * dev, const char * ver) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_nolo_ver(ver);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_nolo_ver(dev->usb, ver);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_sw_ver(struct device_info * dev, char * ver, size_t size) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_sw_ver(ver, size);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_sw_ver(dev->usb, ver, size);
|
||||
else if ( protocol == FLASH_MKII )
|
||||
return mkii_get_sw_ver(dev->usb, ver, size);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_sw_ver(struct device_info * dev, const char * ver) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_sw_ver(ver);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_sw_ver(dev->usb, ver);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_get_content_ver(struct device_info * dev, char * ver, size_t size) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_get_content_ver(ver, size);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_get_content_ver(dev->usb, ver, size);
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int dev_set_content_ver(struct device_info * dev, const char * ver) {
|
||||
|
||||
if ( dev->method == METHOD_LOCAL )
|
||||
return local_set_content_ver(ver);
|
||||
|
||||
if ( dev->method == METHOD_USB ) {
|
||||
|
||||
enum usb_flash_protocol protocol = dev->usb->flash_device->protocol;
|
||||
|
||||
if ( protocol == FLASH_NOLO )
|
||||
return nolo_set_content_ver(dev->usb, ver);
|
||||
|
||||
usb_switch_to_nolo(dev->usb);
|
||||
return -EAGAIN;
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OPERATIONS_H
|
||||
#define OPERATIONS_H
|
||||
|
||||
#include "image.h"
|
||||
#include "usb-device.h"
|
||||
|
||||
enum connection_method {
|
||||
METHOD_UNKNOWN = 0,
|
||||
METHOD_USB,
|
||||
METHOD_LOCAL,
|
||||
};
|
||||
|
||||
struct device_info {
|
||||
enum connection_method method;
|
||||
enum device detected_device;
|
||||
int16_t detected_hwrev;
|
||||
struct usb_device_info * usb;
|
||||
};
|
||||
|
||||
struct device_info * dev_detect(void);
|
||||
void dev_free(struct device_info * dev);
|
||||
|
||||
enum device dev_get_device(struct device_info * dev);
|
||||
|
||||
int dev_cold_flash_images(struct device_info * dev, struct image * x2nd, struct image * secondary);
|
||||
int dev_load_image(struct device_info * dev, struct image * image);
|
||||
int dev_flash_image(struct device_info * dev, struct image * image);
|
||||
int dev_dump_image(struct device_info * dev, enum image_type image, const char * file);
|
||||
int dev_check_badblocks(struct device_info * dev, const char * device);
|
||||
|
||||
int dev_boot_device(struct device_info * dev, const char * cmdline);
|
||||
int dev_reboot_device(struct device_info * dev);
|
||||
|
||||
int dev_get_root_device(struct device_info * dev);
|
||||
int dev_set_root_device(struct device_info * dev, int device);
|
||||
|
||||
int dev_get_usb_host_mode(struct device_info * dev);
|
||||
int dev_set_usb_host_mode(struct device_info * dev, int enable);
|
||||
|
||||
int dev_get_rd_mode(struct device_info * dev);
|
||||
int dev_set_rd_mode(struct device_info * dev, int enable);
|
||||
|
||||
int dev_get_rd_flags(struct device_info * dev, char * flags, size_t size);
|
||||
int dev_set_rd_flags(struct device_info * dev, const char * flags);
|
||||
|
||||
int16_t dev_get_hwrev(struct device_info * dev);
|
||||
int dev_set_hwrev(struct device_info * dev, int16_t hwrev);
|
||||
|
||||
int dev_get_kernel_ver(struct device_info * dev, char * ver, size_t size);
|
||||
int dev_set_kernel_ver(struct device_info * dev, const char * ver);
|
||||
|
||||
int dev_get_initfs_ver(struct device_info * dev, char * ver, size_t size);
|
||||
int dev_set_initfs_ver(struct device_info * dev, const char * ver);
|
||||
|
||||
int dev_get_nolo_ver(struct device_info * dev, char * ver, size_t size);
|
||||
int dev_set_nolo_ver(struct device_info * dev, const char * ver);
|
||||
|
||||
int dev_get_sw_ver(struct device_info * dev, char * ver, size_t size);
|
||||
int dev_set_sw_ver(struct device_info * dev, const char * ver);
|
||||
|
||||
int dev_get_content_ver(struct device_info * dev, char * ver, size_t size);
|
||||
int dev_set_content_ver(struct device_info * dev, const char * ver);
|
||||
|
||||
#endif
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int pcs_n = 0;
|
||||
struct piece_t pcs[10];
|
||||
|
||||
int add_piece(char *piece)
|
||||
{
|
||||
int i,ok = 0;
|
||||
char *file;
|
||||
|
||||
if (pcs_n==9) {
|
||||
fprintf(stderr, "Oops...cannot add more pieces. no sense operation!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
file = strchr(piece, '%');
|
||||
if (file) {
|
||||
file[0]='\0';
|
||||
file = file + 1;
|
||||
for(i=0;pieces[i];i++)
|
||||
if (!strcmp(pieces[i], piece))
|
||||
ok = 1;
|
||||
if (!ok) {
|
||||
printf("Invalid piece name.\n");
|
||||
printf("Pieces: ");
|
||||
for(i=0;pieces[i];i++)
|
||||
printf("%s ", pieces[i]);
|
||||
printf("\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pcs[pcs_n].name = strdup(file);
|
||||
pcs[pcs_n].type = strdup(piece);
|
||||
pcs[pcs_n].vers = NULL; // TODO version string not yet supported
|
||||
} else {
|
||||
/*/ autodetect piece type */
|
||||
pcs[pcs_n].type = (char *)fpid_file(piece);
|
||||
if (pcs[pcs_n].type == NULL) {
|
||||
printf("Use -p [piece]:[file]\n");
|
||||
printf("Pieces: ");
|
||||
for(i=0;pieces[i];i++)
|
||||
printf("%s ", pieces[i]);
|
||||
printf("\n");
|
||||
exit(1);
|
||||
} else {
|
||||
pcs[pcs_n].name = strdup(piece);
|
||||
pcs[pcs_n].type = strdup(pcs[pcs_n].type);
|
||||
pcs[pcs_n].vers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pcs_n++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
* Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#include "printf-utils.h"
|
||||
|
||||
int printf_prev = 0;
|
||||
|
||||
void printf_progressbar(unsigned long long part, unsigned long long total) {
|
||||
|
||||
char *columns = getenv("COLUMNS");
|
||||
int pc;
|
||||
int tmp, cols = 80;
|
||||
|
||||
/* percentage calculation */
|
||||
pc = total == 0 ? 100 : (int)(part*100/total);
|
||||
( pc < 0 ) ? pc = 0 : ( pc > 100 ) ? pc = 100 : 0;
|
||||
|
||||
PRINTF_BACK();
|
||||
PRINTF_ADD("\x1b[K %3d%% [", pc);
|
||||
if ( columns )
|
||||
cols = atoi(columns);
|
||||
if ( cols > 115 )
|
||||
cols = 115;
|
||||
cols-=15;
|
||||
for ( tmp = cols*pc/100; tmp; tmp-- ) PRINTF_ADD("#");
|
||||
for ( tmp = cols-(cols*pc/100); tmp; tmp-- ) PRINTF_ADD("-");
|
||||
PRINTF_ADD("]");
|
||||
if ( part == total ) PRINTF_END();
|
||||
fflush(stdout);
|
||||
|
||||
}
|
||||
|
||||
void printf_and_wait(const char * format, ...) {
|
||||
|
||||
va_list ap;
|
||||
char c;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(0, &rfds);
|
||||
|
||||
while ( select(1, &rfds, NULL, NULL, &tv) == 1 )
|
||||
if ( read(0, &c, 1) < 0 )
|
||||
break;
|
||||
|
||||
va_start(ap, format);
|
||||
vprintf(format, ap);
|
||||
va_end(ap);
|
||||
fflush(stdout);
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(0, &rfds);
|
||||
|
||||
while ( select(1, &rfds, NULL, NULL, NULL) == 1 ) {
|
||||
if ( read(0, &c, 1) < 0 || c == '\n' )
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
* Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PRINTF_UTILS_H
|
||||
#define PRINTF_UTILS_H
|
||||
|
||||
#include "global.h"
|
||||
|
||||
extern int printf_prev;
|
||||
|
||||
#define PRINTF_BACK() do { if ( printf_prev ) { printf("\r%-*s\r", printf_prev, ""); printf_prev = 0; } } while (0)
|
||||
#define PRINTF_ADD(...) do { printf_prev += printf(__VA_ARGS__); } while (0)
|
||||
#define PRINTF_LINE(...) do { PRINTF_BACK(); PRINTF_ADD(__VA_ARGS__); fflush(stdout); } while (0)
|
||||
#define PRINTF_END() do { if ( printf_prev ) { printf("\n"); printf_prev = 0; } } while (0)
|
||||
#define PRINTF_ERROR(...) do { PRINTF_END(); ERROR_INFO(__VA_ARGS__); } while (0)
|
||||
#define PRINTF_ERROR_RETURN(str, ...) do { PRINTF_ERROR("%s", str); return __VA_ARGS__; } while (0)
|
||||
|
||||
void printf_progressbar(unsigned long long part, unsigned long long total);
|
||||
void printf_and_wait(const char * format, ...);
|
||||
|
||||
#endif
|
||||
-339
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <usb.h>
|
||||
|
||||
/* wait for status = 0 */
|
||||
int get_status()
|
||||
{
|
||||
int ret = 0;
|
||||
if (usb_control_msg(dev, CMD_QUERY, 1, 0, 0, (char *)&ret, 4, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot get device status.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* request type: CMD_WRITE
|
||||
* request : 16
|
||||
* value : 0|1 (=> client|host)
|
||||
* index : 2
|
||||
*/
|
||||
int set_usb_mode(unsigned int mode)
|
||||
{
|
||||
if (mode > 1)
|
||||
{
|
||||
printf("Invalid USB mode specified '%d'.\n", mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usb_control_msg(dev, CMD_WRITE, 16, mode, 2, 0, 0, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot set USB mode.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Set USB mode to: '%s'.\n", (mode) ? "host" : "client");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* request type: CMD_QUERY
|
||||
* request : 17
|
||||
* index : 2
|
||||
*
|
||||
* return value: 0|1 (=> client|host)
|
||||
*/
|
||||
int get_usb_mode()
|
||||
{
|
||||
unsigned short mode = 0;
|
||||
|
||||
if (usb_control_msg(dev, CMD_QUERY, 17, 0, 2, (void *) &mode, sizeof(mode), 2000) == -1) {
|
||||
fprintf(stderr, "Cannot query device.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Device's USB mode is '%s'\n", (mode) ? "host" : "client");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Boots the Kernel with the given command-line.
|
||||
*/
|
||||
int boot_board(char *cmdline)
|
||||
{
|
||||
if (usb_control_msg(dev, CMD_WRITE, 130, 0, 0, cmdline, strlen(cmdline), 2000) == -1) {
|
||||
fprintf(stderr, "Cannot boot kernel.\n");
|
||||
perror("boot_board");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Booting kernel with arguments: '%s'.\n", cmdline);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reboots the omap mobo.
|
||||
*/
|
||||
int reboot_board()
|
||||
{
|
||||
// 131 = reboot
|
||||
if (usb_control_msg(dev, CMD_WRITE, 131, 0, 0, 0, 0, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot reboot board.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Mobo rebooted!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_rd_mode(unsigned short mode)
|
||||
{
|
||||
if (((short)mode)==-1)
|
||||
return 1;
|
||||
|
||||
if (usb_control_msg(dev, CMD_WRITE, 16, mode, 0, 0, 0, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot set R&D flags.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("rd mode changed to %s\n", mode?"on":"off");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* query root device
|
||||
*/
|
||||
int get_hw_revision()
|
||||
{
|
||||
unsigned char string[512];
|
||||
int i = 0;
|
||||
|
||||
if (usb_control_msg(dev, CMD_QUERY, 4, 0, 0, (char *)string, 512, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot query hw revision.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("HW revision string: '");
|
||||
for(i=0;i<44;i++) { // XXX ??
|
||||
if (string[i]==0) {
|
||||
printf(" ");
|
||||
} else {
|
||||
if (string[i]>19)
|
||||
printf("%c", string[i]);
|
||||
}
|
||||
}
|
||||
printf("'\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_rd_mode()
|
||||
{
|
||||
char isrd = 1;
|
||||
|
||||
if (usb_control_msg(dev, CMD_QUERY, 17, 0, 0, (char *)&isrd, 1, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot query rd mode.\n");
|
||||
return -1;
|
||||
}
|
||||
printf("RD mode is: %s\n", isrd?"on":"off");
|
||||
|
||||
return isrd;
|
||||
}
|
||||
|
||||
int get_root_device()
|
||||
{
|
||||
unsigned char opcode;
|
||||
|
||||
if (usb_control_msg(dev, CMD_QUERY, 17, 0, 1, (char *)&opcode, 1, 2000) < 0) {
|
||||
fprintf(stderr, "Cannot query root device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opcode>2) { // use sizeof || enum
|
||||
printf("Invalid root device received from the device '%d'.\n", opcode);
|
||||
}
|
||||
|
||||
printf("Root device is: %s\n", root_devices[opcode]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* request type: CMD_WRITE
|
||||
* request : 16
|
||||
* value : 0|1|2 (=> flash|mmc|usb)
|
||||
* index : 1
|
||||
*/
|
||||
int set_root_device(unsigned short root_device)
|
||||
{
|
||||
if (root_device>2) {
|
||||
printf("Invalid root device specified '%d'.\n", root_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usb_control_msg(dev, CMD_WRITE, 16, root_device, 1, 0, 0, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot set root device\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Root device set to: %s\n", root_devices[root_device]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flags:
|
||||
* request type: CMD_WRITE
|
||||
* request : 16
|
||||
* value : flags to set, see below
|
||||
* index : 3
|
||||
*
|
||||
* Clear flags:
|
||||
* request type: CMD_WRITE
|
||||
* request : 16
|
||||
* value : flags to clear, see below
|
||||
* index : 4
|
||||
|
||||
* Flags are composed of:
|
||||
* 0x02 - disable OMAP watchdog (possibly)
|
||||
* 0x04 - disable RETU watchdog (possibly)
|
||||
* 0x08 - disable lifeguard reset
|
||||
* 0x10 - enable serial console
|
||||
* 0x20 - disable USB timeout
|
||||
*
|
||||
* The function encapsule the NOLO API in a way that it works like
|
||||
* a chmod 707. The bits that are not set will be cleared after the
|
||||
* call. This is done by issuing a 'clear flags' command with all the
|
||||
* non set bits.
|
||||
*
|
||||
*/
|
||||
int set_rd_flags(unsigned short flags)
|
||||
{
|
||||
unsigned short reverse_flags = 0;
|
||||
|
||||
if (flags & ~(0x02 | 0x04 | 0x08 | 0x10 | 0x20)) {
|
||||
printf("Invalid rd flags specified '%x'.\n", flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(flags & 0x02))
|
||||
reverse_flags |= 0x02;
|
||||
|
||||
if (!(flags & 0x04))
|
||||
reverse_flags |= 0x04;
|
||||
|
||||
if (!(flags & 0x08))
|
||||
reverse_flags |= 0x08;
|
||||
|
||||
if (!(flags & 0x10))
|
||||
reverse_flags |= 0x10;
|
||||
|
||||
if (!(flags & 0x20))
|
||||
reverse_flags |= 0x20;
|
||||
|
||||
if (usb_control_msg(dev, CMD_WRITE, 16, flags, 3, 0, 0, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot set rd flags\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usb_control_msg(dev, CMD_WRITE, 16, reverse_flags, 4, 0, 0, 2000) == -1) {
|
||||
fprintf(stderr, "Cannot set rd flags\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Set rd flags successfully!\n");
|
||||
printf("disable OMAP watchdog : %s\n", (flags & 0x02) ? "set" : "not set");
|
||||
printf("disable RETU watchdog : %s\n", (flags & 0x04) ? "set" : "not set");
|
||||
printf("disable lifeguard reset: %s\n", (flags & 0x08) ? "set" : "not set");
|
||||
printf("enable serial console : %s\n", (flags & 0x10) ? "set" : "not set");
|
||||
printf("disable USB timeout : %s\n", (flags & 0x20) ? "set" : "not set");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_rd_flags()
|
||||
{
|
||||
unsigned short flags = 0;
|
||||
|
||||
if (usb_control_msg(dev, CMD_QUERY, 17, 0, 3, (void *) &flags, sizeof(flags), 2000) == -1) {
|
||||
fprintf(stderr, "Cannot get rd flags\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Current rd flag setting:\n");
|
||||
printf("disable OMAP watchdog : %s\n", (flags & 0x02) ? "set" : "not set");
|
||||
printf("disable RETU watchdog : %s\n", (flags & 0x04) ? "set" : "not set");
|
||||
printf("disable lifeguard reset: %s\n", (flags & 0x08) ? "set" : "not set");
|
||||
printf("enable serial console : %s\n", (flags & 0x10) ? "set" : "not set");
|
||||
printf("disable USB timeout : %s\n", (flags & 0x20) ? "set" : "not set");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_nolo_version()
|
||||
{
|
||||
unsigned int version; // ensure uint is at least 32 bits
|
||||
|
||||
//if (usb_control_msg(dev, CMD_QUERY, 3, 0, 1, (char *)&version, 4 , 2000) < 0) {
|
||||
if (usb_control_msg(dev, CMD_QUERY, 3, 0, 0, (char *)&version, 4 , 2000) < 0) {
|
||||
fprintf(stderr, "Cannot query nolo version. Old bootloader version?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("NOLO Version %d.%d.%d\n",
|
||||
version >> 20 & 15,
|
||||
version >> 16 & 15,
|
||||
version >> 8 & 255);
|
||||
|
||||
if ((version & 255)> 1)
|
||||
printf("Invalid API version (%d)\n", version&255);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_sw_version()
|
||||
{
|
||||
int ret;
|
||||
char bytes[1024];
|
||||
|
||||
strcpy(bytes, "version:sw-release");
|
||||
ret = usb_control_msg(dev, CMD_WRITE, 18, 0, 0, (char *)&bytes, 18, 2000);
|
||||
if (ret<0) {
|
||||
fprintf(stderr, "error: cannot write query 18\n");
|
||||
return 0;
|
||||
}
|
||||
ret = usb_control_msg(dev, CMD_QUERY, 20, 0, 0, (char *)&bytes, 512, 2000);
|
||||
if (ret<0) {
|
||||
fprintf(stderr, "error: b0rken swversion read!\n");
|
||||
return 0;
|
||||
}
|
||||
printf("SWVERSION GOT: %s\n", bytes); //???+strlen(bytes)+1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
#ifndef QUERY_H_
|
||||
#define QUERY_H_
|
||||
|
||||
int boot_board(char *cmdline);
|
||||
|
||||
int reboot_board();
|
||||
|
||||
int get_status();
|
||||
|
||||
int get_usb_mode();
|
||||
int set_usb_mode(unsigned int);
|
||||
|
||||
int get_rd_mode();
|
||||
int set_rd_mode(unsigned short mode);
|
||||
|
||||
int get_rd_flags();
|
||||
int set_rd_flags(unsigned short flags);
|
||||
|
||||
int get_hw_revision();
|
||||
|
||||
int get_root_device();
|
||||
int set_root_device(unsigned short);
|
||||
|
||||
int get_nolo_version();
|
||||
|
||||
int get_sw_version();
|
||||
|
||||
#endif /*QUERY_H_*/
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
||||
int open_serial(const char *file)
|
||||
{
|
||||
struct termios tc;
|
||||
int fd = open (file, O_RDWR | O_SYNC);
|
||||
if (fd < 0) {
|
||||
perror (file);
|
||||
return -1;
|
||||
}
|
||||
// 115200 baud, 8n1, no flow control
|
||||
tcgetattr(fd, &tc);
|
||||
tc.c_iflag = IGNPAR;
|
||||
tc.c_oflag = 0;
|
||||
tc.c_cflag = CS8 | CREAD | CLOCAL;
|
||||
tc.c_lflag = 0;
|
||||
cfsetispeed(&tc, B115200);
|
||||
cfsetospeed(&tc, B115200);
|
||||
tcsetattr(fd, TCSANOW, &tc);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int console(const char *device)
|
||||
{
|
||||
char str[513];
|
||||
int fd = open_serial(device);
|
||||
int pid;
|
||||
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Cannot open serial device %s\n", device);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid) {
|
||||
while(1) {
|
||||
fgets(str, 512, stdin);
|
||||
if (write(fd, str, strlen(str)-1) == -1) {
|
||||
perror("write");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char buf;
|
||||
while(1) {
|
||||
if (read(fd, &buf,1) == -1) {
|
||||
perror("read");
|
||||
exit (1);
|
||||
}
|
||||
write(1, &buf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "device.h"
|
||||
#include "usb-device.h"
|
||||
#include "printf-utils.h"
|
||||
#include "nolo.h"
|
||||
#include "cold-flash.h"
|
||||
#include "mkii.h"
|
||||
|
||||
#define USB_ERROR(str, err) do { PRINTF_END(); ERROR("%s: %s", str, libusb_strerror(err)); } while (0)
|
||||
|
||||
static libusb_context * usb_ctx;
|
||||
|
||||
static struct usb_flash_device usb_devices[] = {
|
||||
/* vend prod i a protocol devices */
|
||||
{ 0x0421, 0x0096, -1, -1, FLASH_DISK, { DEVICE_RX_44, 0 } },
|
||||
{ 0x0421, 0x0105, 2, 1, FLASH_NOLO, { DEVICE_SU_18, DEVICE_RX_34, DEVICE_RX_44, DEVICE_RX_48, DEVICE_RX_51, DEVICE_RM_680, DEVICE_RM_696, 0 } },
|
||||
{ 0x0421, 0x0106, 0, 0, FLASH_COLD, { DEVICE_RX_51, DEVICE_RM_680, DEVICE_RM_696, 0 } },
|
||||
{ 0x0421, 0x0189, -1, -1, FLASH_DISK, { DEVICE_RX_48, 0 } },
|
||||
{ 0x0421, 0x01c7, -1, -1, FLASH_DISK, { DEVICE_RX_51, 0 } },
|
||||
{ 0x0421, 0x01c8, 1, 1, FLASH_MKII, { DEVICE_RX_51, DEVICE_RM_680, 0 } },
|
||||
{ 0x0421, 0x01c8, 1, 0, FLASH_UNKN, { DEVICE_RX_51, 0 } }, /* U-Boot mode (TTY via USB) */
|
||||
{ 0x0421, 0x03d1, -1, -1, FLASH_DISK, { DEVICE_RM_680, 0 } },
|
||||
{ 0x0421, 0x03d2, 1, 1, FLASH_MKII, { DEVICE_RM_680, 0 } },
|
||||
{ 0x0421, 0x0431, -1, -1, FLASH_DISK, { DEVICE_SU_18, DEVICE_RX_34, 0 } },
|
||||
{ 0x0421, 0x04c3, -1, -1, FLASH_DISK, { DEVICE_RX_34, 0 } },
|
||||
{ 0x0421, 0x0518, -1, -1, FLASH_DISK, { DEVICE_RM_696, 0 } },
|
||||
{ 0x0421, 0x0519, -1, -1, FLASH_UNKN, { DEVICE_RM_696, 0 } }, /* RNDIS/Ethernet mode */
|
||||
{ 0x0421, 0x051a, 2, 1, FLASH_UNKN, { DEVICE_RM_696, 0 } }, /* Sync mode (ADL protocol) */
|
||||
};
|
||||
|
||||
static const char * usb_flash_protocols[] = {
|
||||
[FLASH_NOLO] = "NOLO",
|
||||
[FLASH_COLD] = "Cold flashing",
|
||||
[FLASH_MKII] = "Mk II protocol",
|
||||
[FLASH_DISK] = "RAW disk",
|
||||
};
|
||||
|
||||
const char * usb_flash_protocol_to_string(enum usb_flash_protocol protocol) {
|
||||
|
||||
if ( protocol >= sizeof(usb_flash_protocols)/sizeof(usb_flash_protocols[0]) )
|
||||
return NULL;
|
||||
|
||||
return usb_flash_protocols[protocol];
|
||||
|
||||
}
|
||||
|
||||
static void usb_flash_device_info_print(const struct usb_flash_device * dev) {
|
||||
|
||||
int i;
|
||||
|
||||
PRINTF_ADD("USB device: %s", device_to_string(dev->devices[0]));
|
||||
|
||||
for ( i = 1; dev->devices[i]; ++i )
|
||||
PRINTF_ADD("/%s", device_to_string(dev->devices[i]));
|
||||
|
||||
PRINTF_ADD(" (%#04x:%#04x) in %s mode", dev->vendor, dev->product, usb_flash_protocol_to_string(dev->protocol));
|
||||
|
||||
}
|
||||
|
||||
static void usb_reattach_kernel_driver(libusb_device_handle * udev, int interface, int detached) {
|
||||
|
||||
if ( interface < 0 )
|
||||
return;
|
||||
|
||||
libusb_release_interface(udev, interface);
|
||||
|
||||
/* Reattach only driver detached by us, on macOS reattaching re-enumerates (resets) device */
|
||||
if ( detached )
|
||||
libusb_attach_kernel_driver(udev, interface);
|
||||
|
||||
}
|
||||
|
||||
static void usb_descriptor_info_print(libusb_device_handle * udev, const struct libusb_device_descriptor * desc, char * product, size_t size) {
|
||||
|
||||
char buf[1024];
|
||||
char buf2[1024];
|
||||
unsigned int x;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
libusb_get_string_descriptor_ascii(udev, desc->iProduct, (unsigned char *)buf, sizeof(buf));
|
||||
PRINTF_LINE("USB device product string: %s", buf[0] ? buf : "(not detected)");
|
||||
PRINTF_END();
|
||||
|
||||
if ( product && buf[0] )
|
||||
strncpy(product, buf, size);
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memset(buf2, 0, sizeof(buf2));
|
||||
ret = libusb_get_string_descriptor_ascii(udev, desc->iSerialNumber, (unsigned char *)buf, sizeof(buf));
|
||||
if ( ! isalnum(buf[0]) )
|
||||
buf[0] = 0;
|
||||
for ( i = 0; i < ret; i+=2 ) {
|
||||
sscanf(buf+i, "%2x", &x);
|
||||
if ( x > 31 && x < 127 )
|
||||
buf2[i/2] = x;
|
||||
else {
|
||||
buf2[0] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! isalnum(buf2[0]) )
|
||||
buf2[0] = 0;
|
||||
PRINTF_LINE("USB device serial number string: %s", buf2[0] ? buf2 : ( buf[0] ? buf : "(not detected)" ));
|
||||
PRINTF_END();
|
||||
|
||||
}
|
||||
|
||||
static int usb_device_has_interface(libusb_device * dev, int interface, int alternate) {
|
||||
|
||||
struct libusb_config_descriptor * config;
|
||||
int ret = 1;
|
||||
|
||||
if ( interface == -1 )
|
||||
return 1;
|
||||
|
||||
if ( libusb_get_config_descriptor(dev, 0, &config) < 0 )
|
||||
return 0;
|
||||
|
||||
if ( interface >= config->bNumInterfaces )
|
||||
ret = 0;
|
||||
else if ( alternate != -1 && alternate >= config->interface[interface].num_altsetting )
|
||||
ret = 0;
|
||||
|
||||
libusb_free_config_descriptor(config);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static struct usb_device_info * usb_device_is_valid(libusb_device * dev) {
|
||||
|
||||
size_t i;
|
||||
int err;
|
||||
int detached = 0;
|
||||
char product[1024];
|
||||
struct libusb_device_descriptor desc;
|
||||
struct usb_device_info * ret = NULL;
|
||||
|
||||
if ( libusb_get_device_descriptor(dev, &desc) < 0 )
|
||||
return NULL;
|
||||
|
||||
for ( i = 0; i < sizeof(usb_devices)/sizeof(usb_devices[0]); ++i ) {
|
||||
|
||||
if ( desc.idVendor == usb_devices[i].vendor && desc.idProduct == usb_devices[i].product ) {
|
||||
|
||||
if ( usb_devices[i].protocol == FLASH_UNKN )
|
||||
continue;
|
||||
|
||||
if ( desc.bNumConfigurations < 1 )
|
||||
continue;
|
||||
|
||||
if ( ! usb_device_has_interface(dev, usb_devices[i].interface, usb_devices[i].alternate) )
|
||||
continue;
|
||||
|
||||
printf("\b\b ");
|
||||
PRINTF_END();
|
||||
PRINTF_ADD("Found ");
|
||||
usb_flash_device_info_print(&usb_devices[i]);
|
||||
PRINTF_END();
|
||||
|
||||
PRINTF_LINE("Opening USB...");
|
||||
libusb_device_handle * udev;
|
||||
err = libusb_open(dev, &udev);
|
||||
if ( err < 0 ) {
|
||||
USB_ERROR("libusb_open failed", err);
|
||||
fprintf(stderr, "\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(product, 0, sizeof(product));
|
||||
usb_descriptor_info_print(udev, &desc, product, sizeof(product));
|
||||
|
||||
if ( usb_devices[i].interface >= 0 ) {
|
||||
|
||||
if ( libusb_kernel_driver_active(udev, usb_devices[i].interface) == 1 ) {
|
||||
PRINTF_LINE("Detaching kernel from USB interface...");
|
||||
err = libusb_detach_kernel_driver(udev, usb_devices[i].interface);
|
||||
if ( err == 0 )
|
||||
detached = 1;
|
||||
else {
|
||||
PRINTF_END();
|
||||
WARNING("Cannot detach kernel driver: %s", libusb_strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF_LINE("Claiming USB interface...");
|
||||
err = libusb_claim_interface(udev, usb_devices[i].interface);
|
||||
if ( err < 0 ) {
|
||||
USB_ERROR("libusb_claim_interface failed", err);
|
||||
fprintf(stderr, "\n");
|
||||
usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached);
|
||||
libusb_close(udev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( usb_devices[i].alternate >= 0 ) {
|
||||
PRINTF_LINE("Setting alternate USB interface...");
|
||||
err = libusb_set_interface_alt_setting(udev, usb_devices[i].interface, usb_devices[i].alternate);
|
||||
if ( err < 0 ) {
|
||||
USB_ERROR("libusb_set_interface_alt_setting failed", err);
|
||||
fprintf(stderr, "\n");
|
||||
usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached);
|
||||
libusb_close(udev);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = calloc(1, sizeof(struct usb_device_info));
|
||||
if ( ! ret ) {
|
||||
ALLOC_ERROR();
|
||||
usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached);
|
||||
libusb_close(udev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( strcmp(product, "Nokia 770") == 0 || strcmp(product, "Nokia 770 (Update mode)") == 0 )
|
||||
ret->device = DEVICE_SU_18;
|
||||
else if ( strcmp(product, "Nokia N800 Internet Tablet") == 0 || strcmp(product, "Nokia N800 (Update mode)") == 0 )
|
||||
ret->device = DEVICE_RX_34;
|
||||
else if ( strcmp(product, "Nokia N810 Internet Tablet") == 0 || strcmp(product, "Nokia N810 (Update mode)") == 0 )
|
||||
ret->device = DEVICE_RX_44;
|
||||
else if ( strcmp(product, "Nokia N810 Internet Tablet WiMAX Edition") == 0 || strcmp(product, "Nokia-RX48 (Update mode)") == 0 )
|
||||
ret->device = DEVICE_RX_48;
|
||||
else if ( strcmp(product, "N900 (Storage Mode)") == 0 || strcmp(product, "Nokia N900 (Update mode)") == 0 || strcmp(product, "N900 (PC-Suite Mode)") == 0 || strcmp(product, "N900 (U-Boot)") == 0 )
|
||||
ret->device = DEVICE_RX_51;
|
||||
else if ( strcmp(product, "Nokia N950") == 0 || strcmp(product, "N950 (Update mode)") == 0 )
|
||||
ret->device = DEVICE_RM_680;
|
||||
else if ( strcmp(product, "Nokia N9") == 0 || strcmp(product, "N9 (Update mode)") == 0 || strcmp(product, "Nokia N9 RNDIS/Ethernet") == 0 )
|
||||
ret->device = DEVICE_RM_696;
|
||||
else if ( strcmp(product, "Nokia USB ROM") == 0 || strcmp(product, "Sync Mode") == 0 || strcmp(product, "Nxy (Update mode)") == 0 )
|
||||
ret->device = DEVICE_ANY;
|
||||
else
|
||||
ret->device = DEVICE_UNKNOWN;
|
||||
|
||||
if ( device_to_string(ret->device) )
|
||||
PRINTF_LINE("Detected USB device: %s", device_to_string(ret->device));
|
||||
else
|
||||
PRINTF_LINE("Detected USB device: (not detected)");
|
||||
PRINTF_END();
|
||||
|
||||
if ( ! noverify && ret->device == DEVICE_UNKNOWN ) {
|
||||
ERROR("Device detection failed");
|
||||
fprintf(stderr, "\n");
|
||||
usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached);
|
||||
libusb_close(udev);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( ! noverify && ret->device != DEVICE_ANY ) {
|
||||
enum device * device;
|
||||
for ( device = usb_devices[i].devices; *device; ++device )
|
||||
if ( *device == ret->device )
|
||||
break;
|
||||
if ( ! *device ) {
|
||||
ERROR("Device mishmash");
|
||||
fprintf(stderr, "\n");
|
||||
usb_reattach_kernel_driver(udev, usb_devices[i].interface, detached);
|
||||
libusb_close(udev);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ret->hwrev = -1;
|
||||
ret->flash_device = &usb_devices[i];
|
||||
ret->udev = udev;
|
||||
ret->detached = detached;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static volatile sig_atomic_t signal_quit;
|
||||
|
||||
static void signal_handler(int signum) {
|
||||
|
||||
signal_quit = 1;
|
||||
(void)signum;
|
||||
|
||||
}
|
||||
|
||||
static void usb_exit(void) {
|
||||
|
||||
libusb_exit(usb_ctx);
|
||||
usb_ctx = NULL;
|
||||
|
||||
}
|
||||
|
||||
struct usb_device_info * usb_open_and_wait_for_device(void) {
|
||||
|
||||
libusb_device ** devs;
|
||||
ssize_t count;
|
||||
ssize_t j;
|
||||
struct usb_device_info * ret = NULL;
|
||||
int i = 0;
|
||||
int err;
|
||||
void (*prev)(int);
|
||||
static char progress[] = {'/','-','\\', '|'};
|
||||
|
||||
/* Context is kept until exit, so device list stays up to date between waits */
|
||||
if ( ! usb_ctx ) {
|
||||
err = libusb_init(&usb_ctx);
|
||||
if ( err < 0 ) {
|
||||
USB_ERROR("libusb_init failed", err);
|
||||
return NULL;
|
||||
}
|
||||
atexit(usb_exit);
|
||||
}
|
||||
|
||||
PRINTF_BACK();
|
||||
printf("\n");
|
||||
|
||||
signal_quit = 0;
|
||||
|
||||
prev = signal(SIGINT, signal_handler);
|
||||
|
||||
while ( ! signal_quit ) {
|
||||
|
||||
PRINTF_LINE("Waiting for USB device... %c", progress[++i%sizeof(progress)]);
|
||||
|
||||
count = libusb_get_device_list(usb_ctx, &devs);
|
||||
if ( count < 0 ) {
|
||||
USB_ERROR("libusb_get_device_list failed", (int)count);
|
||||
break;
|
||||
}
|
||||
|
||||
for ( j = 0; j < count; ++j ) {
|
||||
ret = usb_device_is_valid(devs[j]);
|
||||
if ( ret )
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opened device handle holds its own reference */
|
||||
libusb_free_device_list(devs, 1);
|
||||
|
||||
if ( ret )
|
||||
break;
|
||||
|
||||
MSLEEP(50);
|
||||
|
||||
}
|
||||
|
||||
if ( prev != SIG_ERR )
|
||||
signal(SIGINT, prev);
|
||||
|
||||
PRINTF_BACK();
|
||||
printf("\n");
|
||||
|
||||
if ( ! ret )
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void usb_close_device(struct usb_device_info * dev) {
|
||||
|
||||
if ( dev->flash_device->protocol != FLASH_COLD )
|
||||
usb_reattach_kernel_driver(dev->udev, dev->flash_device->interface, dev->detached);
|
||||
libusb_close(dev->udev);
|
||||
free(dev);
|
||||
|
||||
}
|
||||
|
||||
/* Translate libusb error, so error messages which print errno stay meaningful */
|
||||
static int usb_error_to_errno(int err) {
|
||||
|
||||
switch ( err ) {
|
||||
case LIBUSB_ERROR_INVALID_PARAM: return EINVAL;
|
||||
case LIBUSB_ERROR_ACCESS: return EACCES;
|
||||
case LIBUSB_ERROR_NO_DEVICE: return ENODEV;
|
||||
case LIBUSB_ERROR_NOT_FOUND: return ENOENT;
|
||||
case LIBUSB_ERROR_BUSY: return EBUSY;
|
||||
case LIBUSB_ERROR_TIMEOUT: return ETIMEDOUT;
|
||||
case LIBUSB_ERROR_OVERFLOW: return EOVERFLOW;
|
||||
case LIBUSB_ERROR_PIPE: return EPIPE;
|
||||
case LIBUSB_ERROR_INTERRUPTED: return EINTR;
|
||||
case LIBUSB_ERROR_NO_MEM: return ENOMEM;
|
||||
case LIBUSB_ERROR_NOT_SUPPORTED: return ENOTSUP;
|
||||
default: return EIO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Returns number of transferred bytes or negative libusb error code */
|
||||
static int usb_bulk_transfer(libusb_device_handle * udev, unsigned char endpoint, unsigned char * data, int size, unsigned int timeout) {
|
||||
|
||||
int transferred = 0;
|
||||
int ret;
|
||||
|
||||
ret = libusb_bulk_transfer(udev, endpoint, data, size, &transferred, timeout);
|
||||
if ( ret == 0 )
|
||||
return transferred;
|
||||
|
||||
errno = usb_error_to_errno(ret);
|
||||
|
||||
/* Timed out transfer which moved some data is reported as short transfer, callers check its size */
|
||||
if ( ret == LIBUSB_ERROR_TIMEOUT && transferred > 0 )
|
||||
return transferred;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int usb_bulk_send(libusb_device_handle * udev, unsigned char endpoint, const void * data, int size, unsigned int timeout) {
|
||||
|
||||
/* libusb does not modify buffer of OUT transfer */
|
||||
return usb_bulk_transfer(udev, endpoint, (unsigned char *)data, size, timeout);
|
||||
|
||||
}
|
||||
|
||||
int usb_bulk_recv(libusb_device_handle * udev, unsigned char endpoint, void * data, int size, unsigned int timeout) {
|
||||
|
||||
return usb_bulk_transfer(udev, endpoint, data, size, timeout);
|
||||
|
||||
}
|
||||
|
||||
void usb_switch_to_nolo(struct usb_device_info * dev) {
|
||||
|
||||
printf("\nSwitching to NOLO mode...\n");
|
||||
|
||||
if ( dev->flash_device->protocol == FLASH_COLD )
|
||||
leave_cold_flash(dev);
|
||||
else if ( dev->flash_device->protocol == FLASH_MKII )
|
||||
mkii_reboot_device(dev, 0);
|
||||
else if ( dev->flash_device->protocol == FLASH_DISK )
|
||||
printf_and_wait("Unplug USB cable, turn device off, press ENTER and plug USB cable again");
|
||||
|
||||
}
|
||||
|
||||
void usb_switch_to_cold(struct usb_device_info * dev) {
|
||||
|
||||
printf("\nSwitching to Cold Flash mode...\n");
|
||||
|
||||
if ( dev->flash_device->protocol == FLASH_NOLO )
|
||||
nolo_reboot_device(dev);
|
||||
else if ( dev->flash_device->protocol == FLASH_MKII )
|
||||
mkii_reboot_device(dev, 0);
|
||||
else if ( dev->flash_device->protocol == FLASH_DISK )
|
||||
printf_and_wait("Unplug USB cable, turn device off, press ENTER and plug USB cable again");
|
||||
|
||||
}
|
||||
|
||||
void usb_switch_to_update(struct usb_device_info * dev) {
|
||||
|
||||
printf("\nSwitching to Update mode...\n");
|
||||
|
||||
if ( dev->flash_device->protocol == FLASH_COLD )
|
||||
leave_cold_flash(dev);
|
||||
else if ( dev->flash_device->protocol == FLASH_NOLO )
|
||||
nolo_boot_device(dev, "update");
|
||||
else if ( dev->flash_device->protocol == FLASH_MKII && ! ( dev->data & MKII_UPDATE_MODE ) )
|
||||
mkii_reboot_device(dev, 1);
|
||||
else if ( dev->flash_device->protocol == FLASH_DISK )
|
||||
printf_and_wait("Unplug USB cable, turn device off, press ENTER and plug USB cable again");
|
||||
|
||||
}
|
||||
|
||||
void usb_switch_to_disk(struct usb_device_info * dev) {
|
||||
|
||||
printf("\nSwitching to RAW disk mode...\n");
|
||||
|
||||
if ( dev->flash_device->protocol == FLASH_COLD )
|
||||
leave_cold_flash(dev);
|
||||
else if ( dev->flash_device->protocol == FLASH_NOLO ) {
|
||||
nolo_boot_device(dev, NULL);
|
||||
printf_and_wait("Wait until device start, choose USB Mass Storage Mode and press ENTER");
|
||||
} else if ( dev->flash_device->protocol == FLASH_MKII ) {
|
||||
if ( dev->data & MKII_UPDATE_MODE )
|
||||
mkii_reboot_device(dev, 0);
|
||||
else
|
||||
printf_and_wait("Unplug USB cable, plug again, choose USB Mass Storage Mode and press ENTER");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.com>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef USB_DEVICE_H
|
||||
#define USB_DEVICE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#define USB_READ_EP (LIBUSB_ENDPOINT_IN | 0x1)
|
||||
#define USB_WRITE_EP (LIBUSB_ENDPOINT_OUT | 0x1)
|
||||
#define USB_WRITE_DATA_EP (LIBUSB_ENDPOINT_OUT | 0x2)
|
||||
|
||||
#include "device.h"
|
||||
|
||||
enum usb_flash_protocol {
|
||||
FLASH_UNKN = 0,
|
||||
FLASH_NOLO,
|
||||
FLASH_COLD,
|
||||
FLASH_MKII,
|
||||
FLASH_DISK,
|
||||
FLASH_COUNT,
|
||||
};
|
||||
|
||||
struct usb_flash_device {
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
int interface;
|
||||
int alternate;
|
||||
enum usb_flash_protocol protocol;
|
||||
enum device devices[DEVICE_COUNT];
|
||||
};
|
||||
|
||||
struct usb_device_info {
|
||||
enum device device;
|
||||
int16_t hwrev;
|
||||
const struct usb_flash_device * flash_device;
|
||||
libusb_device_handle * udev;
|
||||
int detached;
|
||||
int data;
|
||||
};
|
||||
|
||||
const char * usb_flash_protocol_to_string(enum usb_flash_protocol protocol);
|
||||
struct usb_device_info * usb_open_and_wait_for_device(void);
|
||||
void usb_close_device(struct usb_device_info * dev);
|
||||
|
||||
int usb_bulk_send(libusb_device_handle * udev, unsigned char endpoint, const void * data, int size, unsigned int timeout);
|
||||
int usb_bulk_recv(libusb_device_handle * udev, unsigned char endpoint, void * data, int size, unsigned int timeout);
|
||||
|
||||
void usb_switch_to_nolo(struct usb_device_info * dev);
|
||||
void usb_switch_to_cold(struct usb_device_info * dev);
|
||||
void usb_switch_to_update(struct usb_device_info * dev);
|
||||
void usb_switch_to_disk(struct usb_device_info * dev);
|
||||
|
||||
#endif
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 0xFFFF - Open Free Fiasco Firmware Flasher
|
||||
* Copyright (C) 2007 pancake <pancake@youterm.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <usb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned long get_file_size(char *file)
|
||||
{
|
||||
FILE *fd = fopen(file, "r");
|
||||
unsigned long len = 0;
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr, "Cannot open file '%s'\n", file);
|
||||
exit(1);
|
||||
}
|
||||
fseek(fd, 0, SEEK_END);
|
||||
len = ftell(fd);
|
||||
fclose(fd);
|
||||
return len;
|
||||
}
|
||||
|
||||
void progressbar(unsigned long long part, unsigned long long total)
|
||||
{
|
||||
char *columns = getenv("COLUMNS");
|
||||
int pc;
|
||||
int tmp, cols = 80;
|
||||
|
||||
pc = (int)(part*100/total);
|
||||
(pc<0)?pc=0:(pc>100)?pc=100:0;
|
||||
printf("\e[K %3d%% [", pc);
|
||||
if (columns)
|
||||
cols = atoi(columns);
|
||||
cols-=15;
|
||||
for(tmp=cols*pc/100;tmp;tmp--) printf("#");
|
||||
for(tmp=cols-(cols*pc/100);tmp;tmp--) printf("-");
|
||||
printf("]\r");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void eprintf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
//fflush(stderr); // XXX CRASH?!? stdin here?!?!?
|
||||
}
|
||||
Reference in new issue
Block a user