summaryrefslogtreecommitdiff
path: root/rbutil/jztool/src
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-07-17 19:35:09 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-07-20 14:56:58 +0000
commit740a50687f67f3684e4b5698f8f30e3adebb8f6e (patch)
treecc2afcc989f0ca89e849338ad136e4042acd6bc1 /rbutil/jztool/src
parent6f042e91dd8730bf72b423248aa2c520708f03c5 (diff)
downloadrockbox-740a50687f67f3684e4b5698f8f30e3adebb8f6e.tar.gz
rockbox-740a50687f67f3684e4b5698f8f30e3adebb8f6e.zip
jztool: add support for Shanling Q1 and Eros Qbootloader_shanlingq1_v1
Change-Id: I8e93162d1a9d82e9d132219f2803b1856d24ae6c
Diffstat (limited to 'rbutil/jztool/src')
-rw-r--r--rbutil/jztool/src/device_info.c72
-rw-r--r--rbutil/jztool/src/identify_file.c37
-rw-r--r--rbutil/jztool/src/ucl_unpack.c128
-rw-r--r--rbutil/jztool/src/usb.c40
-rw-r--r--rbutil/jztool/src/x1000.c (renamed from rbutil/jztool/src/fiiom3k.c)149
5 files changed, 266 insertions, 160 deletions
diff --git a/rbutil/jztool/src/device_info.c b/rbutil/jztool/src/device_info.c
index 5ce3899262..cc431959ca 100644
--- a/rbutil/jztool/src/device_info.c
+++ b/rbutil/jztool/src/device_info.c
@@ -22,39 +22,58 @@
22#include "jztool.h" 22#include "jztool.h"
23#include <string.h> 23#include <string.h>
24 24
25static const jz_device_info infotable[] = { 25static const jz_device_info infotable[JZ_NUM_DEVICES] = {
26 { 26 [JZ_DEVICE_FIIOM3K] = {
27 .name = "fiiom3k", 27 .name = "fiiom3k",
28 .file_ext = "m3k",
28 .description = "FiiO M3K", 29 .description = "FiiO M3K",
29 .device_type = JZ_DEVICE_FIIOM3K, 30 .device_type = JZ_DEVICE_FIIOM3K,
30 .cpu_type = JZ_CPU_X1000, 31 .cpu_type = JZ_CPU_X1000,
32 .vendor_id = 0x2972,
33 .product_id = 0x0003,
34 },
35 [JZ_DEVICE_SHANLINGQ1] = {
36 .name = "shanlingq1",
37 .file_ext = "q1",
38 .description = "Shanling Q1",
39 .device_type = JZ_DEVICE_SHANLINGQ1,
40 .cpu_type = JZ_CPU_X1000,
41 .vendor_id = 0x0525,
42 .product_id = 0xa4a5,
43 },
44 [JZ_DEVICE_EROSQ] = {
45 .name = "erosq",
46 .file_ext = "erosq",
47 .description = "AIGO Eros Q",
48 .device_type = JZ_DEVICE_EROSQ,
49 .cpu_type = JZ_CPU_X1000,
50 .vendor_id = 0xc502,
51 .product_id = 0x0023,
52 },
53};
54
55static const jz_cpu_info cputable[JZ_NUM_CPUS] = {
56 [JZ_CPU_X1000] = {
57 .info_str = "X1000_v1",
31 .vendor_id = 0xa108, 58 .vendor_id = 0xa108,
32 .product_id = 0x1000, 59 .product_id = 0x1000,
60 .stage1_load_addr = 0xf4001000,
61 .stage1_exec_addr = 0xf4001800,
62 .stage2_load_addr = 0x80004000,
63 .stage2_exec_addr = 0x80004000,
33 }, 64 },
34}; 65};
35 66
36static const int infotable_size = sizeof(infotable)/sizeof(struct jz_device_info);
37
38/** \brief Get the number of entries in the device info list */
39int jz_get_num_device_info(void)
40{
41 return infotable_size;
42}
43
44/** \brief Lookup info for a device by type, returns NULL if not found. */ 67/** \brief Lookup info for a device by type, returns NULL if not found. */
45const jz_device_info* jz_get_device_info(jz_device_type type) 68const jz_device_info* jz_get_device_info(jz_device_type type)
46{ 69{
47 for(int i = 0; i < infotable_size; ++i) 70 return jz_get_device_info_indexed(type);
48 if(infotable[i].device_type == type)
49 return &infotable[i];
50
51 return NULL;
52} 71}
53 72
54/** \brief Lookup info for a device by name, returns NULL if not found. */ 73/** \brief Lookup info for a device by name, returns NULL if not found. */
55const jz_device_info* jz_get_device_info_named(const char* name) 74const jz_device_info* jz_get_device_info_named(const char* name)
56{ 75{
57 for(int i = 0; i < infotable_size; ++i) 76 for(int i = 0; i < JZ_NUM_DEVICES; ++i)
58 if(!strcmp(infotable[i].name, name)) 77 if(!strcmp(infotable[i].name, name))
59 return &infotable[i]; 78 return &infotable[i];
60 79
@@ -64,8 +83,27 @@ const jz_device_info* jz_get_device_info_named(const char* name)
64/** \brief Get a device info entry by index, returns NULL if out of range. */ 83/** \brief Get a device info entry by index, returns NULL if out of range. */
65const jz_device_info* jz_get_device_info_indexed(int index) 84const jz_device_info* jz_get_device_info_indexed(int index)
66{ 85{
67 if(index < infotable_size) 86 if(index < JZ_NUM_DEVICES)
68 return &infotable[index]; 87 return &infotable[index];
69 else 88 else
70 return NULL; 89 return NULL;
71} 90}
91
92/** \brief Lookup info for a CPU, returns NULL if not found. */
93const jz_cpu_info* jz_get_cpu_info(jz_cpu_type type)
94{
95 if(type < JZ_NUM_CPUS)
96 return &cputable[type];
97 else
98 return NULL;
99}
100
101/** \brief Lookup info for a CPU by info string, returns NULL if not found. */
102const jz_cpu_info* jz_get_cpu_info_named(const char* info_str)
103{
104 for(int i = 0; i < JZ_NUM_CPUS; ++i)
105 if(!strcmp(cputable[i].info_str, info_str))
106 return &cputable[i];
107
108 return NULL;
109}
diff --git a/rbutil/jztool/src/identify_file.c b/rbutil/jztool/src/identify_file.c
index e735075687..e475d98a3b 100644
--- a/rbutil/jztool/src/identify_file.c
+++ b/rbutil/jztool/src/identify_file.c
@@ -118,43 +118,52 @@ int jz_identify_x1000_spl(const void* data, size_t len)
118static const struct scramble_model_info { 118static const struct scramble_model_info {
119 const char* name; 119 const char* name;
120 int model_num; 120 int model_num;
121 size_t offset_crc;
122 size_t offset_name;
123 size_t offset_data;
121} scramble_models[] = { 124} scramble_models[] = {
122 {"fiio", 114}, 125 {"fiio", 114, 0, 4, 8},
123 {NULL, 0}, 126 {"shq1", 115, 0, 4, 8},
127 {"eros", 116, 0, 4, 8},
128 {NULL, 0, 0, 0, 0},
124}; 129};
125 130
126/** \brief Identify a file as a Rockbox `scramble` image 131/** \brief Identify a file as a Rockbox `scramble` image
127 * \param data File data buffer 132 * \param data File data buffer
128 * \param len Length of file 133 * \param len Length of file
129 * \return JZ_SUCCESS if file looks correct, or one of the following errors 134 * \return JZ_SUCCESS if file looks correct, or one of the following errors
130 * \retval JZ_IDERR_WRONG_SIZE file too small to be valid
131 * \retval JZ_IDERR_UNRECOGNIZED_MODEL unsupported/unknown model type 135 * \retval JZ_IDERR_UNRECOGNIZED_MODEL unsupported/unknown model type
132 * \retval JZ_IDERR_BAD_CHECKSUM checksum mismatch 136 * \retval JZ_IDERR_BAD_CHECKSUM checksum mismatch
133 */ 137 */
134int jz_identify_scramble_image(const void* data, size_t len) 138int jz_identify_scramble_image(const void* data, size_t len)
135{ 139{
136 /* 4 bytes checksum + 4 bytes player model */ 140 const uint8_t* dat;
137 if(len < 8) 141 const struct scramble_model_info* model_info;
138 return JZ_IDERR_WRONG_SIZE; 142 uint32_t sum, file_sum;
143
144 dat = (const uint8_t*)data;
145 model_info = &scramble_models[0];
139 146
140 /* Look up the model number */ 147 /* Look up the model number */
141 const uint8_t* dat = (const uint8_t*)data; 148 for(; model_info->name != NULL; ++model_info) {
142 const struct scramble_model_info* model_info = &scramble_models[0]; 149 if(model_info->offset_name + 4 > len)
143 for(; model_info->name != NULL; ++model_info) 150 continue;
144 if(!memcmp(&dat[4], model_info->name, 4)) 151 if(!memcmp(&dat[model_info->offset_name], model_info->name, 4))
145 break; 152 break;
153 }
146 154
147 if(model_info->name == NULL) 155 if(model_info->name == NULL)
148 return JZ_IDERR_UNRECOGNIZED_MODEL; 156 return JZ_IDERR_UNRECOGNIZED_MODEL;
149 157
150 /* Compute the checksum */ 158 /* Compute the checksum */
151 uint32_t sum = model_info->model_num; 159 sum = model_info->model_num;
152 for(size_t i = 8; i < len; ++i) 160 for(size_t i = model_info->offset_data; i < len; ++i)
153 sum += dat[i]; 161 sum += dat[i];
154 162
155 /* Compare with file's checksum, it's stored in big-endian form */ 163 /* Compare with file's checksum, it's stored in big-endian form */
156 uint32_t fsum = (dat[0] << 24) | (dat[1] << 16) | (dat[2] << 8) | dat[3]; 164 dat += model_info->offset_crc;
157 if(sum != fsum) 165 file_sum = (dat[0] << 24) | (dat[1] << 16) | (dat[2] << 8) | dat[3];
166 if(sum != file_sum)
158 return JZ_IDERR_BAD_CHECKSUM; 167 return JZ_IDERR_BAD_CHECKSUM;
159 168
160 return JZ_SUCCESS; 169 return JZ_SUCCESS;
diff --git a/rbutil/jztool/src/ucl_unpack.c b/rbutil/jztool/src/ucl_unpack.c
new file mode 100644
index 0000000000..3b199c7008
--- /dev/null
+++ b/rbutil/jztool/src/ucl_unpack.c
@@ -0,0 +1,128 @@
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 "ucl/ucl.h"
24
25static uint32_t xread32(const uint8_t* d)
26{
27 uint32_t r = 0;
28 r |= d[0] << 24;
29 r |= d[1] << 16;
30 r |= d[2] << 8;
31 r |= d[3] << 0;
32 return r;
33}
34
35/* adapted from firmware/common/ucl_decompress.c */
36jz_buffer* jz_ucl_unpack(const uint8_t* src, uint32_t src_len, uint32_t* dst_len)
37{
38 static const uint8_t magic[8] =
39 {0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a};
40
41 jz_buffer* buffer = NULL;
42
43 /* make sure there are enough bytes for the header */
44 if(src_len < 18)
45 goto error;
46
47 /* avoid memcmp for reasons of code size */
48 for(size_t i = 0; i < sizeof(magic); ++i)
49 if(src[i] != magic[i])
50 goto error;
51
52 /* read the other header fields */
53 /* uint32_t flags = xread32(&src[8]); */
54 uint8_t method = src[12];
55 /* uint8_t level = src[13]; */
56 uint32_t block_size = xread32(&src[14]);
57
58 /* check supported compression method */
59 if(method != 0x2e)
60 goto error;
61
62 /* validate */
63 if(block_size < 1024 || block_size > 8*1024*1024)
64 goto error;
65
66 src += 18;
67 src_len -= 18;
68
69 /* Calculate amount of space that we might need & allocate a buffer:
70 * - subtract 4 to account for end of file marker
71 * - each block is block_size bytes + 8 bytes of header
72 * - add one to nr_blocks to account for case where file size < block size
73 * - total size = max uncompressed size of block * nr_blocks
74 */
75 uint32_t nr_blocks = (src_len - 4) / (8 + block_size) + 1;
76 uint32_t max_size = nr_blocks * (block_size + block_size/8 + 256);
77 buffer = jz_buffer_alloc(max_size, NULL);
78 if(!buffer)
79 goto error;
80
81 /* perform the decompression */
82 uint32_t dst_ilen = buffer->size;
83 uint8_t* dst = buffer->data;
84 while(1) {
85 if(src_len < 4)
86 goto error;
87
88 uint32_t out_len = xread32(src); src += 4, src_len -= 4;
89 if(out_len == 0)
90 break;
91
92 if(src_len < 4)
93 goto error;
94
95 uint32_t in_len = xread32(src); src += 4, src_len -= 4;
96 if(in_len > block_size || out_len > block_size ||
97 in_len == 0 || in_len > out_len)
98 goto error;
99
100 if(src_len < in_len)
101 goto error;
102
103 if(in_len < out_len) {
104 uint32_t actual_out_len = dst_ilen;
105 int rc = ucl_nrv2e_decompress_safe_8(src, in_len, dst, &actual_out_len, NULL);
106 if(rc != UCL_E_OK)
107 goto error;
108 if(actual_out_len != out_len)
109 goto error;
110 } else {
111 for(size_t i = 0; i < in_len; ++i)
112 dst[i] = src[i];
113 }
114
115 src += in_len;
116 src_len -= in_len;
117 dst += out_len;
118 dst_ilen -= out_len;
119 }
120
121 /* subtract leftover number of bytes to get size of compressed output */
122 *dst_len = buffer->size - dst_ilen;
123 return buffer;
124
125 error:
126 jz_buffer_free(buffer);
127 return NULL;
128}
diff --git a/rbutil/jztool/src/usb.c b/rbutil/jztool/src/usb.c
index c101f2be77..cfc3ba60cb 100644
--- a/rbutil/jztool/src/usb.c
+++ b/rbutil/jztool/src/usb.c
@@ -22,6 +22,7 @@
22#include "jztool_private.h" 22#include "jztool_private.h"
23#include <stdlib.h> 23#include <stdlib.h>
24#include <stdbool.h> 24#include <stdbool.h>
25#include <string.h>
25 26
26#define VR_GET_CPU_INFO 0 27#define VR_GET_CPU_INFO 0
27#define VR_SET_DATA_ADDRESS 1 28#define VR_SET_DATA_ADDRESS 1
@@ -145,11 +146,12 @@ void jz_usb_close(jz_usbdev* dev)
145 146
146// Does an Ingenic-specific vendor request 147// Does an Ingenic-specific vendor request
147// Written with X1000 in mind but other Ingenic CPUs have the same commands 148// Written with X1000 in mind but other Ingenic CPUs have the same commands
148static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg) 149static int jz_usb_vendor_req(jz_usbdev* dev, int req, uint32_t arg,
150 void* buffer, int buflen)
149{ 151{
150 int rc = libusb_control_transfer(dev->handle, 152 int rc = libusb_control_transfer(dev->handle,
151 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 153 LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
152 req, arg >> 16, arg & 0xffff, NULL, 0, 1000); 154 req, arg >> 16, arg & 0xffff, buffer, buflen, 1000);
153 155
154 if(rc < 0) { 156 if(rc < 0) {
155 jz_log(dev->jz, JZ_LOG_ERROR, "libusb_control_transfer: %s", libusb_strerror(rc)); 157 jz_log(dev->jz, JZ_LOG_ERROR, "libusb_control_transfer: %s", libusb_strerror(rc));
@@ -200,11 +202,11 @@ static int jz_usb_sendrecv(jz_usbdev* dev, bool write, uint32_t addr,
200 size_t len, void* data) 202 size_t len, void* data)
201{ 203{
202 int rc; 204 int rc;
203 rc = jz_usb_vendor_req(dev, VR_SET_DATA_ADDRESS, addr); 205 rc = jz_usb_vendor_req(dev, VR_SET_DATA_ADDRESS, addr, NULL, 0);
204 if(rc < 0) 206 if(rc < 0)
205 return rc; 207 return rc;
206 208
207 rc = jz_usb_vendor_req(dev, VR_SET_DATA_LENGTH, len); 209 rc = jz_usb_vendor_req(dev, VR_SET_DATA_LENGTH, len, NULL, 0);
208 if(rc < 0) 210 if(rc < 0)
209 return rc; 211 return rc;
210 212
@@ -242,7 +244,7 @@ int jz_usb_recv(jz_usbdev* dev, uint32_t addr, size_t len, void* data)
242 */ 244 */
243int jz_usb_start1(jz_usbdev* dev, uint32_t addr) 245int jz_usb_start1(jz_usbdev* dev, uint32_t addr)
244{ 246{
245 return jz_usb_vendor_req(dev, VR_PROGRAM_START1, addr); 247 return jz_usb_vendor_req(dev, VR_PROGRAM_START1, addr, NULL, 0);
246} 248}
247 249
248/** \brief Execute stage2 program jumping to the specified address 250/** \brief Execute stage2 program jumping to the specified address
@@ -252,7 +254,7 @@ int jz_usb_start1(jz_usbdev* dev, uint32_t addr)
252 */ 254 */
253int jz_usb_start2(jz_usbdev* dev, uint32_t addr) 255int jz_usb_start2(jz_usbdev* dev, uint32_t addr)
254{ 256{
255 return jz_usb_vendor_req(dev, VR_PROGRAM_START2, addr); 257 return jz_usb_vendor_req(dev, VR_PROGRAM_START2, addr, NULL, 0);
256} 258}
257 259
258/** \brief Ask device to flush CPU caches 260/** \brief Ask device to flush CPU caches
@@ -261,5 +263,29 @@ int jz_usb_start2(jz_usbdev* dev, uint32_t addr)
261 */ 263 */
262int jz_usb_flush_caches(jz_usbdev* dev) 264int jz_usb_flush_caches(jz_usbdev* dev)
263{ 265{
264 return jz_usb_vendor_req(dev, VR_FLUSH_CACHES, 0); 266 return jz_usb_vendor_req(dev, VR_FLUSH_CACHES, 0, NULL, 0);
267}
268
269/** \brief Ask device for CPU info string
270 * \param dev USB device
271 * \param buffer Buffer to hold the info string
272 * \param buflen Size of the buffer, in bytes
273 * \return either JZ_SUCCESS on success or a failure code
274 *
275 * The buffer will always be null terminated, but to ensure the info string is
276 * not truncated the buffer needs to be at least `JZ_CPUINFO_BUFLEN` byes long.
277 */
278int jz_usb_get_cpu_info(jz_usbdev* dev, char* buffer, size_t buflen)
279{
280 char tmpbuf[JZ_CPUINFO_BUFLEN];
281 int rc = jz_usb_vendor_req(dev, VR_GET_CPU_INFO, 0, tmpbuf, 8);
282 if(rc != JZ_SUCCESS)
283 return rc;
284
285 if(buflen > 0) {
286 strncpy(buffer, tmpbuf, buflen);
287 buffer[buflen - 1] = 0;
288 }
289
290 return JZ_SUCCESS;
265} 291}
diff --git a/rbutil/jztool/src/fiiom3k.c b/rbutil/jztool/src/x1000.c
index 72e25a1220..aacad0ef01 100644
--- a/rbutil/jztool/src/fiiom3k.c
+++ b/rbutil/jztool/src/x1000.c
@@ -22,117 +22,11 @@
22#include "jztool.h" 22#include "jztool.h"
23#include "jztool_private.h" 23#include "jztool_private.h"
24#include "microtar.h" 24#include "microtar.h"
25#include "ucl/ucl.h"
26#include <stdbool.h> 25#include <stdbool.h>
27#include <string.h> 26#include <string.h>
28 27
29static uint32_t xread32(const uint8_t* d) 28/* TODO: these functions could be refactored to be CPU-agnostic */
30{ 29static int run_stage1(jz_usbdev* dev, jz_buffer* buf)
31 uint32_t r = 0;
32 r |= d[0] << 24;
33 r |= d[1] << 16;
34 r |= d[2] << 8;
35 r |= d[3] << 0;
36 return r;
37}
38
39/* adapted from firmware/common/ucl_decompress.c */
40static jz_buffer* ucl_unpack(const uint8_t* src, uint32_t src_len,
41 uint32_t* dst_len)
42{
43 static const uint8_t magic[8] =
44 {0x00, 0xe9, 0x55, 0x43, 0x4c, 0xff, 0x01, 0x1a};
45
46 jz_buffer* buffer = NULL;
47
48 /* make sure there are enough bytes for the header */
49 if(src_len < 18)
50 goto error;
51
52 /* avoid memcmp for reasons of code size */
53 for(size_t i = 0; i < sizeof(magic); ++i)
54 if(src[i] != magic[i])
55 goto error;
56
57 /* read the other header fields */
58 /* uint32_t flags = xread32(&src[8]); */
59 uint8_t method = src[12];
60 /* uint8_t level = src[13]; */
61 uint32_t block_size = xread32(&src[14]);
62
63 /* check supported compression method */
64 if(method != 0x2e)
65 goto error;
66
67 /* validate */
68 if(block_size < 1024 || block_size > 8*1024*1024)
69 goto error;
70
71 src += 18;
72 src_len -= 18;
73
74 /* Calculate amount of space that we might need & allocate a buffer:
75 * - subtract 4 to account for end of file marker
76 * - each block is block_size bytes + 8 bytes of header
77 * - add one to nr_blocks to account for case where file size < block size
78 * - total size = max uncompressed size of block * nr_blocks
79 */
80 uint32_t nr_blocks = (src_len - 4) / (8 + block_size) + 1;
81 uint32_t max_size = nr_blocks * (block_size + block_size/8 + 256);
82 buffer = jz_buffer_alloc(max_size, NULL);
83 if(!buffer)
84 goto error;
85
86 /* perform the decompression */
87 uint32_t dst_ilen = buffer->size;
88 uint8_t* dst = buffer->data;
89 while(1) {
90 if(src_len < 4)
91 goto error;
92
93 uint32_t out_len = xread32(src); src += 4, src_len -= 4;
94 if(out_len == 0)
95 break;
96
97 if(src_len < 4)
98 goto error;
99
100 uint32_t in_len = xread32(src); src += 4, src_len -= 4;
101 if(in_len > block_size || out_len > block_size ||
102 in_len == 0 || in_len > out_len)
103 goto error;
104
105 if(src_len < in_len)
106 goto error;
107
108 if(in_len < out_len) {
109 uint32_t actual_out_len = dst_ilen;
110 int rc = ucl_nrv2e_decompress_safe_8(src, in_len, dst, &actual_out_len, NULL);
111 if(rc != UCL_E_OK)
112 goto error;
113 if(actual_out_len != out_len)
114 goto error;
115 } else {
116 for(size_t i = 0; i < in_len; ++i)
117 dst[i] = src[i];
118 }
119
120 src += in_len;
121 src_len -= in_len;
122 dst += out_len;
123 dst_ilen -= out_len;
124 }
125
126 /* subtract leftover number of bytes to get size of compressed output */
127 *dst_len = buffer->size - dst_ilen;
128 return buffer;
129
130 error:
131 jz_buffer_free(buffer);
132 return NULL;
133}
134
135static int m3k_stage1(jz_usbdev* dev, jz_buffer* buf)
136{ 30{
137 int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data); 31 int rc = jz_usb_send(dev, 0xf4001000, buf->size, buf->data);
138 if(rc < 0) 32 if(rc < 0)
@@ -141,7 +35,7 @@ static int m3k_stage1(jz_usbdev* dev, jz_buffer* buf)
141 return jz_usb_start1(dev, 0xf4001800); 35 return jz_usb_start1(dev, 0xf4001800);
142} 36}
143 37
144static int m3k_stage2(jz_usbdev* dev, jz_buffer* buf) 38static int run_stage2(jz_usbdev* dev, jz_buffer* buf)
145{ 39{
146 int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data); 40 int rc = jz_usb_send(dev, 0x80004000, buf->size, buf->data);
147 if(rc < 0) 41 if(rc < 0)
@@ -154,8 +48,8 @@ static int m3k_stage2(jz_usbdev* dev, jz_buffer* buf)
154 return jz_usb_start2(dev, 0x80004000); 48 return jz_usb_start2(dev, 0x80004000);
155} 49}
156 50
157static int m3k_get_file(jz_context* jz, mtar_t* tar, const char* file, 51static int get_file(jz_context* jz, mtar_t* tar, const char* file,
158 bool decompress, jz_buffer** buf) 52 bool decompress, jz_buffer** buf)
159{ 53{
160 jz_buffer* buffer = NULL; 54 jz_buffer* buffer = NULL;
161 mtar_header_t h; 55 mtar_header_t h;
@@ -180,7 +74,7 @@ static int m3k_get_file(jz_context* jz, mtar_t* tar, const char* file,
180 74
181 if(decompress) { 75 if(decompress) {
182 uint32_t dst_len; 76 uint32_t dst_len;
183 jz_buffer* nbuf = ucl_unpack(buffer->data, buffer->size, &dst_len); 77 jz_buffer* nbuf = jz_ucl_unpack(buffer->data, buffer->size, &dst_len);
184 jz_buffer_free(buffer); 78 jz_buffer_free(buffer);
185 if(!nbuf) { 79 if(!nbuf) {
186 jz_log(jz, JZ_LOG_ERROR, "error decompressing %s in boot file", file); 80 jz_log(jz, JZ_LOG_ERROR, "error decompressing %s in boot file", file);
@@ -196,7 +90,7 @@ static int m3k_get_file(jz_context* jz, mtar_t* tar, const char* file,
196 return JZ_SUCCESS; 90 return JZ_SUCCESS;
197} 91}
198 92
199static int m3k_show_version(jz_context* jz, jz_buffer* info_file) 93static int show_version(jz_context* jz, jz_buffer* info_file)
200{ 94{
201 /* Extract the version string and log it for informational purposes */ 95 /* Extract the version string and log it for informational purposes */
202 char* boot_version = (char*)info_file->data; 96 char* boot_version = (char*)info_file->data;
@@ -211,17 +105,28 @@ static int m3k_show_version(jz_context* jz, jz_buffer* info_file)
211 return JZ_SUCCESS; 105 return JZ_SUCCESS;
212} 106}
213 107
214/** \brief Load the Rockbox bootloader on the FiiO M3K 108/** \brief Load the Rockbox bootloader on an X1000 device
215 * \param dev USB device freshly returned by jz_usb_open() 109 * \param dev USB device freshly returned by jz_usb_open()
216 * \param filename Path to the "bootloader.m3k" file 110 * \param filename Path to the "bootloader.target" file
217 * \return either JZ_SUCCESS or an error code 111 * \return either JZ_SUCCESS or an error code
218 */ 112 */
219int jz_fiiom3k_boot(jz_usbdev* dev, const char* filename) 113int jz_x1000_boot(jz_usbdev* dev, jz_device_type type, const char* filename)
220{ 114{
115 const jz_device_info* dev_info;
116 char spl_filename[32];
221 jz_buffer* spl = NULL, *bootloader = NULL, *info_file = NULL; 117 jz_buffer* spl = NULL, *bootloader = NULL, *info_file = NULL;
222 mtar_t tar; 118 mtar_t tar;
223 int rc; 119 int rc;
224 120
121 /* In retrospect using a model-dependent archive format was not a good
122 * idea, but it's not worth fixing just yet... */
123 dev_info = jz_get_device_info(type);
124 if(!dev_info)
125 return JZ_ERR_OTHER;
126 /* use of sprintf is safe since file_ext is short */
127 sprintf(spl_filename, "spl.%s", dev_info->file_ext);
128
129 /* Now open the archive */
225 rc = mtar_open(&tar, filename, "r"); 130 rc = mtar_open(&tar, filename, "r");
226 if(rc != MTAR_ESUCCESS) { 131 if(rc != MTAR_ESUCCESS) {
227 jz_log(dev->jz, JZ_LOG_ERROR, "cannot open file %s (tar error: %d)", filename, rc); 132 jz_log(dev->jz, JZ_LOG_ERROR, "cannot open file %s (tar error: %d)", filename, rc);
@@ -229,25 +134,25 @@ int jz_fiiom3k_boot(jz_usbdev* dev, const char* filename)
229 } 134 }
230 135
231 /* Extract all necessary files */ 136 /* Extract all necessary files */
232 rc = m3k_get_file(dev->jz, &tar, "spl.m3k", false, &spl); 137 rc = get_file(dev->jz, &tar, spl_filename, false, &spl);
233 if(rc != JZ_SUCCESS) 138 if(rc != JZ_SUCCESS)
234 goto error; 139 goto error;
235 140
236 rc = m3k_get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader); 141 rc = get_file(dev->jz, &tar, "bootloader.ucl", true, &bootloader);
237 if(rc != JZ_SUCCESS) 142 if(rc != JZ_SUCCESS)
238 goto error; 143 goto error;
239 144
240 rc = m3k_get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file); 145 rc = get_file(dev->jz, &tar, "bootloader-info.txt", false, &info_file);
241 if(rc != JZ_SUCCESS) 146 if(rc != JZ_SUCCESS)
242 goto error; 147 goto error;
243 148
244 /* Display the version string */ 149 /* Display the version string */
245 rc = m3k_show_version(dev->jz, info_file); 150 rc = show_version(dev->jz, info_file);
246 if(rc != JZ_SUCCESS) 151 if(rc != JZ_SUCCESS)
247 goto error; 152 goto error;
248 153
249 /* Stage1 boot of SPL to set up hardware */ 154 /* Stage1 boot of SPL to set up hardware */
250 rc = m3k_stage1(dev, spl); 155 rc = run_stage1(dev, spl);
251 if(rc != JZ_SUCCESS) 156 if(rc != JZ_SUCCESS)
252 goto error; 157 goto error;
253 158
@@ -256,7 +161,7 @@ int jz_fiiom3k_boot(jz_usbdev* dev, const char* filename)
256 161
257 /* Stage2 boot into the bootloader's recovery menu 162 /* Stage2 boot into the bootloader's recovery menu
258 * User has to take manual action from there */ 163 * User has to take manual action from there */
259 rc = m3k_stage2(dev, bootloader); 164 rc = run_stage2(dev, bootloader);
260 if(rc != JZ_SUCCESS) 165 if(rc != JZ_SUCCESS)
261 goto error; 166 goto error;
262 167