diff options
Diffstat (limited to 'utils/rk27utils/rkusbtool/rkusbtool.c')
-rw-r--r-- | utils/rk27utils/rkusbtool/rkusbtool.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/utils/rk27utils/rkusbtool/rkusbtool.c b/utils/rk27utils/rkusbtool/rkusbtool.c new file mode 100644 index 0000000000..06fb7e860c --- /dev/null +++ b/utils/rk27utils/rkusbtool/rkusbtool.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* on ubuntu compile with gcc -W rkusbtool.c -o rkusbtool -lusb-1.0 -I/usr/include/libusb-1.0/ */ | ||
2 | #include <libusb.h> | ||
3 | #include <stdint.h> | ||
4 | #include <stdio.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #define VERSION "v0.1" | ||
8 | |||
9 | #define RETRY_MAX 5 | ||
10 | #define USB_TIMEOUT 512 | ||
11 | #define VENDORID 0x071b | ||
12 | #define PRODUCTID 0x3203 | ||
13 | |||
14 | #define OUT_EP 0x01 | ||
15 | #define IN_EP 0x82 | ||
16 | |||
17 | #define CBW_SIGNATURE 0x43425355 | ||
18 | #define CSW_SIGNATURE 0x53425355 | ||
19 | #define SCSICMD_READ_12 0xa8 | ||
20 | |||
21 | /* rockchip specific commands */ | ||
22 | #define RK_CMD 0xe0 | ||
23 | #define RK_GET_VERSION 0xffffffff | ||
24 | #define RK_SWITCH_ROCKUSB 0xfeffffff | ||
25 | #define RK_CHECK_USB 0xfdffffff | ||
26 | #define RK_OPEN_SYSDISK 0xfcffffff | ||
27 | |||
28 | enum { | ||
29 | NONE = 0, | ||
30 | INFO = 1, | ||
31 | RKUSB = 2, | ||
32 | SYSDISK = 4, | ||
33 | CHECKUSB = 8 | ||
34 | }; | ||
35 | |||
36 | enum { | ||
37 | COMMAND_PASSED = 0, | ||
38 | COMMAND_FAILED = 1, | ||
39 | PHASE_ERROR = 2 | ||
40 | }; | ||
41 | |||
42 | struct CBWCB_t | ||
43 | { | ||
44 | uint8_t cbCode; | ||
45 | uint8_t cbLun; | ||
46 | uint32_t LBA; | ||
47 | uint32_t cbLen; | ||
48 | uint8_t reseved; | ||
49 | uint8_t control; | ||
50 | } __attribute__((__packed__)); | ||
51 | |||
52 | struct CBW_t | ||
53 | { | ||
54 | uint32_t dCBWSignature; | ||
55 | uint32_t dCBWTag; | ||
56 | uint32_t dCBWDataTransferLength; | ||
57 | uint8_t bmCBWFlags; | ||
58 | uint8_t bCBWLUN; | ||
59 | uint8_t bCBWCBLength; | ||
60 | uint8_t CBWCB[16]; | ||
61 | } __attribute__((__packed__)); | ||
62 | |||
63 | struct CSW_t | ||
64 | { | ||
65 | uint32_t dCSWSignature; | ||
66 | uint32_t dCSWTag; | ||
67 | uint32_t dCSWDataResidue; | ||
68 | uint8_t bCSWStatus; | ||
69 | } __attribute__((__packed__)); | ||
70 | |||
71 | static int send_msc_cmd(libusb_device_handle *hdev, struct CBWCB_t *cbwcb, uint32_t data_len, uint32_t *reftag) | ||
72 | { | ||
73 | struct CBW_t cbw; | ||
74 | int ret, repeat, transferred; | ||
75 | static uint32_t tag = 0xdaefbc01; | ||
76 | |||
77 | memset(&cbw, 0, sizeof(cbw)); | ||
78 | cbw.dCBWSignature = CBW_SIGNATURE; | ||
79 | cbw.dCBWTag = tag++; | ||
80 | cbw.dCBWDataTransferLength = data_len; | ||
81 | cbw.bmCBWFlags = 0x80; /* device to host */ | ||
82 | cbw.bCBWLUN = 0; | ||
83 | cbw.bCBWCBLength = sizeof(struct CBWCB_t); | ||
84 | memcpy(cbw.CBWCB, cbwcb, sizeof(struct CBWCB_t)); | ||
85 | |||
86 | *reftag = cbw.dCBWTag; | ||
87 | do | ||
88 | { | ||
89 | /* transfer command to the device */ | ||
90 | ret = libusb_bulk_transfer(hdev, OUT_EP, (unsigned char*)&cbw, 31, &transferred, USB_TIMEOUT); | ||
91 | if (ret == LIBUSB_ERROR_PIPE) | ||
92 | { | ||
93 | libusb_clear_halt(hdev, OUT_EP); | ||
94 | } | ||
95 | repeat++; | ||
96 | } while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX)); | ||
97 | |||
98 | if (ret != LIBUSB_SUCCESS) | ||
99 | { | ||
100 | printf("error: command transfer error\n"); | ||
101 | return -1; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int get_msc_csw(libusb_device_handle *hdev, uint32_t reftag) | ||
108 | { | ||
109 | struct CSW_t csw; | ||
110 | int ret, repeat, transferred; | ||
111 | |||
112 | /* get CSW response from device */ | ||
113 | repeat = 0; | ||
114 | do | ||
115 | { | ||
116 | ret = libusb_bulk_transfer(hdev, IN_EP, (unsigned char *)&csw, 13, &transferred, USB_TIMEOUT); | ||
117 | if (ret == LIBUSB_ERROR_PIPE) | ||
118 | { | ||
119 | libusb_clear_halt(hdev, IN_EP); | ||
120 | } | ||
121 | repeat++; | ||
122 | } while ((ret == LIBUSB_ERROR_PIPE) && (repeat < RETRY_MAX)); | ||
123 | |||
124 | if (ret != LIBUSB_SUCCESS) | ||
125 | { | ||
126 | printf("error reading CSW\n"); | ||
127 | return -3; | ||
128 | } | ||
129 | |||
130 | if (transferred != 13) | ||
131 | { | ||
132 | printf("error wrong size of CSW packet\n"); | ||
133 | return -4; | ||
134 | } | ||
135 | |||
136 | if (csw.dCSWSignature != CSW_SIGNATURE) | ||
137 | { | ||
138 | printf("error: wrong CSW signature.\n"); | ||
139 | return -5; | ||
140 | } | ||
141 | |||
142 | if (csw.dCSWTag != reftag) | ||
143 | { | ||
144 | printf("error: CSW dCSWTag mismatch\n"); | ||
145 | return -6; | ||
146 | } | ||
147 | |||
148 | if (csw.bCSWStatus) | ||
149 | { | ||
150 | /* In case of CSW indicating error dump the content of the packet */ | ||
151 | printf ("dCSWSignature: 0x%0x\n", csw.dCSWSignature); | ||
152 | printf ("dCSWTag: 0x%0x\n", csw.dCSWTag); | ||
153 | printf ("dCSWDataResidue: 0x%0x\n", csw.dCSWDataResidue); | ||
154 | printf ("bCSWStatus: 0x%0x\n", csw.bCSWStatus); | ||
155 | } | ||
156 | |||
157 | return csw.bCSWStatus; | ||
158 | } | ||
159 | |||
160 | static int rk_cmd(libusb_device_handle *hdev, uint32_t command, uint8_t *buf, uint8_t len) | ||
161 | { | ||
162 | struct CBWCB_t cbwcb; | ||
163 | int ret, transferred; | ||
164 | uint32_t reftag; | ||
165 | |||
166 | /* enter command */ | ||
167 | memset(&cbwcb, 0, sizeof(cbwcb)); | ||
168 | cbwcb.cbCode = SCSICMD_READ_12; | ||
169 | cbwcb.cbLun = RK_CMD; | ||
170 | cbwcb.LBA = command; /* RK_GET_VERSION, RK_OPEN_SYSDISK, RK_SWITCH_ROCKUSB */ | ||
171 | cbwcb.cbLen = len; /* size of transfer in response to this command */ | ||
172 | |||
173 | ret = send_msc_cmd(hdev, &cbwcb, len, &reftag); | ||
174 | |||
175 | /* get the response */ | ||
176 | if (len > 0) | ||
177 | { | ||
178 | ret = libusb_bulk_transfer(hdev, IN_EP, buf, len, &transferred, USB_TIMEOUT); | ||
179 | if (ret != LIBUSB_SUCCESS || transferred != len) | ||
180 | { | ||
181 | printf("error: reading response data failed\n"); | ||
182 | return -2; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | return get_msc_csw(hdev, reftag); | ||
187 | } | ||
188 | |||
189 | static int get_sense(libusb_device_handle *hdev) | ||
190 | { | ||
191 | struct CBWCB_t cbwcb; | ||
192 | unsigned char sense[0x12]; | ||
193 | int size, ret; | ||
194 | uint32_t reftag; | ||
195 | |||
196 | memset(&cbwcb, 0, sizeof(cbwcb)); | ||
197 | cbwcb.cbCode = 0x03; | ||
198 | cbwcb.cbLun = 0; | ||
199 | cbwcb.LBA = 0; | ||
200 | cbwcb.cbLen = 0x12; | ||
201 | |||
202 | ret = send_msc_cmd(hdev, &cbwcb, 0x12, &reftag); | ||
203 | libusb_bulk_transfer(hdev, IN_EP, (unsigned char*)&sense, 0x12, &size, USB_TIMEOUT); | ||
204 | |||
205 | return get_msc_csw(hdev, reftag); | ||
206 | } | ||
207 | |||
208 | static void usage(void) | ||
209 | { | ||
210 | printf("Usage: rkusbtool [options]\n"); | ||
211 | printf("-h|--help This help message\n"); | ||
212 | printf("-i|--info Get version string from the device\n"); | ||
213 | printf("-d|--dfu Put device into DFU mode\n"); | ||
214 | printf("-s|--sysdisk Open system disk\n"); | ||
215 | printf("-c|--checkusb Check if dev is in System or Loader USB mode\n"); | ||
216 | } | ||
217 | |||
218 | int main (int argc, char **argv) | ||
219 | { | ||
220 | libusb_device_handle *hdev; | ||
221 | int ret; | ||
222 | int i = 0, action = NONE; | ||
223 | uint32_t ver[3]; | ||
224 | |||
225 | if (argc < 2) | ||
226 | { | ||
227 | usage(); | ||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | /* print banner */ | ||
232 | fprintf(stderr,"rkusbtool " VERSION "\n"); | ||
233 | fprintf(stderr,"(C) Marcin Bukat 2011\n"); | ||
234 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | ||
235 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | ||
236 | |||
237 | /* arguments handling */ | ||
238 | while (i < argc) | ||
239 | { | ||
240 | if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--info")==0)) | ||
241 | { | ||
242 | action |= INFO; | ||
243 | } | ||
244 | else if ((strcmp(argv[i],"-d")==0) || (strcmp(argv[i],"--dfu")==0)) | ||
245 | { | ||
246 | action |= RKUSB; | ||
247 | } | ||
248 | else if ((strcmp(argv[i],"-s")==0) || (strcmp(argv[i],"--sysdisk")==0)) | ||
249 | { | ||
250 | action |= SYSDISK; | ||
251 | } | ||
252 | else if ((strcmp(argv[i],"-c")==0) || (strcmp(argv[i],"--checkusb")==0)) | ||
253 | { | ||
254 | action |= CHECKUSB; | ||
255 | } | ||
256 | else if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0)) | ||
257 | { | ||
258 | usage(); | ||
259 | return 0; | ||
260 | } | ||
261 | i++; | ||
262 | } | ||
263 | |||
264 | /* initialize libusb */ | ||
265 | libusb_init(NULL); | ||
266 | /* usb_set_debug(2); */ | ||
267 | |||
268 | hdev = libusb_open_device_with_vid_pid(NULL, VENDORID, PRODUCTID); | ||
269 | if (hdev == NULL) | ||
270 | { | ||
271 | printf("error: can't open device\n"); | ||
272 | return -10; | ||
273 | } | ||
274 | |||
275 | ret = libusb_kernel_driver_active(hdev, 0); | ||
276 | |||
277 | if (ret < 0) | ||
278 | { | ||
279 | printf ("error checking kernel driver active\n"); | ||
280 | libusb_close(hdev); | ||
281 | return -3; | ||
282 | } | ||
283 | else | ||
284 | { | ||
285 | if (ret) | ||
286 | libusb_detach_kernel_driver(hdev, 0); | ||
287 | } | ||
288 | |||
289 | ret = libusb_set_configuration(hdev, 1); | ||
290 | if (ret < 0) | ||
291 | { | ||
292 | printf("error: could not select configuration (1)\n"); | ||
293 | libusb_close(hdev); | ||
294 | return -3; | ||
295 | } | ||
296 | |||
297 | ret = libusb_claim_interface(hdev, 0); | ||
298 | if (ret < 0) | ||
299 | { | ||
300 | printf("error: could not claim interface #0\n"); | ||
301 | libusb_close(hdev); | ||
302 | return -11; | ||
303 | } | ||
304 | |||
305 | ret = libusb_set_interface_alt_setting(hdev, 0, 0); | ||
306 | if ( ret != LIBUSB_SUCCESS) | ||
307 | { | ||
308 | printf("error: could not set alt setting for interface #0\n"); | ||
309 | libusb_close(hdev); | ||
310 | return -11; | ||
311 | } | ||
312 | |||
313 | /* BulkOnly reset */ | ||
314 | //ret = libusb_control_transfer(hdev, 0x21, 0xff, 0, 0, NULL, 0, USB_TIMEOUT); | ||
315 | |||
316 | /* BulkOnly get max lun */ | ||
317 | //ret = libusb_control_transfer(hdev, 0xa1, 0xfe, 0, 0, &maxlun, 1, USB_TIMEOUT); | ||
318 | |||
319 | /* Devices that do not support multiple LUNs may STALL this command. */ | ||
320 | //if (ret == 0) | ||
321 | // maxlun = -1; | ||
322 | |||
323 | //printf("MAXLUN: %d\n", maxlun); | ||
324 | |||
325 | get_sense(hdev); | ||
326 | |||
327 | if (action & INFO) | ||
328 | { | ||
329 | ret = rk_cmd(hdev, RK_GET_VERSION, (uint8_t *)ver, 12); | ||
330 | |||
331 | if (ret) | ||
332 | { | ||
333 | printf("error sending RK_GET_VERSION command. Err 0x%0x\n", ret); | ||
334 | libusb_close(hdev); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | printf("Rockchip device info:\n"); | ||
339 | printf("loader ver: %x.%x\n", (ver[0]>>16)&0xff, ver[0]&0xff); | ||
340 | printf("kernel ver: %x.%x\n", (ver[1]>>16)&0xff, ver[1]&0xff); | ||
341 | printf("sdk ver: %x.%x\n", (ver[2]>>16)&0xff, ver[2]&0xff); | ||
342 | } | ||
343 | |||
344 | if (action & CHECKUSB) | ||
345 | { | ||
346 | printf("Checking USB mode...\n"); | ||
347 | ret = rk_cmd(hdev, RK_CHECK_USB, (uint8_t *)ver, 1); | ||
348 | |||
349 | //if (ret) | ||
350 | //{ | ||
351 | // libusb_close(hdev); | ||
352 | // return ret; | ||
353 | //} | ||
354 | |||
355 | if (*(char *)ver) | ||
356 | printf("The device is in Loader USB mode\n"); | ||
357 | else | ||
358 | printf("The device is in System USB mode\n"); | ||
359 | } | ||
360 | |||
361 | if (action & SYSDISK) | ||
362 | { | ||
363 | printf("Opening system disk...\n"); | ||
364 | ret = rk_cmd(hdev, RK_OPEN_SYSDISK, NULL, 0); | ||
365 | |||
366 | if (ret) | ||
367 | { | ||
368 | libusb_close(hdev); | ||
369 | return ret; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | if (action & RKUSB) | ||
374 | { | ||
375 | printf("Switching into rk DFU mode...\n"); | ||
376 | ret = rk_cmd(hdev, RK_SWITCH_ROCKUSB, NULL, 0); | ||
377 | |||
378 | if (ret) | ||
379 | { | ||
380 | libusb_close(hdev); | ||
381 | return ret; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | libusb_close(hdev); | ||
386 | libusb_exit(NULL); | ||
387 | return 0; | ||
388 | } | ||