summaryrefslogtreecommitdiff
path: root/utils/jztool/jztool.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/jztool/jztool.c')
-rw-r--r--utils/jztool/jztool.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/utils/jztool/jztool.c b/utils/jztool/jztool.c
new file mode 100644
index 0000000000..dcd78137b3
--- /dev/null
+++ b/utils/jztool/jztool.c
@@ -0,0 +1,212 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "jztool.h"
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdbool.h>
27
28jz_context* jz = NULL;
29jz_usbdev* usbdev = NULL;
30const jz_device_info* dev_info = NULL;
31const jz_cpu_info* cpu_info = NULL;
32
33void usage_x1000(void)
34{
35 printf(
36"Usage:\n"
37" jztool fiiom3k load <bootloader.m3k>\n"
38" jztool shanlingq1 load <bootloader.q1>\n"
39" jztool erosq load <bootloader.erosq>\n"
40"\n"
41"The 'load' command is used to boot the Rockbox bootloader in recovery\n"
42"mode, which allows you to install the Rockbox bootloader and backup or\n"
43"restore bootloader images. You need to connect your player in USB boot\n"
44"mode in order to use this tool.\n"
45"\n"
46"To connect the player in USB boot mode, follow these steps:\n"
47"\n"
48"1. Ensure the player is fully powered off.\n"
49"2. Plug one end of the USB cable into your player.\n"
50"3. Hold down your player's USB boot key (see below).\n"
51"4. Plug the other end of the USB cable into your computer.\n"
52"5. Let go of the USB boot key.\n"
53"\n"
54"USB boot keys:\n"
55"\n"
56" FiiO M3K - Volume Down\n"
57" Shanling Q1 - Play\n"
58" Eros Q - Menu\n"
59"\n"
60"Not all players give a visible indication that they are in USB boot mode.\n"
61"If you're having trouble connecting your player, try resetting it by\n"
62"holding the power button for 10 seconds, and try the above steps again.\n"
63"\n"
64"Note for Windows users: you need to install the WinUSB driver using a\n"
65"3rd-party tool such as Zadig <https://zadig.akeo.ie> before this tool\n"
66"can access your player in USB boot mode. You need to run Zadig while the\n"
67"player is plugged in and in USB boot mode. For more details check the\n"
68"jztool README.md file or visit <https://rockbox.org/wiki/IngenicX1000>.\n"
69"\n");
70
71 exit(4);
72}
73
74int cmdline_x1000(int argc, char** argv)
75{
76 if(argc < 2 || strcmp(argv[0], "load")) {
77 usage_x1000();
78 return 2;
79 }
80
81 int rc = jz_usb_open(jz, &usbdev, cpu_info->vendor_id, cpu_info->product_id);
82 if(rc < 0) {
83 jz_log(jz, JZ_LOG_ERROR, "Cannot open USB device: %d", rc);
84 return 1;
85 }
86
87 rc = jz_x1000_boot(usbdev, dev_info->device_type, argv[1]);
88 if(rc < 0) {
89 jz_log(jz, JZ_LOG_ERROR, "Boot failed: %d", rc);
90 return 1;
91 }
92
93 return 0;
94}
95
96void usage(void)
97{
98 printf("Usage:\n"
99 " jztool [global options] <device> <command> [command arguments]\n"
100 "\n"
101 "Global options:\n"
102 " -h, --help Display this help\n"
103 " -q, --quiet Don't log anything except errors\n"
104 " -v, --verbose Display detailed logging output\n\n");
105
106 printf("Supported devices:\n\n");
107 for(int i = 0; i < JZ_NUM_DEVICES; ++i) {
108 const jz_device_info* info = jz_get_device_info_indexed(i);
109 printf(" %s - %s\n", info->name, info->description);
110 }
111
112 printf("\n"
113 "For device-specific help run 'jztool DEVICE' without arguments,\n"
114 "eg. 'jztool fiiom3k' will display help for the FiiO M3K.\n");
115
116 exit(4);
117}
118
119void cleanup(void)
120{
121 if(usbdev)
122 jz_usb_close(usbdev);
123 if(jz)
124 jz_context_destroy(jz);
125}
126
127int main(int argc, char** argv)
128{
129 if(argc < 2)
130 usage();
131
132 /* Library initialization */
133 jz = jz_context_create();
134 if(!jz) {
135 fprintf(stderr, "ERROR: Can't create context");
136 return 1;
137 }
138
139 atexit(cleanup);
140 jz_context_set_log_cb(jz, jz_log_cb_stderr);
141 jz_context_set_log_level(jz, JZ_LOG_NOTICE);
142
143 /* Parse global options */
144 --argc, ++argv;
145 while(argc > 0 && argv[0][0] == '-') {
146 if(!strcmp(*argv, "-h") || !strcmp(*argv, "--help"))
147 usage();
148 else if(!strcmp(*argv, "-q") || !strcmp(*argv, "--quiet"))
149 jz_context_set_log_level(jz, JZ_LOG_ERROR);
150 else if(!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose"))
151 jz_context_set_log_level(jz, JZ_LOG_DETAIL);
152 else if(!strcmp(*argv, "-l") || !strcmp(*argv, "--loglevel")) {
153 ++argv;
154 if(--argc == 0) {
155 jz_log(jz, JZ_LOG_ERROR, "Missing argument to option %s", *argv);
156 exit(2);
157 }
158
159 enum jz_log_level level;
160 if(!strcmp(*argv, "ignore"))
161 level = JZ_LOG_IGNORE;
162 else if(!strcmp(*argv, "error"))
163 level = JZ_LOG_ERROR;
164 else if(!strcmp(*argv, "warning"))
165 level = JZ_LOG_WARNING;
166 else if(!strcmp(*argv, "notice"))
167 level = JZ_LOG_NOTICE;
168 else if(!strcmp(*argv, "detail"))
169 level = JZ_LOG_DETAIL;
170 else if(!strcmp(*argv, "debug"))
171 level = JZ_LOG_DEBUG;
172 else {
173 jz_log(jz, JZ_LOG_ERROR, "Invalid log level '%s'", *argv);
174 exit(2);
175 }
176
177 jz_context_set_log_level(jz, level);
178 } else {
179 jz_log(jz, JZ_LOG_ERROR, "Invalid global option '%s'", *argv);
180 exit(2);
181 }
182
183 --argc, ++argv;
184 }
185
186 /* Read the device type */
187 if(argc == 0) {
188 jz_log(jz, JZ_LOG_ERROR, "No device specified (try jztool --help)");
189 exit(2);
190 }
191
192 dev_info = jz_get_device_info_named(*argv);
193 if(!dev_info) {
194 jz_log(jz, JZ_LOG_ERROR, "Unknown device '%s' (try jztool --help)", *argv);
195 exit(2);
196 }
197
198 cpu_info = jz_get_cpu_info(dev_info->cpu_type);
199
200 /* Dispatch to device handler */
201 --argc, ++argv;
202 switch(dev_info->device_type) {
203 case JZ_DEVICE_FIIOM3K:
204 case JZ_DEVICE_SHANLINGQ1:
205 case JZ_DEVICE_EROSQ:
206 return cmdline_x1000(argc, argv);
207
208 default:
209 jz_log(jz, JZ_LOG_ERROR, "INTERNAL ERROR: unhandled device type");
210 return 1;
211 }
212}