blob: 2372714a497dd73538dfd98a6e3e9fe6175e1e7b [file] [log] [blame]
Dave Chapman71cdf002007-10-20 09:11:34 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
12 * USB code based on ifp-line - http://ifp-driver.sourceforge.net
13 *
14 * ifp-line is (C) Pavel Kriz, Jun Yamishiro and Joe Roback and
15 * licensed under the GPL (v2)
16 *
17 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000018 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
Dave Chapman71cdf002007-10-20 09:11:34 +000022 *
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
25 *
26 ****************************************************************************/
27
Dave Chapman71cdf002007-10-20 09:11:34 +000028#include <stdio.h>
29#include <inttypes.h>
30#include <usb.h>
31#include <string.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
35#include <fcntl.h>
36
Dave Chapman28c5ba82007-10-27 07:53:42 +000037#define MAX_FIRMWARESIZE (10*1024*1024) /* Arbitrary limit (for safety) */
Dave Chapman71cdf002007-10-20 09:11:34 +000038
Dave Chapman164b8f62007-10-31 17:52:50 +000039/* For win32 compatibility: */
40#ifndef O_BINARY
41#define O_BINARY 0
42#endif
43
Dave Chapman71cdf002007-10-20 09:11:34 +000044struct device_t
45{
46 char* name;
47 char* label;
Dave Chapman11251f42007-10-21 11:00:28 +000048 uint16_t productid;
Dave Chapman71cdf002007-10-20 09:11:34 +000049 uint32_t loadaddr;
Dave Chapman2c816d12007-10-20 21:00:34 +000050 uint32_t sdcfg;
Dave Chapman71cdf002007-10-20 09:11:34 +000051};
52
53static struct device_t devices[] =
54{
Dave Chapman738a8972007-10-27 11:55:38 +000055 {"c100", "Sansa C100 series", 0xb021, 0x20000000, 0x42e97010 },
Robert Menes02512be2009-05-07 20:49:03 +000056 {"m200", "Sansa M200 series", 0xb021, 0x20000000, 0x42e97010 },
Dave Chapman28c5ba82007-10-27 07:53:42 +000057 {"cowond2", "Cowon D2", 0xb011, 0x20000000, 0xa2e92010 },
Bertrik Sikkend0ffa932010-11-10 18:55:59 +000058 {"cowonj3", "Cowon J3", 0xb057, 0x20000000, 0xaaac7800 },
Dave Chapmancdcca872010-05-02 09:42:51 +000059 {"cowons9", "Cowon S9", 0xb057, 0x20000000, 0xa1102800 },
Dave Chapman11251f42007-10-21 11:00:28 +000060 {"iaudio6", "iAudio 6", 0xb021, 0x20000000, 0x62e97010 },
61 {"iaudio7", "iAudio 7", 0xb021, 0x20000000, 0x62e97010 },
Dave Chapman1b39f2e2008-02-07 20:53:20 +000062 {"logikdax", "Logik DAX 1GB DAB/MP3 player", 0xb021, 0x20000000, 0x52e97410 },
Dave Chapman5b3627f2008-10-05 00:36:12 +000063 {"x20", "iRiver X20", 0xb051, 0x20000000, 0x02e92010 },
Dave Chapman7d189352008-02-23 20:47:40 +000064 {"ypp2", "Samsung YP-P2", 0xb011, 0x20000000, 0x22e92010 },
Dave Chapman9ce02612008-02-23 20:50:26 +000065 {"ypk3", "Samsung YP-K3", 0xb021, 0x20000000, 0x62e92018 },
Amaury Poulyafd85632013-09-18 13:06:30 +020066 {"ypt10", "Samsung YP-T10", 0xb011, 0x20000000, 0x62e97080 },
Dave Chapman71cdf002007-10-20 09:11:34 +000067};
68
69#define NUM_DEVICES ((sizeof(devices) / sizeof(struct device_t)))
70
71int find_device(char* devname)
72{
73 unsigned int i = 0;
74
75 while ((i < NUM_DEVICES) && (strcmp(devices[i].name,devname)))
76 i++;
77
78 if (i==NUM_DEVICES)
79 return -1;
80 else
81 return i;
82}
83
84void print_devices(void)
85{
86 unsigned int i;
87
88 printf("Valid devices are:\n");
89 for (i=0; i<NUM_DEVICES; i++)
90 {
91 printf(" %10s - %s\n",devices[i].name,devices[i].label);
92 }
93}
94
95/* USB IDs for USB Boot Mode */
96#define TCC_VENDORID 0x140e
Dave Chapman71cdf002007-10-20 09:11:34 +000097
98#define TCC_BULK_TO 1
99#define TOUT 5000
100#define PACKET_SIZE 64 /* Number of bytes to send in one write */
101
102#ifndef MAX
103#define MAX(a,b) (((a)>(b))?(a):(b))
104#endif
105
106static void put_int32le(uint32_t x, char* p)
107{
108 p[0] = x & 0xff;
109 p[1] = (x >> 8) & 0xff;
110 p[2] = (x >> 16) & 0xff;
111 p[3] = (x >> 24) & 0xff;
112}
113
114int upload_app(usb_dev_handle* dh, int device, char* p, int len)
115{
116 char buf[PACKET_SIZE];
117 int err;
118 int i;
119
Dave Chapman2c816d12007-10-20 21:00:34 +0000120 /* Send the header - Destination address, length and SDCFG value */
Dave Chapman71cdf002007-10-20 09:11:34 +0000121 memset(buf, 0, PACKET_SIZE);
122
123 put_int32le(0xf0000000, buf); /* Unknown - always the same */
124 put_int32le(len / PACKET_SIZE, buf + 4);
125 put_int32le(devices[device].loadaddr, buf + 8);
Dave Chapman2c816d12007-10-20 21:00:34 +0000126 put_int32le(devices[device].sdcfg, buf + 12);
Dave Chapman71cdf002007-10-20 09:11:34 +0000127
128 err = usb_bulk_write(dh, TCC_BULK_TO, buf, PACKET_SIZE, TOUT);
129
130 if (err < 0)
131 {
132 fprintf(stderr,"[ERR] Error writing header\n");
133 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
134 return -1;
135 }
136
137 /* Now send the data, PACKET_SIZE bytes at a time. */
138
139 for (i=0 ; i < (len / PACKET_SIZE) ; i++)
140 {
141 err = usb_bulk_write(dh, TCC_BULK_TO, p, PACKET_SIZE, TOUT);
142
143 if (err < 0)
144 {
145 fprintf(stderr,"[ERR] Error writing data\n");
146 fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
147 return -1;
148 }
149
150 p += PACKET_SIZE;
151 }
152
153 return 0;
154}
155
156
157/* The main function */
158
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000159int do_patching(int device, char* buf, int len)
Dave Chapman71cdf002007-10-20 09:11:34 +0000160{
161 struct usb_bus *busses;
162 struct usb_bus *bus;
163 struct usb_device *tmp_dev;
164 struct usb_device *dev = NULL;
165 usb_dev_handle *dh;
166 int err;
167
168 fprintf(stderr,"[INFO] Searching for TCC device...\n");
169
170 usb_init();
171 if(usb_find_busses() < 0) {
172 fprintf(stderr, "[ERR] Could not find any USB busses.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000173 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000174 }
175
176 if (usb_find_devices() < 0) {
177 fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000178 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000179 }
180
181 /* C calling convention, it's not nice to use global stuff */
182 busses = usb_get_busses();
183
184 for (bus = busses; bus; bus = bus->next) {
185 for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) {
186 //printf("Found Vendor %04x Product %04x\n",tmp_dev->descriptor.idVendor, tmp_dev->descriptor.idProduct);
187 if (tmp_dev->descriptor.idVendor == TCC_VENDORID &&
Dave Chapman11251f42007-10-21 11:00:28 +0000188 tmp_dev->descriptor.idProduct == devices[device].productid) {
Dave Chapman71cdf002007-10-20 09:11:34 +0000189
190 dev = tmp_dev;
191 goto found;
192
193 }
194 }
195 }
196
197 if (dev == NULL) {
198 fprintf(stderr, "[ERR] TCC device not found.\n");
199 fprintf(stderr, "[ERR] Ensure your TCC device is in USB boot mode and run tcctool again.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000200 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000201 }
202
203found:
204 if ( (dh = usb_open(dev)) == NULL) {
205 fprintf(stderr,"[ERR] Unable to open TCC device.\n");
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000206 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000207 }
208
209 err = usb_set_configuration(dh, 1);
210
211 if (err < 0) {
212 fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err);
213 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000214 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000215 }
216
217 /* "must be called" written in the libusb documentation */
218 err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
219 if (err < 0) {
220 fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err);
221 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000222 return -1;
Dave Chapman71cdf002007-10-20 09:11:34 +0000223 }
224
225 fprintf(stderr,"[INFO] Found TCC device, uploading application.\n");
226
227 /* Now we can transfer the application to the device. */
228
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000229 if ( (err = upload_app(dh, device, buf, len)) < 0)
Dave Chapman71cdf002007-10-20 09:11:34 +0000230 {
231 fprintf(stderr,"[ERR] Upload of application failed.\n");
232 }
233 else
234 {
235 fprintf(stderr,"[INFO] Patching application uploaded successfully!\n");
236 }
237
238 /* release claimed interface */
239 usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
Dave Chapman71cdf002007-10-20 09:11:34 +0000240 usb_close(dh);
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000241
242 return err < 0 ? -1: 0;
Dave Chapman71cdf002007-10-20 09:11:34 +0000243}
244
245off_t filesize(int fd) {
246 struct stat buf;
247
248 if (fstat(fd,&buf) < 0) {
249 perror("[ERR] Checking filesize of input file");
250 return -1;
251 } else {
252 return(buf.st_size);
253 }
254}
255
256void print_usage(void)
257{
258 printf("Usage: tcctool -d devicename firmware.bin\n");
259}
260
261int main(int argc, char* argv[])
262{
263 char* buf;
Dave Chapman3d300292008-10-12 18:10:39 +0000264 int n,len,padded_len;
Dave Chapman71cdf002007-10-20 09:11:34 +0000265 int fd;
266 int device;
267
Dave Chapman9de9b9d2010-05-02 09:54:14 +0000268 printf("tcctool " VERSION " - (C) 2007-2010 Dave Chapman\n");
Dave Chapman71cdf002007-10-20 09:11:34 +0000269 printf("This is free software; see the source for copying conditions. There is NO\n");
270 printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
271
272 if (argc != 4)
273 {
274 print_usage();
Dave Chapman28c5ba82007-10-27 07:53:42 +0000275 print_devices();
Dave Chapman71cdf002007-10-20 09:11:34 +0000276 return 1;
277 }
278
279 if (strcmp(argv[1],"-d"))
280 {
281 print_usage();
Dave Chapman28c5ba82007-10-27 07:53:42 +0000282 print_devices();
Dave Chapman71cdf002007-10-20 09:11:34 +0000283 return 2;
284 }
285
286 device = find_device(argv[2]);
287
288 if (device < 0)
289 {
290 printf("[ERR] Unknown device \"%s\"\n",argv[2]);
291 print_devices();
292 return 3;
293 }
294
295 printf("[INFO] Using device \"%s\"\n",devices[device].label);
Dave Chapman164b8f62007-10-31 17:52:50 +0000296 fd = open(argv[3], O_RDONLY|O_BINARY);
Dave Chapman71cdf002007-10-20 09:11:34 +0000297 if (fd < 0)
298 {
299 printf("[ERR] Could not open %s\n", argv[3]);
300 return 4;
301 }
302
303 len = filesize(fd);
304
305 if (len > MAX_FIRMWARESIZE)
306 {
307 printf("[ERR] Firmware file too big\n");
308 close(fd);
309 return 5;
310 }
311
Dave Chapman3d300292008-10-12 18:10:39 +0000312 /* Round len up to multiple of PACKET_SIZE */
313 padded_len = (len + PACKET_SIZE) & ~(PACKET_SIZE-1);
314
315 buf = malloc(padded_len);
Dave Chapman71cdf002007-10-20 09:11:34 +0000316 if (buf == NULL)
317 {
318 printf("[ERR] Could not allocate memory.\n");
319 close(fd);
320 return 6;
321 }
322
323 n = read(fd, buf, len);
324 if (n != len)
325 {
326 printf("[ERR] Short read.\n");
327 close(fd);
328 return 7;
329 }
330 close(fd);
331
Vitja Makarov7a6aeb82008-10-13 11:31:35 +0000332 if (do_patching(device, buf, padded_len))
333 {
334 return 8;
335 }
Dave Chapman71cdf002007-10-20 09:11:34 +0000336
337 return 0;
338}